diff --git a/DEPS b/DEPS
index 80fd8d66..aff6f3d 100644
--- a/DEPS
+++ b/DEPS
@@ -199,11 +199,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '854ee85736e3ea38f874ac490a9ba24d2d58158a',
+  'skia_revision': '6a718c4e909e07b3626297da342e3d2859ef8b9f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'c8d1d1cbceae8f59975b2ec7d86981ec3fabb11b',
+  'v8_revision': '8bf25fa0cda754dd0f8e0f8b7c9f8854eabfe72d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -211,7 +211,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'e91097bf3a24895f23b928ed12087dcbb1d54d7b',
+  'angle_revision': '382bf2883fa9962f5544d7b339df2569cc0a5cab',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -274,7 +274,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': '92311b48d43d56afc88aea141176455a8b5d68c0',
+  'devtools_frontend_revision': '8a3bba16ba86d5ff5f04315ea0732f5c15877394',
   # 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.
@@ -314,7 +314,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': '200941c797512895039e9f0315fc18fd9d9734ad',
+  'dawn_revision': 'a84acc4fcca80d80c379e3b02d8dc0f7b102ba9d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -553,7 +553,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'f03c0a36e0fcc5ded1f7ce51b0a0589224689d01',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '6cf2fb727b73cf7ac8ef0722b4de8afdfd1bdf9d',
       'condition': 'checkout_ios',
   },
 
@@ -893,7 +893,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '6128ceacf0011786c1c3f0875911305fc5bdd086',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '3a03505a9fd6e74d09b6ca06cc7f5b747ac71a02',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1266,7 +1266,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'f9a1b53d2809ce2f710e66b06f69449b8242ee8b',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '4dde23fea5996c50208504f79c85264f27e21aea',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1344,7 +1344,7 @@
       'packages': [
           {
               'package': 'fuchsia/third_party/aemu/linux-amd64',
-              'version': 'sVTM9Oz2ICYVmyroC8mUqO8lr6-FvUbNVn4u7F-n-nMC'
+              'version': 'LanwSa4qZkDJRxK05Ym26IRV6bksO-9CZE-3jrgCbV8C'
           },
       ],
       'condition': 'host_os == "linux" and checkout_fuchsia',
@@ -1385,7 +1385,7 @@
   },
 
   'src/third_party/re2/src':
-    Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '9e5430536b59ad8a8aff8616a6e6b0f888594fac',
+    Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + 'c33d1680c7e9ab7edea02d7465a8db13e80b558d',
 
   'src/third_party/r8': {
       'packages': [
@@ -1556,7 +1556,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/linux-amd64',
-          'version': 'CQ5a33Wu9Sm6bRTrd26RFsJVr42IoKD4Ediyp7eyuwwC',
+          'version': 'C_u9-R-I-yQyomb3Y-XIH8Ad3Ya4ZWi2MpPiFTtfHz4C',
         },
       ],
       'dep_type': 'cipd',
@@ -1566,7 +1566,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/windows-amd64',
-          'version': 'slJNuZyzBI9lNI9Uje1a2fiVtubv8LEBgUZLFdHZjssC',
+          'version': 'FzQDQOcAASIc0LaD9YBjqH2JPm0HbYCE2x0WXw2xpz0C',
         },
       ],
       'dep_type': 'cipd',
@@ -1576,7 +1576,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/mac-amd64',
-          'version': 'AXBg8ZzAzlIdv0U_KR8dr92w1szmAp-MB0Z9ZYBmFy4C',
+          'version': 'H_4GgcW8CtnxDnWd7RX17C39CAYzfHUaFR6drL3wWAcC',
         },
       ],
       'dep_type': 'cipd',
@@ -1590,7 +1590,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f257fc7a70558430d8225886810e6c724cdd0746',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@3da30cd29fe373845a62373e8f590a61811d90cc',
     'condition': 'checkout_src_internal',
   },
 
@@ -4533,7 +4533,7 @@
                 '--no_resume',
                 '--extract',
                 '--no_auth',
-                '--bucket', 'chromium-nodejs/12.14.1',
+                '--bucket', 'chromium-nodejs/14.15.4',
                 '-s', 'src/third_party/node/linux/node-linux-x64.tar.gz.sha1',
     ],
   },
@@ -4546,7 +4546,7 @@
                 '--no_resume',
                 '--extract',
                 '--no_auth',
-                '--bucket', 'chromium-nodejs/12.14.1',
+                '--bucket', 'chromium-nodejs/14.15.4',
                 '-s', 'src/third_party/node/mac/node-darwin-x64.tar.gz.sha1',
     ],
   },
@@ -4558,7 +4558,7 @@
                 'src/third_party/depot_tools/download_from_google_storage.py',
                 '--no_resume',
                 '--no_auth',
-                '--bucket', 'chromium-nodejs/12.14.1',
+                '--bucket', 'chromium-nodejs/14.15.4',
                 '-s', 'src/third_party/node/win/node.exe.sha1',
     ],
   },
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index d446f5c6..9a5077c 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -373,7 +373,6 @@
   '^chrome/browser/supervised_user/',
   '^chrome/browser/sync_file_system/',
   '^chrome/browser/translate/',
-  '^chrome/browser/ui/',
   '^chrome/browser/web_applications/',
   '^chrome/browser/win/',
   '^chrome/test/chromedriver/server/http_handler.cc',
diff --git a/apps/ui/views/app_window_frame_view.cc b/apps/ui/views/app_window_frame_view.cc
index b38c168c..1a73ae21 100644
--- a/apps/ui/views/app_window_frame_view.cc
+++ b/apps/ui/views/app_window_frame_view.cc
@@ -24,6 +24,7 @@
 #include "ui/strings/grit/ui_strings.h"  // Accessibility names
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/layout/grid_layout.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
 
@@ -35,9 +36,6 @@
 
 namespace apps {
 
-const char AppWindowFrameView::kViewClassName[] =
-    "browser/ui/views/extensions/AppWindowFrameView";
-
 AppWindowFrameView::AppWindowFrameView(views::Widget* widget,
                                        extensions::NativeAppWindow* window,
                                        bool draw_frame,
@@ -325,8 +323,6 @@
   canvas->DrawPath(path, flags);
 }
 
-const char* AppWindowFrameView::GetClassName() const { return kViewClassName; }
-
 gfx::Size AppWindowFrameView::GetMinimumSize() const {
   gfx::Size min_size = widget_->client_view()->GetMinimumSize();
   if (!draw_frame_) {
@@ -392,4 +388,7 @@
   }
 }
 
+BEGIN_METADATA(AppWindowFrameView, views::NonClientFrameView)
+END_METADATA
+
 }  // namespace apps
diff --git a/apps/ui/views/app_window_frame_view.h b/apps/ui/views/app_window_frame_view.h
index 28557cf..0d18c0bc 100644
--- a/apps/ui/views/app_window_frame_view.h
+++ b/apps/ui/views/app_window_frame_view.h
@@ -11,6 +11,7 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/views/controls/button/button.h"
+#include "ui/views/metadata/metadata_header_macros.h"
 #include "ui/views/window/non_client_view.h"
 
 namespace extensions {
@@ -32,7 +33,7 @@
 // A frameless or non-Ash, non-panel NonClientFrameView for app windows.
 class AppWindowFrameView : public views::NonClientFrameView {
  public:
-  static const char kViewClassName[];
+  METADATA_HEADER(AppWindowFrameView);
 
   // AppWindowFrameView is used to draw frames for app windows when a non
   // standard frame is needed. This occurs if there is no frame needed, or if
@@ -73,7 +74,6 @@
   // views::View implementation.
   gfx::Size CalculatePreferredSize() const override;
   void Layout() override;
-  const char* GetClassName() const override;
   void OnPaint(gfx::Canvas* canvas) override;
   gfx::Size GetMinimumSize() const override;
   gfx::Size GetMaximumSize() const override;
diff --git a/ash/accessibility/accessibility_controller_impl.cc b/ash/accessibility/accessibility_controller_impl.cc
index df90960..2ebc564 100644
--- a/ash/accessibility/accessibility_controller_impl.cc
+++ b/ash/accessibility/accessibility_controller_impl.cc
@@ -46,7 +46,6 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/user_metrics.h"
 #include "base/strings/string16.h"
-#include "base/strings/string_number_conversions.h"
 #include "chromeos/audio/cras_audio_handler.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -190,9 +189,9 @@
     prefs::kAccessibilitySwitchAccessAutoScanKeyboardSpeedMs,
     prefs::kAccessibilitySwitchAccessAutoScanSpeedMs,
     prefs::kAccessibilitySwitchAccessEnabled,
-    prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes,
-    prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes,
-    prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes,
+    prefs::kAccessibilitySwitchAccessNextKeyCodes,
+    prefs::kAccessibilitySwitchAccessPreviousKeyCodes,
+    prefs::kAccessibilitySwitchAccessSelectKeyCodes,
 };
 
 // Helper function that is used to verify the validity of kFeatures and
@@ -371,11 +370,11 @@
 std::string PrefKeyForSwitchAccessCommand(SwitchAccessCommand command) {
   switch (command) {
     case SwitchAccessCommand::kSelect:
-      return prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes;
+      return prefs::kAccessibilitySwitchAccessSelectKeyCodes;
     case SwitchAccessCommand::kNext:
-      return prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes;
+      return prefs::kAccessibilitySwitchAccessNextKeyCodes;
     case SwitchAccessCommand::kPrevious:
-      return prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes;
+      return prefs::kAccessibilitySwitchAccessPreviousKeyCodes;
     case SwitchAccessCommand::kNone:
       NOTREACHED();
       return "";
@@ -419,26 +418,6 @@
   }
 }
 
-void MigrateSwitchAccessKeyCodePref(PrefService* prefs,
-                                    const std::string& old_pref,
-                                    const std::string& new_pref) {
-  if (!prefs->HasPrefPath(old_pref))
-    return;
-
-  base::ListValue devices;
-  devices.Append(ash::kSwitchAccessInternalDevice);
-  devices.Append(ash::kSwitchAccessUsbDevice);
-  devices.Append(ash::kSwitchAccessBluetoothDevice);
-
-  const auto old_keys = prefs->Get(old_pref)->GetList();
-  base::DictionaryValue new_keys;
-  for (const auto& key : old_keys)
-    new_keys.SetPath(base::NumberToString(key.GetInt()), devices.Clone());
-
-  prefs->Set(new_pref, std::move(new_keys));
-  prefs->ClearPref(old_pref);
-}
-
 }  // namespace
 
 AccessibilityControllerImpl::Feature::Feature(
@@ -684,17 +663,17 @@
   registry->RegisterBooleanPref(
       prefs::kAccessibilitySwitchAccessEnabled, false,
       user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
-  registry->RegisterDictionaryPref(
-      prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes,
-      base::Value(base::Value::Type::DICTIONARY),
+  registry->RegisterListPref(
+      prefs::kAccessibilitySwitchAccessSelectKeyCodes,
+      base::Value(std::vector<base::Value>()),
       user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
-  registry->RegisterDictionaryPref(
-      prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes,
-      base::Value(base::Value::Type::DICTIONARY),
+  registry->RegisterListPref(
+      prefs::kAccessibilitySwitchAccessNextKeyCodes,
+      base::Value(std::vector<base::Value>()),
       user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
-  registry->RegisterDictionaryPref(
-      prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes,
-      base::Value(base::Value::Type::DICTIONARY),
+  registry->RegisterListPref(
+      prefs::kAccessibilitySwitchAccessPreviousKeyCodes,
+      base::Value(std::vector<base::Value>()),
       user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
   registry->RegisterBooleanPref(
       prefs::kAccessibilitySwitchAccessAutoScanEnabled, false,
@@ -1354,26 +1333,6 @@
 void AccessibilityControllerImpl::ObservePrefs(PrefService* prefs) {
   DCHECK(prefs);
 
-  // TODO(accessibility): Remove in m92 or later after deprecation; see
-  // https://bugs.chromium.org/p/chromium/issues/detail?id=1161305
-  static const char kAccessibilitySwitchAccessSelectKeyCodes[] =
-      "settings.a11y.switch_access.select.key_codes";
-  static const char kAccessibilitySwitchAccessNextKeyCodes[] =
-      "settings.a11y.switch_access.next.key_codes";
-  static const char kAccessibilitySwitchAccessPreviousKeyCodes[] =
-      "settings.a11y.switch_access.previous.key_codes";
-
-  // Migrate old keys to the new format.
-  MigrateSwitchAccessKeyCodePref(
-      prefs, kAccessibilitySwitchAccessSelectKeyCodes,
-      prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes);
-  MigrateSwitchAccessKeyCodePref(
-      prefs, kAccessibilitySwitchAccessNextKeyCodes,
-      prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes);
-  MigrateSwitchAccessKeyCodePref(
-      prefs, kAccessibilitySwitchAccessPreviousKeyCodes,
-      prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes);
-
   active_user_prefs_ = prefs;
 
   // Watch for pref updates from webui settings and policy.
@@ -1439,17 +1398,17 @@
           &AccessibilityControllerImpl::UpdateShortcutsEnabledFromPref,
           base::Unretained(this)));
   pref_change_registrar_->Add(
-      prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes,
+      prefs::kAccessibilitySwitchAccessSelectKeyCodes,
       base::BindRepeating(
           &AccessibilityControllerImpl::UpdateSwitchAccessKeyCodesFromPref,
           base::Unretained(this), SwitchAccessCommand::kSelect));
   pref_change_registrar_->Add(
-      prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes,
+      prefs::kAccessibilitySwitchAccessNextKeyCodes,
       base::BindRepeating(
           &AccessibilityControllerImpl::UpdateSwitchAccessKeyCodesFromPref,
           base::Unretained(this), SwitchAccessCommand::kNext));
   pref_change_registrar_->Add(
-      prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes,
+      prefs::kAccessibilitySwitchAccessPreviousKeyCodes,
       base::BindRepeating(
           &AccessibilityControllerImpl::UpdateSwitchAccessKeyCodesFromPref,
           base::Unretained(this), SwitchAccessCommand::kPrevious));
@@ -1707,26 +1666,12 @@
 
   SyncSwitchAccessPrefsToSignInProfile();
 
-  if (!accessibility_event_rewriter_)
-    return;
-
   std::string pref_key = PrefKeyForSwitchAccessCommand(command);
-  const base::DictionaryValue* key_codes_pref =
-      active_user_prefs_->GetDictionary(pref_key);
-  std::map<int, std::set<std::string>> key_codes;
-  for (const auto& v : key_codes_pref->DictItems()) {
-    int key_code;
-    if (!base::StringToInt(v.first, &key_code)) {
-      NOTREACHED();
-      return;
-    }
-
-    key_codes[key_code] = std::set<std::string>();
-
-    for (const base::Value& device_type : v.second.GetList())
-      key_codes[key_code].insert(device_type.GetString());
-
-    DCHECK(!key_codes[key_code].empty());
+  const base::ListValue* key_codes_pref = active_user_prefs_->GetList(pref_key);
+  std::set<int> key_codes;
+  for (const base::Value& v : *key_codes_pref) {
+    int key_code = v.GetInt();
+    key_codes.insert(key_code);
   }
 
   std::string uma_name = UmaNameForSwitchAccessCommand(command);
@@ -1734,11 +1679,12 @@
     SwitchAccessCommandKeyCode uma_value = UmaValueForKeyCode(0);
     base::UmaHistogramEnumeration(uma_name, uma_value);
   }
-  for (const auto& key_code : key_codes) {
-    SwitchAccessCommandKeyCode uma_value = UmaValueForKeyCode(key_code.first);
+  for (int key_code : key_codes) {
+    SwitchAccessCommandKeyCode uma_value = UmaValueForKeyCode(key_code);
     base::UmaHistogramEnumeration(uma_name, uma_value);
   }
 
+  if (accessibility_event_rewriter_)
     accessibility_event_rewriter_->SetKeyCodesForSwitchAccessCommand(key_codes,
                                                                      command);
 }
diff --git a/ash/events/accessibility_event_rewriter.cc b/ash/events/accessibility_event_rewriter.cc
index a5c06a6..24de2268 100644
--- a/ash/events/accessibility_event_rewriter.cc
+++ b/ash/events/accessibility_event_rewriter.cc
@@ -11,35 +11,28 @@
 #include "ash/public/cpp/accessibility_event_rewriter_delegate.h"
 #include "ash/shell.h"
 #include "ui/chromeos/events/event_rewriter_chromeos.h"
-#include "ui/events/devices/device_data_manager.h"
+#include "ui/events/devices/input_device.h"
 #include "ui/events/event.h"
 #include "ui/events/event_utils.h"
 #include "ui/events/types/event_type.h"
 
 namespace ash {
 
-namespace {
-
-// Returns a ui::InputDeviceType given a Switch Access string device type.
-ui::InputDeviceType GetInputDeviceType(
-    const std::string& switch_access_device_type) {
-  if (switch_access_device_type == kSwitchAccessInternalDevice)
-    return ui::INPUT_DEVICE_INTERNAL;
-  if (switch_access_device_type == kSwitchAccessUsbDevice)
-    return ui::INPUT_DEVICE_USB;
-  if (switch_access_device_type == kSwitchAccessBluetoothDevice)
-    return ui::INPUT_DEVICE_BLUETOOTH;
-
-  NOTREACHED();
-  return ui::INPUT_DEVICE_UNKNOWN;
-}
-}  // namespace
-
 AccessibilityEventRewriter::AccessibilityEventRewriter(
     ui::EventRewriterChromeOS* event_rewriter_chromeos,
     AccessibilityEventRewriterDelegate* delegate)
     : delegate_(delegate), event_rewriter_chromeos_(event_rewriter_chromeos) {
   Shell::Get()->accessibility_controller()->SetAccessibilityEventRewriter(this);
+
+  // By default, observe all input device types.
+  keyboard_input_device_types_.insert(ui::INPUT_DEVICE_INTERNAL);
+  keyboard_input_device_types_.insert(ui::INPUT_DEVICE_USB);
+  keyboard_input_device_types_.insert(ui::INPUT_DEVICE_BLUETOOTH);
+  keyboard_input_device_types_.insert(ui::INPUT_DEVICE_UNKNOWN);
+
+  UpdateKeyboardDeviceIds();
+
+  observer_.Add(ui::DeviceDataManager::GetInstance());
 }
 
 AccessibilityEventRewriter::~AccessibilityEventRewriter() {
@@ -73,36 +66,58 @@
   }
 }
 
-void AccessibilityEventRewriter::SetKeyCodesForSwitchAccessCommand(
-    const std::map<int, std::set<std::string>>& key_codes,
+bool AccessibilityEventRewriter::SetKeyCodesForSwitchAccessCommand(
+    std::set<int> new_key_codes,
     SwitchAccessCommand command) {
-  // Remove all keys for the command.
-  for (auto it = key_code_to_switch_access_command_.begin();
-       it != key_code_to_switch_access_command_.end();) {
-    if (it->second == command) {
-      switch_access_key_codes_to_capture_.erase(it->first);
-      it = key_code_to_switch_access_command_.erase(it);
-    } else {
-      it++;
+  bool has_changed = false;
+  std::set<int> to_clear;
+
+  // Clear old values that conflict with the new assignment.
+  // TODO(anastasi): convert to use iterators directly and remove has_changed as
+  // an extra step.
+  for (const auto& val : key_code_to_switch_access_command_) {
+    int old_key_code = val.first;
+    SwitchAccessCommand old_command = val.second;
+
+    if (new_key_codes.count(old_key_code) > 0) {
+      if (old_command != command) {
+        has_changed = true;
+        // Modifying the map while iterating through it causes reference
+        // failures.
+        to_clear.insert(old_key_code);
+      } else {
+        new_key_codes.erase(old_key_code);
+      }
+      continue;
+    }
+
+    // This value was previously mapped to the command, but is no longer.
+    if (old_command == command) {
+      has_changed = true;
+      to_clear.insert(old_key_code);
+      switch_access_key_codes_to_capture_.erase(old_key_code);
     }
   }
-
-  for (const auto& key_code : key_codes) {
-    // Remove any preexisting key.
-    switch_access_key_codes_to_capture_.erase(key_code.first);
-    key_code_to_switch_access_command_.erase(key_code.first);
-
-    // Map device types from Switch Access's internal representation.
-    std::set<ui::InputDeviceType> device_types;
-    for (const std::string& switch_access_device : key_code.second)
-      device_types.insert(GetInputDeviceType(switch_access_device));
-
-    switch_access_key_codes_to_capture_.insert({key_code.first, device_types});
-    key_code_to_switch_access_command_.insert({key_code.first, command});
+  for (int key_code : to_clear) {
+    key_code_to_switch_access_command_.erase(key_code);
   }
 
-  // Conflict resolution occurs up the stack (e.g. in the settings pages for
-  // Switch Access).
+  if (new_key_codes.size() == 0)
+    return has_changed;
+
+  // Add any new key codes to the map.
+  for (int key_code : new_key_codes) {
+    switch_access_key_codes_to_capture_.insert(key_code);
+    key_code_to_switch_access_command_[key_code] = command;
+  }
+
+  return true;
+}
+
+void AccessibilityEventRewriter::SetKeyboardInputDeviceTypes(
+    const std::set<ui::InputDeviceType>& keyboard_input_device_types) {
+  keyboard_input_device_types_ = keyboard_input_device_types;
+  UpdateKeyboardDeviceIds();
 }
 
 bool AccessibilityEventRewriter::RewriteEventForChromeVox(
@@ -163,29 +178,10 @@
     return false;
 
   const ui::KeyEvent* key_event = event.AsKeyEvent();
-  const auto& key =
-      switch_access_key_codes_to_capture_.find(key_event->key_code());
-  if (key == switch_access_key_codes_to_capture_.end())
-    return false;
+  bool capture =
+      switch_access_key_codes_to_capture_.count(key_event->key_code()) > 0;
 
-  int source_device_id = key_event->source_device_id();
-  ui::InputDeviceType keyboard_type = ui::INPUT_DEVICE_UNKNOWN;
-  for (const auto& keyboard :
-       ui::DeviceDataManager::GetInstance()->GetKeyboardDevices()) {
-    if (source_device_id == keyboard.id) {
-      keyboard_type = keyboard.type;
-      break;
-    }
-  }
-
-  // An unknown |source_device_id| needs to pass this check as it's set that way
-  // in tests.
-  if (source_device_id != ui::ED_UNKNOWN_DEVICE &&
-      key->second.count(keyboard_type) == 0) {
-    return false;
-  }
-
-  if (key_event->type() == ui::ET_KEY_PRESSED) {
+  if (capture && key_event->type() == ui::ET_KEY_PRESSED) {
     AccessibilityControllerImpl* accessibility_controller =
         Shell::Get()->accessibility_controller();
 
@@ -203,7 +199,7 @@
       delegate_->SendSwitchAccessCommand(command);
     }
   }
-  return true;
+  return capture;
 }
 
 bool AccessibilityEventRewriter::RewriteEventForMagnifier(
@@ -270,6 +266,15 @@
   delegate_->SendMagnifierCommand(MagnifierCommand::kMoveStop);
 }
 
+void AccessibilityEventRewriter::UpdateKeyboardDeviceIds() {
+  keyboard_device_ids_.clear();
+  for (auto& keyboard :
+       ui::DeviceDataManager::GetInstance()->GetKeyboardDevices()) {
+    if (keyboard_input_device_types_.count(keyboard.type))
+      keyboard_device_ids_.insert(keyboard.id);
+  }
+}
+
 void AccessibilityEventRewriter::MaybeSendMouseEvent(const ui::Event& event) {
   // Mouse moves are the only pertinent event for accessibility component
   // extensions.
@@ -283,6 +288,11 @@
 ui::EventDispatchDetails AccessibilityEventRewriter::RewriteEvent(
     const ui::Event& event,
     const Continuation continuation) {
+  if (event.IsKeyEvent() && event.source_device_id() != ui::ED_UNKNOWN_DEVICE &&
+      keyboard_device_ids_.count(event.source_device_id()) == 0) {
+    return SendEvent(continuation, &event);
+  }
+
   bool captured = false;
   if (!delegate_)
     return SendEvent(continuation, &event);
@@ -310,4 +320,10 @@
                   : SendEvent(continuation, &event);
 }
 
+void AccessibilityEventRewriter::OnInputDeviceConfigurationChanged(
+    uint8_t input_device_types) {
+  if (input_device_types & ui::InputDeviceEventObserver::kKeyboard)
+    UpdateKeyboardDeviceIds();
+}
+
 }  // namespace ash
diff --git a/ash/events/accessibility_event_rewriter.h b/ash/events/accessibility_event_rewriter.h
index a89e8f3..686342a 100644
--- a/ash/events/accessibility_event_rewriter.h
+++ b/ash/events/accessibility_event_rewriter.h
@@ -11,11 +11,13 @@
 
 #include "ash/ash_export.h"
 #include "base/scoped_observer.h"
-#include "ui/events/devices/input_device.h"
+#include "ui/events/devices/device_data_manager.h"
+#include "ui/events/devices/input_device_event_observer.h"
 #include "ui/events/event_rewriter.h"
 
 namespace ui {
 class EventRewriterChromeOS;
+enum InputDeviceType;
 }
 
 namespace ash {
@@ -27,7 +29,9 @@
 // AccessibilityEventRewriter sends key events to Accessibility extensions (such
 // as ChromeVox and Switch Access) via the delegate when the corresponding
 // extension is enabled. Continues dispatch of unhandled key events.
-class ASH_EXPORT AccessibilityEventRewriter : public ui::EventRewriter {
+class ASH_EXPORT AccessibilityEventRewriter
+    : public ui::EventRewriter,
+      public ui::InputDeviceEventObserver {
  public:
   AccessibilityEventRewriter(ui::EventRewriterChromeOS* event_rewriter_chromeos,
                              AccessibilityEventRewriterDelegate* delegate);
@@ -40,10 +44,14 @@
   // NOTE: These events may be delivered out-of-order from non-ChromeVox events.
   void OnUnhandledSpokenFeedbackEvent(std::unique_ptr<ui::Event> event) const;
 
-  // Sets what |key_codes| are captured for a given Switch Access command.
-  void SetKeyCodesForSwitchAccessCommand(
-      const std::map<int, std::set<std::string>>& key_codes,
-      SwitchAccessCommand command);
+  // Sets what |key_codes| are captured for a given Switch Access command;
+  // returns true if any mapping changed.
+  bool SetKeyCodesForSwitchAccessCommand(std::set<int> key_codes,
+                                         SwitchAccessCommand command);
+
+  // Set the types of keyboard input types processed by this rewriter.
+  void SetKeyboardInputDeviceTypes(
+      const std::set<ui::InputDeviceType>& keyboard_input_device_types);
 
   void set_chromevox_capture_all_keys(bool value) {
     chromevox_capture_all_keys_ = value;
@@ -56,8 +64,7 @@
   }
 
   // For testing use only.
-  std::map<int, std::set<ui::InputDeviceType>>
-  switch_access_key_codes_to_capture_for_test() {
+  std::set<int> switch_access_key_codes_to_capture_for_test() {
     return switch_access_key_codes_to_capture_;
   }
   std::map<int, SwitchAccessCommand>
@@ -77,6 +84,10 @@
   void OnMagnifierKeyPressed(const ui::KeyEvent* event);
   void OnMagnifierKeyReleased(const ui::KeyEvent* event);
 
+  // Updates the list of allowed keyboard device ids based on the current set of
+  // keyboard input types.
+  void UpdateKeyboardDeviceIds();
+
   // Maybe sends a mouse event to be dispatched to accessibility component
   // extensions.
   void MaybeSendMouseEvent(const ui::Event& event);
@@ -86,6 +97,9 @@
       const ui::Event& event,
       const Continuation continuation) override;
 
+  // ui::InputDeviceObserver:
+  void OnInputDeviceConfigurationChanged(uint8_t input_device_types) override;
+
   // Continuation saved for OnUnhandledSpokenFeedbackEvent().
   Continuation chromevox_continuation_;
 
@@ -99,9 +113,8 @@
   // Whether to capture all keys for ChromeVox.
   bool chromevox_capture_all_keys_ = false;
 
-  // Maps a key to a set of devices which should be captured for Switch Access.
-  std::map<int, std::set<ui::InputDeviceType>>
-      switch_access_key_codes_to_capture_;
+  // Set of keys to capture for Switch Access.
+  std::set<int> switch_access_key_codes_to_capture_;
 
   // Maps a captured key from above to a Switch Access command.
   std::map<int, SwitchAccessCommand> key_code_to_switch_access_command_;
@@ -110,6 +123,17 @@
   // taylored behavior.
   ui::EventRewriterChromeOS* const event_rewriter_chromeos_;
 
+  // A set of keyboard device ids who's key events we want to process.
+  std::set<int> keyboard_device_ids_;
+
+  // A set of input device types used to filter the list of keyboard devices
+  // above.
+  std::set<ui::InputDeviceType> keyboard_input_device_types_;
+
+  // Used to refresh state when keyboard devices change.
+  ScopedObserver<ui::DeviceDataManager, ui::InputDeviceEventObserver> observer_{
+      this};
+
   // Suspends key handling for Switch Access during key assignment in web ui.
   bool suspend_switch_access_key_handling_ = false;
 };
diff --git a/ash/events/accessibility_event_rewriter_unittest.cc b/ash/events/accessibility_event_rewriter_unittest.cc
index 73be228..9f6183e 100644
--- a/ash/events/accessibility_event_rewriter_unittest.cc
+++ b/ash/events/accessibility_event_rewriter_unittest.cc
@@ -9,7 +9,6 @@
 
 #include "ash/accessibility/accessibility_controller_impl.h"
 #include "ash/public/cpp/accessibility_event_rewriter_delegate.h"
-#include "ash/public/cpp/ash_constants.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "base/macros.h"
@@ -64,8 +63,6 @@
   void SendMagnifierCommand(MagnifierCommand command) override {}
 };
 
-}  // namespace
-
 class ChromeVoxAccessibilityEventRewriterTest
     : public ash::AshTestBase,
       public ui::EventRewriterChromeOS::Delegate {
@@ -129,6 +126,16 @@
     modifier_remapping_[pref_name] = static_cast<int>(value);
   }
 
+  std::set<int> GetSwitchAccessKeyCodesToCapture() {
+    return accessibility_event_rewriter_
+        ->switch_access_key_codes_to_capture_for_test();
+  }
+
+  std::map<int, SwitchAccessCommand> GetSwitchAccessCommandForKeyCodeMap() {
+    return accessibility_event_rewriter_
+        ->key_code_to_switch_access_command_map_for_test();
+  }
+
  protected:
   // A test accessibility event delegate; simulates ChromeVox and Switch Access.
   ChromeVoxTestDelegate delegate_;
@@ -400,8 +407,6 @@
   SwitchAccessCommand last_command() { return commands_.back(); }
   int command_count() { return commands_.size(); }
 
-  void ClearCommands() { commands_.clear(); }
-
   // AccessibilityEventRewriterDelegate:
   void SendSwitchAccessCommand(SwitchAccessCommand command) override {
     commands_.push_back(command);
@@ -445,14 +450,6 @@
     controller_->SetAccessibilityEventRewriter(
         accessibility_event_rewriter_.get());
     controller_->switch_access().SetEnabled(true);
-
-    std::vector<ui::InputDevice> keyboards;
-    ui::DeviceDataManagerTestApi device_data_test_api;
-    keyboards.push_back(ui::InputDevice(1, ui::INPUT_DEVICE_INTERNAL, ""));
-    keyboards.push_back(ui::InputDevice(2, ui::INPUT_DEVICE_USB, ""));
-    keyboards.push_back(ui::InputDevice(3, ui::INPUT_DEVICE_BLUETOOTH, ""));
-    keyboards.push_back(ui::InputDevice(4, ui::INPUT_DEVICE_UNKNOWN, ""));
-    device_data_test_api.SetKeyboardDevices(keyboards);
   }
 
   void TearDown() override {
@@ -463,20 +460,19 @@
     AshTestBase::TearDown();
   }
 
-  void SetKeyCodesForSwitchAccessCommand(
-      std::map<int, std::set<std::string>> key_codes,
-      SwitchAccessCommand command) {
+  void SetKeyCodesForSwitchAccessCommand(std::set<int> key_codes,
+                                         SwitchAccessCommand command) {
     AccessibilityEventRewriter* rewriter =
         controller_->GetAccessibilityEventRewriterForTest();
     rewriter->SetKeyCodesForSwitchAccessCommand(key_codes, command);
   }
 
-  const std::map<int, std::set<ui::InputDeviceType>> GetKeyCodesToCapture() {
+  const std::set<int> GetKeyCodesToCapture() {
     AccessibilityEventRewriter* rewriter =
         controller_->GetAccessibilityEventRewriterForTest();
     if (rewriter)
       return rewriter->switch_access_key_codes_to_capture_for_test();
-    return std::map<int, std::set<ui::InputDeviceType>>();
+    return std::set<int>();
   }
 
   const std::map<int, SwitchAccessCommand> GetCommandForKeyCodeMap() {
@@ -498,79 +494,58 @@
 
 TEST_F(SwitchAccessAccessibilityEventRewriterTest, CaptureSpecifiedKeys) {
   // Set keys for Switch Access to capture.
-  SetKeyCodesForSwitchAccessCommand(
-      {{ui::VKEY_1, {kSwitchAccessInternalDevice}},
-       {ui::VKEY_2, {kSwitchAccessUsbDevice}}},
-      SwitchAccessCommand::kSelect);
+  SetKeyCodesForSwitchAccessCommand({ui::VKEY_1, ui::VKEY_2},
+                                    SwitchAccessCommand::kSelect);
 
   EXPECT_FALSE(event_capturer_.last_key_event());
 
-  // Press 1 from the internal keyboard.
-  generator_->PressKey(ui::VKEY_1, ui::EF_NONE, 1 /* keyboard id */);
-  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE, 1 /* keyboard id */);
+  generator_->PressKey(ui::VKEY_1, ui::EF_NONE);
+  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE);
 
   // The event was captured by AccessibilityEventRewriter.
   EXPECT_FALSE(event_capturer_.last_key_event());
   EXPECT_EQ(SwitchAccessCommand::kSelect, delegate_->last_command());
 
-  delegate_->ClearCommands();
-
-  // Press 1 from the bluetooth keyboard.
-  generator_->PressKey(ui::VKEY_1, ui::EF_NONE, 3 /* keyboard id */);
-  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE, 3 /* keyboard id */);
-
-  // The event was not captured by AccessibilityEventRewriter.
-  EXPECT_TRUE(event_capturer_.last_key_event());
-  EXPECT_EQ(0, delegate_->command_count());
-
   // Press the "2" key.
-  generator_->PressKey(ui::VKEY_2, ui::EF_NONE, 2 /* keyboard id */);
-  generator_->ReleaseKey(ui::VKEY_2, ui::EF_NONE, 2 /* keyboard id */);
+  generator_->PressKey(ui::VKEY_2, ui::EF_NONE);
+  generator_->ReleaseKey(ui::VKEY_2, ui::EF_NONE);
+
+  // We received a new event.
+
+  // The event was captured by AccessibilityEventRewriter.
+  EXPECT_FALSE(event_capturer_.last_key_event());
+
+  // Press the "3" key.
+  generator_->PressKey(ui::VKEY_3, ui::EF_NONE);
+  generator_->ReleaseKey(ui::VKEY_3, ui::EF_NONE);
 
   // The event was captured by AccessibilityEventRewriter.
   EXPECT_TRUE(event_capturer_.last_key_event());
-  EXPECT_EQ(SwitchAccessCommand::kSelect, delegate_->last_command());
-
-  delegate_->ClearCommands();
-
-  // Press the "3" key.
-  generator_->PressKey(ui::VKEY_3, ui::EF_NONE, 1 /* keyboard id */);
-  generator_->ReleaseKey(ui::VKEY_3, ui::EF_NONE, 1 /* keyboard id */);
-
-  // The event was not captured by AccessibilityEventRewriter.
-  EXPECT_TRUE(event_capturer_.last_key_event());
-  EXPECT_EQ(0, delegate_->command_count());
 }
 
 TEST_F(SwitchAccessAccessibilityEventRewriterTest,
        KeysNoLongerCaptureAfterUpdate) {
   // Set Switch Access to capture the keys {1, 2, 3}.
-  SetKeyCodesForSwitchAccessCommand(
-      {{ui::VKEY_1, {kSwitchAccessInternalDevice}},
-       {ui::VKEY_2, {kSwitchAccessInternalDevice}},
-       {ui::VKEY_3, {kSwitchAccessInternalDevice}}},
-      SwitchAccessCommand::kSelect);
+  SetKeyCodesForSwitchAccessCommand({ui::VKEY_1, ui::VKEY_2, ui::VKEY_3},
+                                    SwitchAccessCommand::kSelect);
 
   EXPECT_FALSE(event_capturer_.last_key_event());
 
   // Press the "1" key.
-  generator_->PressKey(ui::VKEY_1, ui::EF_NONE, 1 /* keyboard id */);
-  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE, 1 /* keyboard id */);
+  generator_->PressKey(ui::VKEY_1, ui::EF_NONE);
+  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE);
 
   // The event was captured by AccessibilityEventRewriter.
   EXPECT_FALSE(event_capturer_.last_key_event());
   EXPECT_EQ(SwitchAccessCommand::kSelect, delegate_->last_command());
 
   // Update the Switch Access keys to capture {2, 3, 4}.
-  SetKeyCodesForSwitchAccessCommand(
-      {{ui::VKEY_2, {kSwitchAccessInternalDevice}},
-       {ui::VKEY_3, {kSwitchAccessInternalDevice}},
-       {ui::VKEY_4, {kSwitchAccessInternalDevice}}},
-      SwitchAccessCommand::kSelect);
+  SetKeyCodesForSwitchAccessCommand({ui::VKEY_2, ui::VKEY_3, ui::VKEY_4},
+                                    SwitchAccessCommand::kSelect);
 
   // Press the "1" key.
-  generator_->PressKey(ui::VKEY_1, ui::EF_NONE, 1 /* keyboard id */);
-  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE, 1 /* keyboard id */);
+  generator_->PressKey(ui::VKEY_1, ui::EF_NONE);
+  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE);
 
   // We received a new event.
 
@@ -579,13 +554,10 @@
   EXPECT_FALSE(event_capturer_.last_key_event()->handled());
 
   // Press the "4" key.
-  event_capturer_.Reset();
-  generator_->PressKey(ui::VKEY_4, ui::EF_NONE, 1 /* keyboard id */);
-  generator_->ReleaseKey(ui::VKEY_4, ui::EF_NONE, 1 /* keyboard id */);
+  generator_->PressKey(ui::VKEY_4, ui::EF_NONE);
+  generator_->ReleaseKey(ui::VKEY_4, ui::EF_NONE);
 
   // The event was captured by AccessibilityEventRewriter.
-  EXPECT_FALSE(event_capturer_.last_key_event());
-  EXPECT_EQ(SwitchAccessCommand::kSelect, delegate_->last_command());
 }
 
 TEST_F(SwitchAccessAccessibilityEventRewriterTest,
@@ -599,15 +571,14 @@
   EXPECT_EQ(0u, GetCommandForKeyCodeMap().size());
 
   // Set key codes for Select command.
-  std::map<int, std::set<std::string>> new_key_codes;
-  new_key_codes[48 /* '0' */] = {kSwitchAccessInternalDevice};
-  new_key_codes[83 /* 's' */] = {kSwitchAccessInternalDevice};
+  std::set<int> new_key_codes;
+  new_key_codes.insert(48 /* '0' */);
+  new_key_codes.insert(83 /* 's' */);
   rewriter->SetKeyCodesForSwitchAccessCommand(new_key_codes,
                                               SwitchAccessCommand::kSelect);
 
   // Check that values are added to both data structures.
-  std::map<int, std::set<ui::InputDeviceType>> kc_to_capture =
-      GetKeyCodesToCapture();
+  std::set<int> kc_to_capture = GetKeyCodesToCapture();
   EXPECT_EQ(2u, kc_to_capture.size());
   EXPECT_EQ(1u, kc_to_capture.count(48));
   EXPECT_EQ(1u, kc_to_capture.count(83));
@@ -619,8 +590,8 @@
 
   // Set key codes for the Next command.
   new_key_codes.clear();
-  new_key_codes[49 /* '1' */] = {kSwitchAccessInternalDevice};
-  new_key_codes[78 /* 'n' */] = {kSwitchAccessInternalDevice};
+  new_key_codes.insert(49 /* '1' */);
+  new_key_codes.insert(78 /* 'n' */);
   rewriter->SetKeyCodesForSwitchAccessCommand(new_key_codes,
                                               SwitchAccessCommand::kNext);
 
@@ -637,8 +608,8 @@
 
   // Set key codes for the Previous command. Re-use a key code from above.
   new_key_codes.clear();
-  new_key_codes[49 /* '1' */] = {kSwitchAccessInternalDevice};
-  new_key_codes[80 /* 'p' */] = {kSwitchAccessInternalDevice};
+  new_key_codes.insert(49 /* '1' */);
+  new_key_codes.insert(80 /* 'p' */);
   rewriter->SetKeyCodesForSwitchAccessCommand(new_key_codes,
                                               SwitchAccessCommand::kPrevious);
 
@@ -656,8 +627,8 @@
 
   // Set a new key code for the Select command.
   new_key_codes.clear();
-  new_key_codes[51 /* '3' */] = {kSwitchAccessInternalDevice};
-  new_key_codes[83 /* 's' */] = {kSwitchAccessInternalDevice};
+  new_key_codes.insert(51 /* '3' */);
+  new_key_codes.insert(83 /* 's' */);
   rewriter->SetKeyCodesForSwitchAccessCommand(new_key_codes,
                                               SwitchAccessCommand::kSelect);
 
@@ -675,6 +646,86 @@
   EXPECT_EQ(command_map.end(), command_map.find(48));
 }
 
+TEST_F(SwitchAccessAccessibilityEventRewriterTest, SetKeyboardInputTypes) {
+  AccessibilityEventRewriter* rewriter =
+      controller_->GetAccessibilityEventRewriterForTest();
+  EXPECT_NE(nullptr, rewriter);
+
+  // Set Switch Access to capture these keys as the select command.
+  SetKeyCodesForSwitchAccessCommand(
+      {ui::VKEY_1, ui::VKEY_2, ui::VKEY_3, ui::VKEY_4},
+      SwitchAccessCommand::kSelect);
+
+  std::vector<ui::InputDevice> keyboards;
+  ui::DeviceDataManagerTestApi device_data_test_api;
+  keyboards.emplace_back(ui::InputDevice(1, ui::INPUT_DEVICE_INTERNAL, ""));
+  keyboards.emplace_back(ui::InputDevice(2, ui::INPUT_DEVICE_USB, ""));
+  keyboards.emplace_back(ui::InputDevice(3, ui::INPUT_DEVICE_BLUETOOTH, ""));
+  keyboards.emplace_back(ui::InputDevice(4, ui::INPUT_DEVICE_UNKNOWN, ""));
+  device_data_test_api.SetKeyboardDevices(keyboards);
+
+  // Press the "1" key with no source device id.
+  generator_->PressKey(ui::VKEY_1, ui::EF_NONE);
+  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE);
+
+  // The event was captured by AccessibilityEventRewriter.
+  EXPECT_FALSE(event_capturer_.last_key_event());
+  EXPECT_EQ(SwitchAccessCommand::kSelect, delegate_->last_command());
+
+  // Press the "1" key from the internal keyboard which is captured by
+  // AccessibilityEventRewriter.
+  generator_->PressKey(ui::VKEY_1, ui::EF_NONE, 1);
+  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE, 1);
+  EXPECT_FALSE(event_capturer_.last_key_event());
+
+  // Press the "2" key from the usb keyboard which is captured by
+  // AccessibilityEventRewriter.
+  generator_->PressKey(ui::VKEY_2, ui::EF_NONE, 2);
+  generator_->ReleaseKey(ui::VKEY_2, ui::EF_NONE, 2);
+  EXPECT_FALSE(event_capturer_.last_key_event());
+
+  // Press the "3" key from the bluetooth keyboard which is captured by
+  // AccessibilityEventRewriter.
+  generator_->PressKey(ui::VKEY_3, ui::EF_NONE, 3);
+  generator_->ReleaseKey(ui::VKEY_3, ui::EF_NONE, 3);
+  EXPECT_FALSE(event_capturer_.last_key_event());
+
+  // Press the "4" key from the unknown keyboard which is captured by
+  // AccessibilityEventRewriter.
+  generator_->PressKey(ui::VKEY_4, ui::EF_NONE, 4);
+  generator_->ReleaseKey(ui::VKEY_4, ui::EF_NONE, 2);
+  EXPECT_FALSE(event_capturer_.last_key_event());
+
+  // Now, exclude some device types.
+  rewriter->SetKeyboardInputDeviceTypes(
+      {ui::INPUT_DEVICE_USB, ui::INPUT_DEVICE_BLUETOOTH});
+
+  // Press the "1" key from the internal keyboard which is not captured by
+  // AccessibilityEventRewriter.
+  generator_->PressKey(ui::VKEY_1, ui::EF_NONE, 1);
+  generator_->ReleaseKey(ui::VKEY_1, ui::EF_NONE, 1);
+  EXPECT_TRUE(event_capturer_.last_key_event());
+  event_capturer_.Reset();
+
+  // Press the "2" key from the usb keyboard which is captured by
+  // AccessibilityEventRewriter.
+  generator_->PressKey(ui::VKEY_2, ui::EF_NONE, 2);
+  generator_->ReleaseKey(ui::VKEY_2, ui::EF_NONE, 2);
+  EXPECT_FALSE(event_capturer_.last_key_event());
+
+  // Press the "3" key from the bluetooth keyboard which is captured by
+  // AccessibilityEventRewriter.
+  generator_->PressKey(ui::VKEY_3, ui::EF_NONE, 3);
+  generator_->ReleaseKey(ui::VKEY_3, ui::EF_NONE, 3);
+  EXPECT_FALSE(event_capturer_.last_key_event());
+
+  // Press the "4" key from the unknown keyboard which is not captured by
+  // AccessibilityEventRewriter.
+  generator_->PressKey(ui::VKEY_4, ui::EF_NONE, 4);
+  generator_->ReleaseKey(ui::VKEY_4, ui::EF_NONE, 2);
+  EXPECT_TRUE(event_capturer_.last_key_event());
+}
+
 class MagnifierTestDelegate : public AccessibilityEventRewriterDelegate {
  public:
   MagnifierTestDelegate() = default;
@@ -777,4 +828,5 @@
   EXPECT_TRUE(event_capturer_.last_key_event());
 }
 
+}  // namespace
 }  // namespace ash
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index 13918d89..8cd0d46 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -59,7 +59,6 @@
     "app_types.h",
     "arc_app_id_provider.cc",
     "arc_app_id_provider.h",
-    "ash_constants.cc",
     "ash_constants.h",
     "ash_features.cc",
     "ash_features.h",
diff --git a/ash/public/cpp/ash_constants.cc b/ash/public/cpp/ash_constants.cc
deleted file mode 100644
index c1e39e42..0000000
--- a/ash/public/cpp/ash_constants.cc
+++ /dev/null
@@ -1,14 +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 "ash/public/cpp/ash_constants.h"
-
-namespace ash {
-
-const char kSwitchAccessInternalDevice[] = "internal";
-const char kSwitchAccessUsbDevice[] = "usb";
-const char kSwitchAccessBluetoothDevice[] = "bluetooth";
-const char kSwitchAccessUnknownDevice[] = "unknown";
-
-}  // namespace ash
diff --git a/ash/public/cpp/ash_constants.h b/ash/public/cpp/ash_constants.h
index fc70c06..4bfcfb5 100644
--- a/ash/public/cpp/ash_constants.h
+++ b/ash/public/cpp/ash_constants.h
@@ -6,7 +6,6 @@
 #define ASH_PUBLIC_CPP_ASH_CONSTANTS_H_
 
 #include "ash/public/cpp/accessibility_controller_enums.h"
-#include "ash/public/cpp/ash_public_export.h"
 #include "base/time/time.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/color_palette.h"
@@ -28,13 +27,6 @@
 // The option in the Switch Access settings for no switch assigned.
 constexpr int kSwitchAccessAssignmentNone = 0;
 
-// These device types are a subset of ui::InputDeviceType. These strings are
-// also used in Switch Access webui.
-ASH_PUBLIC_EXPORT extern const char kSwitchAccessInternalDevice[];
-ASH_PUBLIC_EXPORT extern const char kSwitchAccessUsbDevice[];
-ASH_PUBLIC_EXPORT extern const char kSwitchAccessBluetoothDevice[];
-ASH_PUBLIC_EXPORT extern const char kSwitchAccessUnknownDevice[];
-
 // The default delay before Switch Access automatically moves to the next
 // element on the page that is interesting, based on the Switch Access
 // predicates.
diff --git a/ash/public/cpp/ash_pref_names.cc b/ash/public/cpp/ash_pref_names.cc
index 0a0d238..e4114380 100644
--- a/ash/public/cpp/ash_pref_names.cc
+++ b/ash/public/cpp/ash_pref_names.cc
@@ -105,18 +105,15 @@
 // A boolean pref which determines whether Switch Access is enabled.
 const char kAccessibilitySwitchAccessEnabled[] =
     "settings.a11y.switch_access.enabled";
-// A dictionary pref keyed on a key code mapped to a list value of device types
-// for the "select" action.
-const char kAccessibilitySwitchAccessSelectDeviceKeyCodes[] =
-    "settings.a11y.switch_access.select.device_key_codes";
-// A dictionary pref keyed on a key code mapped to a list value of device types
-// for the "next" action.
-const char kAccessibilitySwitchAccessNextDeviceKeyCodes[] =
-    "settings.a11y.switch_access.next.device_key_codes";
-// A dictionary pref keyed on a key code mapped to a list value of device types
-// for the "previous" action.
-const char kAccessibilitySwitchAccessPreviousDeviceKeyCodes[] =
-    "settings.a11y.switch_access.previous.device_key_codes";
+// A pref that stores the key code for the "select" action.
+const char kAccessibilitySwitchAccessSelectKeyCodes[] =
+    "settings.a11y.switch_access.select.key_codes";
+// A pref that stores the key code for the "next" action.
+const char kAccessibilitySwitchAccessNextKeyCodes[] =
+    "settings.a11y.switch_access.next.key_codes";
+// A pref that stores the key code for the "previous" action.
+const char kAccessibilitySwitchAccessPreviousKeyCodes[] =
+    "settings.a11y.switch_access.previous.key_codes";
 // A boolean pref which determines whether auto-scanning is enabled within
 // Switch Access.
 const char kAccessibilitySwitchAccessAutoScanEnabled[] =
diff --git a/ash/public/cpp/ash_pref_names.h b/ash/public/cpp/ash_pref_names.h
index 5fa7e0c..67f129e 100644
--- a/ash/public/cpp/ash_pref_names.h
+++ b/ash/public/cpp/ash_pref_names.h
@@ -41,12 +41,10 @@
 ASH_PUBLIC_EXPORT extern const char kAccessibilityFocusHighlightEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilitySelectToSpeakEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilitySwitchAccessEnabled[];
+ASH_PUBLIC_EXPORT extern const char kAccessibilitySwitchAccessSelectKeyCodes[];
+ASH_PUBLIC_EXPORT extern const char kAccessibilitySwitchAccessNextKeyCodes[];
 ASH_PUBLIC_EXPORT extern const char
-    kAccessibilitySwitchAccessSelectDeviceKeyCodes[];
-ASH_PUBLIC_EXPORT extern const char
-    kAccessibilitySwitchAccessNextDeviceKeyCodes[];
-ASH_PUBLIC_EXPORT extern const char
-    kAccessibilitySwitchAccessPreviousDeviceKeyCodes[];
+    kAccessibilitySwitchAccessPreviousKeyCodes[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilitySwitchAccessAutoScanEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilitySwitchAccessAutoScanSpeedMs[];
 ASH_PUBLIC_EXPORT extern const char
diff --git a/ash/system/dark_mode/dark_mode_detailed_view.cc b/ash/system/dark_mode/dark_mode_detailed_view.cc
index d6b95297..f00826a 100644
--- a/ash/system/dark_mode/dark_mode_detailed_view.cc
+++ b/ash/system/dark_mode/dark_mode_detailed_view.cc
@@ -16,6 +16,7 @@
 #include "ui/views/controls/button/radio_button.h"
 #include "ui/views/controls/button/toggle_button.h"
 #include "ui/views/controls/scroll_view.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
 
 namespace ash {
 
@@ -115,10 +116,6 @@
   Layout();
 }
 
-const char* DarkModeDetailedView::GetClassName() const {
-  return "DarkModeDetailedView";
-}
-
 void DarkModeDetailedView::OnThemeChanged() {
   TrayDetailedView::OnThemeChanged();
   TrayPopupUtils::SetLabelFontList(themed_label_,
@@ -138,4 +135,7 @@
             : neutral_mode_button_->SetChecked(true);
 }
 
+BEGIN_METADATA(DarkModeDetailedView, TrayDetailedView)
+END_METADATA
+
 }  // namespace ash
diff --git a/ash/system/dark_mode/dark_mode_detailed_view.h b/ash/system/dark_mode/dark_mode_detailed_view.h
index e275154..8086969 100644
--- a/ash/system/dark_mode/dark_mode_detailed_view.h
+++ b/ash/system/dark_mode/dark_mode_detailed_view.h
@@ -6,6 +6,7 @@
 #define ASH_SYSTEM_DARK_MODE_DARK_MODE_DETAILED_VIEW_H_
 
 #include "ash/system/tray/tray_detailed_view.h"
+#include "ui/views/metadata/metadata_header_macros.h"
 
 namespace views {
 class Label;
@@ -20,13 +21,13 @@
 // feature pod label button.
 class DarkModeDetailedView : public TrayDetailedView {
  public:
+  METADATA_HEADER(DarkModeDetailedView);
+
   explicit DarkModeDetailedView(DetailedViewDelegate* delegate);
   DarkModeDetailedView(const DarkModeDetailedView& other) = delete;
   DarkModeDetailedView& operator=(const DarkModeDetailedView& other) = delete;
   ~DarkModeDetailedView() override;
 
-  // views::View:
-  const char* GetClassName() const override;
   void OnThemeChanged() override;
 
   // Updates the status of |toggle_| on |dark_mode_enabled|.
diff --git a/ash/system/holding_space/holding_space_item_chips_container.cc b/ash/system/holding_space/holding_space_item_chips_container.cc
index 7ca8638..d0c0a15 100644
--- a/ash/system/holding_space/holding_space_item_chips_container.cc
+++ b/ash/system/holding_space/holding_space_item_chips_container.cc
@@ -7,6 +7,7 @@
 #include "ash/public/cpp/holding_space/holding_space_constants.h"
 #include "ui/views/layout/layout_manager_base.h"
 #include "ui/views/layout/proposed_layout.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
 
 namespace ash {
 namespace {
@@ -115,8 +116,7 @@
 
 HoldingSpaceItemChipsContainer::~HoldingSpaceItemChipsContainer() = default;
 
-const char* HoldingSpaceItemChipsContainer::GetClassName() const {
-  return "HoldingSpaceItemChipsContainer";
-}
+BEGIN_METADATA(HoldingSpaceItemChipsContainer, views::View)
+END_METADATA
 
 }  // namespace ash
\ No newline at end of file
diff --git a/ash/system/holding_space/holding_space_item_chips_container.h b/ash/system/holding_space/holding_space_item_chips_container.h
index e7c3ffe..96956a7 100644
--- a/ash/system/holding_space/holding_space_item_chips_container.h
+++ b/ash/system/holding_space/holding_space_item_chips_container.h
@@ -6,6 +6,7 @@
 #define ASH_SYSTEM_HOLDING_SPACE_HOLDING_SPACE_ITEM_CHIPS_CONTAINER_H_
 
 #include "ash/ash_export.h"
+#include "ui/views/metadata/metadata_header_macros.h"
 #include "ui/views/view.h"
 
 namespace ash {
@@ -13,15 +14,14 @@
 // A container view which arranges item chips into a 2 column grid.
 class HoldingSpaceItemChipsContainer : public views::View {
  public:
+  METADATA_HEADER(HoldingSpaceItemChipsContainer);
+
   HoldingSpaceItemChipsContainer();
   HoldingSpaceItemChipsContainer(const HoldingSpaceItemChipsContainer& other) =
       delete;
   HoldingSpaceItemChipsContainer& operator=(
       const HoldingSpaceItemChipsContainer& other) = delete;
   ~HoldingSpaceItemChipsContainer() override;
-
-  // views::View:
-  const char* GetClassName() const override;
 };
 
 }  // namespace ash
diff --git a/ash/system/holding_space/holding_space_tray.cc b/ash/system/holding_space/holding_space_tray.cc
index f37971ac..903cac8f 100644
--- a/ash/system/holding_space/holding_space_tray.cc
+++ b/ash/system/holding_space/holding_space_tray.cc
@@ -28,6 +28,7 @@
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/menu/menu_runner.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
 
 namespace ash {
 
@@ -185,10 +186,6 @@
   return bubble_ ? bubble_->GetBubbleView() : nullptr;
 }
 
-const char* HoldingSpaceTray::GetClassName() const {
-  return "HoldingSpaceTray";
-}
-
 void HoldingSpaceTray::SetVisiblePreferred(bool preferred_visibility) {
   if (visible_preferred() != preferred_visibility) {
     holding_space_metrics::RecordPodAction(
@@ -422,4 +419,7 @@
   return previews_tray_icon_ && previews_tray_icon_->GetVisible();
 }
 
+BEGIN_METADATA(HoldingSpaceTray, TrayBackgroundView)
+END_METADATA
+
 }  // namespace ash
diff --git a/ash/system/holding_space/holding_space_tray.h b/ash/system/holding_space/holding_space_tray.h
index ff1d40f9..2cc03fb 100644
--- a/ash/system/holding_space/holding_space_tray.h
+++ b/ash/system/holding_space/holding_space_tray.h
@@ -23,6 +23,7 @@
 #include "base/timer/timer.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/views/context_menu_controller.h"
+#include "ui/views/metadata/metadata_header_macros.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_observer.h"
 
@@ -47,6 +48,8 @@
                                     public views::ContextMenuController,
                                     public views::WidgetObserver {
  public:
+  METADATA_HEADER(HoldingSpaceTray);
+
   explicit HoldingSpaceTray(Shelf* shelf);
   HoldingSpaceTray(const HoldingSpaceTray& other) = delete;
   HoldingSpaceTray& operator=(const HoldingSpaceTray& other) = delete;
@@ -63,7 +66,6 @@
   void CloseBubble() override;
   void ShowBubble(bool show_by_click) override;
   TrayBubbleView* GetBubbleView() override;
-  const char* GetClassName() const override;
   void SetVisiblePreferred(bool visible_preferred) override;
 
   void set_use_zero_previews_update_delay_for_testing(bool zero_delay) {
diff --git a/ash/system/phonehub/silence_phone_quick_action_controller.cc b/ash/system/phonehub/silence_phone_quick_action_controller.cc
index 49c0823..3c85e65b 100644
--- a/ash/system/phonehub/silence_phone_quick_action_controller.cc
+++ b/ash/system/phonehub/silence_phone_quick_action_controller.cc
@@ -45,6 +45,9 @@
   item_ = new QuickActionItem(this, IDS_ASH_PHONE_HUB_SILENCE_PHONE_TITLE,
                               kPhoneHubSilencePhoneOnIcon,
                               kPhoneHubSilencePhoneOffIcon);
+  item_->icon_button()->set_button_behavior(
+      FeaturePodIconButton::DisabledButtonBehavior::
+          kCanDisplayDisabledToggleValue);
   OnDndStateChanged();
   return item_;
 }
@@ -106,7 +109,6 @@
       sub_label_text = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_ON_STATE;
       break;
     case ActionState::kDisabled:
-      // TODO(1155784): Update disabled view with matching toggle-state colors.
       icon_enabled = dnd_controller_->IsDndEnabled();
       button_enabled = false;
       state_text_id = IDS_ASH_PHONE_HUB_SILENCE_BUTTON_NOT_AVAILABLE_TOOLTIP;
diff --git a/ash/system/unified/feature_pod_button.cc b/ash/system/unified/feature_pod_button.cc
index d4d5e5a..f271d22 100644
--- a/ash/system/unified/feature_pod_button.cc
+++ b/ash/system/unified/feature_pod_button.cc
@@ -92,14 +92,20 @@
   const AshColorProvider* color_provider = AshColorProvider::Get();
   SkColor color = color_provider->GetControlsLayerColor(
       ControlsLayerType::kControlBackgroundColorInactive);
-  if (GetEnabled()) {
-    if (toggled_) {
-      color = color_provider->GetControlsLayerColor(
-          ControlsLayerType::kControlBackgroundColorActive);
-    }
-  } else {
-    color = AshColorProvider::GetDisabledColor(color);
+
+  bool should_show_button_toggled_on =
+      toggled_ && (GetEnabled() ||
+                   button_behavior_ ==
+                       DisabledButtonBehavior::kCanDisplayDisabledToggleValue);
+  if (should_show_button_toggled_on) {
+    color = color_provider->GetControlsLayerColor(
+        ControlsLayerType::kControlBackgroundColorActive);
   }
+
+  // If the button is disabled, apply opacity filter to the color.
+  if (!GetEnabled())
+    color = AshColorProvider::GetDisabledColor(color);
+
   flags.setColor(color);
 
   flags.setStyle(cc::PaintFlags::kFill_Style);
diff --git a/ash/system/unified/feature_pod_button.h b/ash/system/unified/feature_pod_button.h
index dfdd6f0..934491d0 100644
--- a/ash/system/unified/feature_pod_button.h
+++ b/ash/system/unified/feature_pod_button.h
@@ -23,6 +23,15 @@
 // A toggle button with an icon used by feature pods and in other places.
 class FeaturePodIconButton : public views::ImageButton {
  public:
+  // Used to determine how the button will behave when disabled.
+  enum class DisabledButtonBehavior {
+    // The button will display toggle button as off.
+    kNone = 0,
+
+    // The button will display on/off status of toggle.
+    kCanDisplayDisabledToggleValue = 1,
+  };
+
   FeaturePodIconButton(PressedCallback callback, bool is_togglable);
   ~FeaturePodIconButton() override;
 
@@ -32,6 +41,10 @@
   // Sets the button's icon.
   void SetVectorIcon(const gfx::VectorIcon& icon);
 
+  void set_button_behavior(DisabledButtonBehavior button_behavior) {
+    button_behavior_ = button_behavior;
+  }
+
   // views::ImageButton:
   void PaintButtonContents(gfx::Canvas* canvas) override;
   std::unique_ptr<views::InkDrop> CreateInkDrop() override;
@@ -55,6 +68,8 @@
   // True if the button is currently toggled.
   bool toggled_ = false;
 
+  DisabledButtonBehavior button_behavior_ = DisabledButtonBehavior::kNone;
+
   const gfx::VectorIcon* icon_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(FeaturePodIconButton);
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc
index f166fc7e..dfc6545 100644
--- a/ash/wm/desks/desks_unittests.cc
+++ b/ash/wm/desks/desks_unittests.cc
@@ -3705,7 +3705,8 @@
   ~DesksMockTimeTest() override = default;
 };
 
-TEST_F(DesksMockTimeTest, DeskTraversalNonTouchpadMetrics) {
+// crbug.com/1163489
+TEST_F(DesksMockTimeTest, DISABLED_DeskTraversalNonTouchpadMetrics) {
   NewDesk();
   NewDesk();
   NewDesk();
diff --git a/ash/wm/window_cycle/window_cycle_controller.cc b/ash/wm/window_cycle/window_cycle_controller.cc
index 6d21159..daaf4c2 100644
--- a/ash/wm/window_cycle/window_cycle_controller.cc
+++ b/ash/wm/window_cycle/window_cycle_controller.cc
@@ -89,6 +89,8 @@
   if (!IsCycling())
     StartCycling();
 
+  // TODO(crbug.com/1157100): Handle window highlighting after switching
+  // alt-tab mode.
   Step(direction);
 }
 
@@ -173,23 +175,10 @@
 }
 
 void WindowCycleController::SetAltTabMode(DesksMruType alt_tab_mode) {
-  DCHECK(features::IsBentoEnabled());
   if (alt_tab_mode_ == alt_tab_mode)
     return;
   alt_tab_mode_ = alt_tab_mode;
   MaybeResetCycleList();
-
-  is_switching_mode_ = true;
-  // When user first press alt + tab, `HandleCycleForwardMRU` triggers
-  // `HandleCycleWindow(WindowCycleController::FORWARD)` since it considers
-  // the initial tab as forward cycling. Therefore, switching the mode
-  // should imitate the same forward cycling behavior after the cycle is reset.
-  HandleCycleWindow(WindowCycleController::FORWARD);
-  is_switching_mode_ = false;
-}
-
-bool WindowCycleController::IsSwitchingMode() {
-  return features::IsBentoEnabled() && is_switching_mode_;
 }
 
 bool WindowCycleController::IsAltTabPerActiveDesk() {
diff --git a/ash/wm/window_cycle/window_cycle_controller.h b/ash/wm/window_cycle/window_cycle_controller.h
index 06893da5..9ff7de3 100644
--- a/ash/wm/window_cycle/window_cycle_controller.h
+++ b/ash/wm/window_cycle/window_cycle_controller.h
@@ -95,12 +95,6 @@
   // to all desk unless LimitAltTabToActiveDesk flag is explicitly enabled.
   bool IsAltTabPerActiveDesk();
 
-  // Returns true while switching the alt-tab mode and Bento flag is enabled.
-  // This helps `Scroll()` and `Step()` distinguish between pressing tabs and
-  // switching mode, so they refresh |current_index_| and the highlighted
-  // window correctly.
-  bool IsSwitchingMode();
-
  private:
   // Gets a list of windows from the currently open windows, removing windows
   // with transient roots already in the list. The returned list of windows
@@ -136,9 +130,6 @@
   // TODO(crbug.com/1157105): Store per-desk mode in primary user pref.
   DesksMruType alt_tab_mode_ = DesksMruType::kAllDesks;
 
-  // Tracks whether alt-tab mode is currently switching or not.
-  bool is_switching_mode_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(WindowCycleController);
 };
 
diff --git a/ash/wm/window_cycle/window_cycle_controller_unittest.cc b/ash/wm/window_cycle/window_cycle_controller_unittest.cc
index 0371c1d..9906fc26 100644
--- a/ash/wm/window_cycle/window_cycle_controller_unittest.cc
+++ b/ash/wm/window_cycle/window_cycle_controller_unittest.cc
@@ -1540,132 +1540,4 @@
   waiter.Wait();
 }
 
-// Tests that switching between modes correctly reset the alt-tab-highlighted
-// window to the second most recently used window, i.e. the next window to tab
-// into from the currently used window. Since the window cycle list is ordered
-// by MRU, such window is therefore the second window in the MRU list.
-TEST_F(ModeSelectionWindowCycleControllerTest,
-       SwitchingModeUpdatesWindowHighlight) {
-  WindowCycleController* cycle_controller =
-      Shell::Get()->window_cycle_controller();
-
-  // Create two windows for desk1 and three windows for desk2 in the reversed
-  // order of the most recently active window.
-  auto win4 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
-  auto win3 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
-  auto* desks_controller = DesksController::Get();
-  desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
-  ASSERT_EQ(2u, desks_controller->desks().size());
-  const Desk* desk_2 = desks_controller->desks()[1].get();
-  ActivateDesk(desk_2);
-  EXPECT_EQ(desk_2, desks_controller->active_desk());
-  auto win2 = CreateAppWindow(gfx::Rect(0, 0, 300, 200));
-  auto win1 = CreateAppWindow(gfx::Rect(10, 30, 400, 200));
-  auto win0 = CreateAppWindow(gfx::Rect(10, 30, 400, 200));
-
-  // Enter the all-desk mode by default with the window order [0, 1, 2, 3 ,4].
-  cycle_controller->StartCycling();
-  cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
-
-  EXPECT_FALSE(cycle_controller->IsAltTabPerActiveDesk());
-  auto cycle_windows = GetWindows(cycle_controller);
-  // The window list is MRU ordered.
-  EXPECT_EQ(win0.get(), cycle_windows[0]);
-  EXPECT_EQ(win1.get(), cycle_windows[1]);
-  EXPECT_EQ(win2.get(), cycle_windows[2]);
-  EXPECT_EQ(win3.get(), cycle_windows[3]);
-  EXPECT_EQ(win4.get(), cycle_windows[4]);
-  // Alt-Tab should highlight the second most recently used window, which is
-  // the second window in the MRU list, win1.
-  EXPECT_EQ(win1.get(), GetTargetWindow());
-
-  // Step to win2 and win3, so we are now select a window in a non-active desk.
-  cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  EXPECT_EQ(win2.get(), GetTargetWindow());
-  cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  EXPECT_EQ(win3.get(), GetTargetWindow());
-
-  // Switching from the all-desks mode, which highlights a non-current-desk
-  // window to the current-desk mode [0, 1, 2] should resolve the highlight
-  // correctly to win1, the second window in the cycle list.
-  SwitchPerDeskAltTabMode(true);
-  EXPECT_EQ(win1.get(), GetTargetWindow());
-  EXPECT_EQ(win1.get(), cycle_windows[1]);
-  // Step to win2.
-  cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  EXPECT_EQ(win2.get(), GetTargetWindow());
-
-  // Switching back to the all-desk mode should reset highlight to win1 again.
-  SwitchPerDeskAltTabMode(false);
-  EXPECT_EQ(win1.get(), GetTargetWindow());
-  cycle_controller->CompleteCycling();
-}
-
-// Similar to `SwitchingModeUpdatesWindowHighlight`, tests that switching the
-// alt-tab mode updates the highlighted window to the first window (most
-// recently used) in the special case where all windows are minimized.
-// When they are minimized, cycling forward should help unminimize the most
-// recently used window rather than trying to open the second most recently
-// used window.
-TEST_F(ModeSelectionWindowCycleControllerTest,
-       SwitchingModeUpdatesMinimizedWindowHighlight) {
-  WindowCycleController* cycle_controller =
-      Shell::Get()->window_cycle_controller();
-
-  // Create two windows for desk1 and three windows for desk2 in the reversed
-  // order of the most recently active window.
-  auto win4 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
-  auto win3 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
-  auto* desks_controller = DesksController::Get();
-  desks_controller->NewDesk(DesksCreationRemovalSource::kButton);
-  ASSERT_EQ(2u, desks_controller->desks().size());
-  const Desk* desk_2 = desks_controller->desks()[1].get();
-  ActivateDesk(desk_2);
-  EXPECT_EQ(desk_2, desks_controller->active_desk());
-  auto win2 = CreateAppWindow(gfx::Rect(0, 0, 300, 200));
-  auto win1 = CreateAppWindow(gfx::Rect(10, 30, 400, 200));
-  auto win0 = CreateAppWindow(gfx::Rect(10, 30, 400, 200));
-
-  // Minimize all windows to test this special case.
-  WindowState::Get(win4.get())->Minimize();
-  WindowState::Get(win3.get())->Minimize();
-  WindowState::Get(win2.get())->Minimize();
-  WindowState::Get(win1.get())->Minimize();
-  WindowState::Get(win0.get())->Minimize();
-  EXPECT_FALSE(WindowState::Get(win0.get())->IsActive());
-  EXPECT_FALSE(WindowState::Get(win1.get())->IsActive());
-  EXPECT_FALSE(WindowState::Get(win2.get())->IsActive());
-  EXPECT_FALSE(WindowState::Get(win3.get())->IsActive());
-  EXPECT_FALSE(WindowState::Get(win4.get())->IsActive());
-
-  // Enter the all-desk mode by default with the window order [0, 1, 2, 3 ,4].
-  cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  EXPECT_FALSE(cycle_controller->IsAltTabPerActiveDesk());
-  auto cycle_windows = GetWindows(cycle_controller);
-  EXPECT_EQ(5u, GetWindowCycleItemViews().size());
-  // The window list is MRU ordered.
-  EXPECT_EQ(win0.get(), cycle_windows[0]);
-  EXPECT_EQ(win1.get(), cycle_windows[1]);
-  EXPECT_EQ(win2.get(), cycle_windows[2]);
-  EXPECT_EQ(win3.get(), cycle_windows[3]);
-  EXPECT_EQ(win4.get(), cycle_windows[4]);
-  // Step forward a few times and switch to all-desks mode. This should
-  // highlight win0, the first window in the current-desk cycle list.
-  cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  SwitchPerDeskAltTabMode(true);
-  EXPECT_EQ(3u, GetWindowCycleItemViews().size());
-  EXPECT_EQ(win0.get(), GetTargetWindow());
-  EXPECT_EQ(win0.get(), cycle_windows[0]);
-
-  // Stepping to win1 and switching back to the all-desk mode should reset
-  // a highlight to win0 again.
-  cycle_controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  EXPECT_EQ(win1.get(), GetTargetWindow());
-  SwitchPerDeskAltTabMode(false);
-  EXPECT_EQ(5u, GetWindowCycleItemViews().size());
-  EXPECT_EQ(win0.get(), GetTargetWindow());
-  cycle_controller->CompleteCycling();
-}
-
 }  // namespace ash
diff --git a/ash/wm/window_cycle/window_cycle_list.cc b/ash/wm/window_cycle/window_cycle_list.cc
index e1210407..f00ec39 100644
--- a/ash/wm/window_cycle/window_cycle_list.cc
+++ b/ash/wm/window_cycle/window_cycle_list.cc
@@ -690,16 +690,7 @@
   }
 
   const int offset = direction == WindowCycleController::FORWARD ? 1 : -1;
-  if (offset == 1 && !wm::IsActiveWindow(windows_[0]) &&
-      Shell::Get()->window_cycle_controller()->IsSwitchingMode()) {
-    // Similar to `WindowCycleList::Scroll()`, when switching to alt-tab mode,
-    // if all windows are minimized, the starting window should be the first
-    // one rather than the second. Note that during entering alt-tab mode,
-    // `SetFocusedWindow()` does nothing, so we don't need to prevent it here.
-    SetFocusedWindow(windows_[0]);
-  } else {
-    SetFocusedWindow(windows_[GetOffsettedWindowIndex(offset)]);
-  }
+  SetFocusedWindow(windows_[GetOffsettedWindowIndex(offset)]);
   Scroll(offset);
 }
 
@@ -884,17 +875,16 @@
 
   DCHECK(static_cast<size_t>(current_index_) < windows_.size());
 
-  // If alt-tab is entered or switched to the other mode, check the following
-  // special case: user is cycling forward but the MRU window is not active.
-  // This occurs when all windows are minimized. The starting window should be
-  // the first one rather than the second.
-  if ((!cycle_view_ ||
-       Shell::Get()->window_cycle_controller()->IsSwitchingMode()) &&
-      current_index_ == 0 && offset == 1 && !wm::IsActiveWindow(windows_[0])) {
-    current_index_ = -1;
+  if (!cycle_view_ && current_index_ == 0) {
+    // Special case the situation where we're cycling forward but the MRU
+    // window is not active. This occurs when all windows are minimized. The
+    // starting window should be the first one rather than the second.
+    if (offset == 1 && !wm::IsActiveWindow(windows_[0]))
+      current_index_ = -1;
   }
 
   current_index_ = GetOffsettedWindowIndex(offset);
+
   if (ShouldShowUi()) {
     if (current_index_ > 1)
       InitWindowCycleView();
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc
index 6d327e9..9f6ca3b 100644
--- a/base/allocator/partition_allocator/partition_alloc_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -1685,6 +1685,81 @@
   }
 }
 
+// These tests rely on precise layout. We handle cookies, not reference counts.
+#if !ENABLE_REF_COUNT_FOR_BACKUP_REF_PTR
+
+namespace {
+
+// Used to adjust the returned pointer. This is necessary to make the following
+// death tests pass with DCHECK_IS_ON(), as they rely on the precise knowledge
+// of the allocator layout. Since the offset is 0 for non-DCHECK() builds, this
+// provides the benefit of more testing coverage.
+constexpr size_t kAllocationOffset =
+#if DCHECK_IS_ON()
+    kCookieSize;
+#else
+    0;
+#endif
+}  // namespace
+
+TEST_F(PartitionAllocDeathTest, UseAfterFreeDetection) {
+  void* data = allocator.root()->Alloc(100, "");
+  allocator.root()->Free(data);
+
+  // use after free, not crashing here, but the next allocation should crash,
+  // since we corrupted the freelist.
+  //
+  // When there is a cookie, must offset the UaF since the freelist entry is
+  // stored over the cookie area, not the allocated data.
+  void* data_before_cookie = reinterpret_cast<char*>(data) - kAllocationOffset;
+  memset(data_before_cookie, 0x42, 100);
+  EXPECT_DEATH(allocator.root()->Alloc(100, ""), "");
+}
+
+TEST_F(PartitionAllocDeathTest, FreelistCorruption) {
+  const size_t alloc_size = 2 * sizeof(void*);
+  void** fake_freelist_entry =
+      static_cast<void**>(allocator.root()->Alloc(alloc_size, ""));
+  fake_freelist_entry[0] = nullptr;
+  fake_freelist_entry[1] = nullptr;
+
+  void** uaf_data =
+      static_cast<void**>(allocator.root()->Alloc(alloc_size, ""));
+  allocator.root()->Free(uaf_data);
+  void** uaf_data_before_cookie = reinterpret_cast<void**>(
+      reinterpret_cast<char*>(uaf_data) - kAllocationOffset);
+  // Try to confuse the allocator. This is still easy to circumvent willingly,
+  // "just" need to set uaf_data[1] to ~uaf_data[0].
+  uaf_data_before_cookie[0] = fake_freelist_entry;
+  EXPECT_DEATH(allocator.root()->Alloc(alloc_size, ""), "");
+}
+
+// With DCHECK_IS_ON(), cookies already handle off-by-one detection.
+#if !DCHECK_IS_ON()
+TEST_F(PartitionAllocDeathTest, OffByOneDetection) {
+  const size_t alloc_size = 2 * sizeof(void*);
+  char* array = static_cast<char*>(allocator.root()->Alloc(alloc_size, ""));
+  array[alloc_size] = 'A';
+  // Crash at the next allocation. This assumes that we are touching a new,
+  // non-randomized slot span, where the next slot to be handed over to the
+  // application directly follows the current one.
+  EXPECT_DEATH(allocator.root()->Alloc(alloc_size, ""), "");
+}
+
+TEST_F(PartitionAllocDeathTest, OffByOneDetectionWithRealisticData) {
+  const size_t alloc_size = 2 * sizeof(void*);
+  void** array = static_cast<void**>(allocator.root()->Alloc(alloc_size, ""));
+  char valid;
+  array[2] = &valid;
+  // Crash at the next allocation. This assumes that we are touching a new,
+  // non-randomized slot span, where the next slot to be handed over to the
+  // application directly follows the current one.
+  EXPECT_DEATH(allocator.root()->Alloc(alloc_size, ""), "");
+}
+#endif  // !DCHECK_IS_ON()
+
+#endif  // !ENABLE_REF_COUNT_FOR_BACKUP_REF_PTR
+
 #endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
 
 // Tests that |PartitionDumpStats| and |PartitionDumpStats| run without
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc
index 1e8089e..88241e1 100644
--- a/base/allocator/partition_allocator/partition_bucket.cc
+++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -416,6 +416,10 @@
     slot_span->num_unprovisioned_slots--;
   }
 
+#if DCHECK_IS_ON()
+  slot_span->freelist_head->CheckFreeList();
+#endif
+
   return return_slot;
 }
 
@@ -628,7 +632,10 @@
     PartitionFreelistEntry* new_head = entry->GetNext();
     new_slot_span->SetFreelistHead(new_head);
     new_slot_span->num_allocated_slots++;
-    return entry;
+
+    // We likely set *is_already_zeroed to true above, make sure that the
+    // freelist entry doesn't contain data.
+    return entry->ClearForAllocation();
   }
 
   // Otherwise, we need to provision more slots by committing more pages. Build
diff --git a/base/allocator/partition_allocator/partition_freelist_entry.h b/base/allocator/partition_allocator/partition_freelist_entry.h
index e0c12abe..062ff0a 100644
--- a/base/allocator/partition_allocator/partition_freelist_entry.h
+++ b/base/allocator/partition_allocator/partition_freelist_entry.h
@@ -9,14 +9,30 @@
 
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/compiler_specific.h"
+#include "base/dcheck_is_on.h"
+#include "base/immediate_crash.h"
 #include "base/sys_byteorder.h"
 #include "build/build_config.h"
 
 namespace base {
 namespace internal {
 
+namespace {
+
+[[noreturn]] NOINLINE void FreelistCorruptionDetected() {
+  IMMEDIATE_CRASH();
+}
+
+}  // namespace
+
 struct EncodedPartitionFreelistEntry;
 
+static_assert((1 << kMinBucketedOrder) >= 2 * sizeof(void*),
+              "Need enough space for two pointers in freelist entries");
+
+// Freelist entries are encoded for security reasons. See
+// //base/allocator/partition_allocator/PartitionAlloc.md and |Transform()| for
+// the rationale and mechanism, respectively.
 class PartitionFreelistEntry {
  public:
   PartitionFreelistEntry() { SetNext(nullptr); }
@@ -27,7 +43,9 @@
       void* ptr,
       PartitionFreelistEntry* next) {
     auto* entry = reinterpret_cast<PartitionFreelistEntry*>(ptr);
-    entry->SetNextForThreadCache(next);
+    // ThreadCache freelists can point to entries across superpage boundaries,
+    // no check contrary to |SetNext()|.
+    entry->SetNextInternal(next);
     return entry;
   }
 
@@ -42,13 +60,29 @@
   }
 
   ALWAYS_INLINE PartitionFreelistEntry* GetNext() const;
+  NOINLINE void CheckFreeList() const {
+    for (auto* entry = this; entry; entry = entry->GetNext()) {
+      // |GetNext()| checks freelist integrity.
+    }
+  }
 
-  // Regular freelists always point to an entry within the same super page.
   ALWAYS_INLINE void SetNext(PartitionFreelistEntry* ptr) {
-    PA_DCHECK(!ptr ||
-              (reinterpret_cast<uintptr_t>(this) & kSuperPageBaseMask) ==
-                  (reinterpret_cast<uintptr_t>(ptr) & kSuperPageBaseMask));
-    next_ = Encode(ptr);
+#if DCHECK_IS_ON()
+    // Regular freelists always point to an entry within the same super page.
+    if (UNLIKELY(ptr &&
+                 (reinterpret_cast<uintptr_t>(this) & kSuperPageBaseMask) !=
+                     (reinterpret_cast<uintptr_t>(ptr) & kSuperPageBaseMask))) {
+      FreelistCorruptionDetected();
+    }
+#endif
+    SetNextInternal(ptr);
+  }
+
+  // Zeroes out |this| before returning it.
+  ALWAYS_INLINE void* ClearForAllocation() {
+    next_ = nullptr;
+    inverted_next_ = 0;
+    return reinterpret_cast<void*>(this);
   }
 
  private:
@@ -70,16 +104,21 @@
     return reinterpret_cast<void*>(masked);
   }
 
-  // ThreadCache freelists can point to entries across superpage boundaries.
-  ALWAYS_INLINE void SetNextForThreadCache(PartitionFreelistEntry* ptr) {
+  ALWAYS_INLINE void SetNextInternal(PartitionFreelistEntry* ptr) {
     next_ = Encode(ptr);
+    inverted_next_ = ~reinterpret_cast<uintptr_t>(next_);
   }
 
   EncodedPartitionFreelistEntry* next_;
+  // This is intended to detect unintentional corruptions of the freelist.
+  // These can happen due to a Use-after-Free, or overflow of the previous
+  // allocation in the slot span.
+  uintptr_t inverted_next_;
 };
 
 struct EncodedPartitionFreelistEntry {
   char scrambled[sizeof(PartitionFreelistEntry*)];
+  char copy_of_scrambled[sizeof(PartitionFreelistEntry*)];
 
   EncodedPartitionFreelistEntry() = delete;
   ~EncodedPartitionFreelistEntry() = delete;
@@ -96,6 +135,11 @@
               "Should not have padding");
 
 ALWAYS_INLINE PartitionFreelistEntry* PartitionFreelistEntry::GetNext() const {
+  // GetNext() can be called on decommitted memory, which is full of
+  // zeroes. This is not a corruption issue, so only check integrity when we
+  // have a non-nullptr |next_| pointer.
+  if (UNLIKELY(next_ && ~reinterpret_cast<uintptr_t>(next_) != inverted_next_))
+    FreelistCorruptionDetected();
   return EncodedPartitionFreelistEntry::Decode(next_);
 }
 
diff --git a/base/allocator/partition_allocator/partition_page.cc b/base/allocator/partition_allocator/partition_page.cc
index 5131e6f..0c21582 100644
--- a/base/allocator/partition_allocator/partition_page.cc
+++ b/base/allocator/partition_allocator/partition_page.cc
@@ -126,6 +126,9 @@
     if (UNLIKELY(bucket->is_direct_mapped())) {
       return PartitionDirectUnmap(this);
     }
+#if DCHECK_IS_ON()
+    freelist_head->CheckFreeList();
+#endif
     // If it's the current active slot span, change it. We bounce the slot span
     // to the empty list as a force towards defragmentation.
     if (LIKELY(this == bucket->active_slot_spans_head))
diff --git a/base/allocator/partition_allocator/partition_root.cc b/base/allocator/partition_allocator/partition_root.cc
index 8ff1d0a..1d8b01f8 100644
--- a/base/allocator/partition_allocator/partition_root.cc
+++ b/base/allocator/partition_allocator/partition_root.cc
@@ -13,6 +13,10 @@
 #include "base/allocator/partition_allocator/pcscan.h"
 #include "build/build_config.h"
 
+#if defined(OS_WIN)
+#include "wow64apiset.h"
+#endif
+
 namespace base {
 
 namespace {
@@ -320,10 +324,10 @@
 [[noreturn]] NOINLINE void PartitionRoot<thread_safe>::OutOfMemory(
     size_t size) {
 #if !defined(ARCH_CPU_64_BITS)
-  size_t virtual_address_space_size =
+  const size_t virtual_address_space_size =
       total_size_of_super_pages.load(std::memory_order_relaxed) +
       total_size_of_direct_mapped_pages.load(std::memory_order_relaxed);
-  size_t uncommitted_size =
+  const size_t uncommitted_size =
       virtual_address_space_size -
       total_size_of_committed_pages.load(std::memory_order_relaxed);
 
@@ -333,11 +337,20 @@
     internal::PartitionOutOfMemoryWithLotsOfUncommitedPages(size);
   }
 
-  constexpr size_t kReasonableVirtualSize =
 #if defined(OS_WIN)
-      // 1GiB on Windows, as the entire address space is typically 2GiB.
-      1024 * 1024 * 1024;
+  // If true then we are running on 64-bit Windows.
+  BOOL is_wow_64 = FALSE;
+  // Intentionally ignoring failures.
+  IsWow64Process(GetCurrentProcess(), &is_wow_64);
+  // 32-bit address space on Windows is typically either 2 GiB (on 32-bit
+  // Windows) or 4 GiB (on 64-bit Windows). 2.8 and 1.0 GiB are just rough
+  // guesses as to how much address space PA can consume (note that code,
+  // stacks, and other allocators will also consume address space).
+  const size_t kReasonableVirtualSize = (is_wow_64 ? 2800 : 1024) * 1024 * 1024;
+  // Make it obvious whether we are running on 64-bit Windows.
+  base::debug::Alias(&is_wow_64);
 #else
+  constexpr size_t kReasonableVirtualSize =
       // 1.5GiB elsewhere, since address space is typically 3GiB.
       (1024 + 512) * 1024 * 1024;
 #endif
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 506f8b8..456cec4 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20210105.2.1
+0.20210105.3.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 506f8b8..456cec4 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20210105.2.1
+0.20210105.3.1
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index f53d7a09..2b112b2 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -1076,22 +1076,16 @@
   assert(_framework_binary_path != "",
          "Ignore configuration-dependent unused variable warning")
 
-  if (!is_asan && !is_component_build) {
+  if (!is_component_build) {
     action("verify_chrome_framework_order") {
-      script = "//chrome/tools/build/mac/run_verify_order.py"
+      script = "//chrome/tools/build/mac/verify_order.py"
       stamp_file = "$target_out_dir/run_$target_name.stamp"
-      inputs = [
-        script,
-        "//chrome/tools/build/mac/verify_order",
-      ]
+      inputs = [ script ]
       args = [
-        "--stamp",
-        rebase_path(stamp_file, root_out_dir),
-      ]
-      args += [
-        "_ChromeMain",
-        rebase_path(_framework_binary_path, root_out_dir),
-        mac_bin_path,
+        "--stamp=" + rebase_path(stamp_file, root_out_dir),
+        "--binary=" + rebase_path(_framework_binary_path, root_out_dir),
+        "--mac-bin-path=" + mac_bin_path,
+        "--symbol-file=" + rebase_path("app/framework.order", root_build_dir),
       ]
       outputs = [ stamp_file ]
       public_deps = [ ":chrome_framework" ]
diff --git a/chrome/VERSION b/chrome/VERSION
index f72f05f3..2eb6622 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=89
 MINOR=0
-BUILD=4380
+BUILD=4381
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 6b63f668..bb49f751 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -203,6 +203,7 @@
     "//chrome/browser/ui/android/favicon:java_resources",
     "//chrome/browser/ui/android/strings:ui_strings_grd",
     "//chrome/browser/ui/android/theme:java_resources",
+    "//chrome/browser/ui/android/toolbar:java_resources",
     "//chrome/browser/ui/messages/android:java_resources",
     "//components/autofill/android:autofill_java_resources",
     "//components/blocked_content/android:java_resources",
@@ -362,6 +363,7 @@
     "//chrome/browser/version:java",
     "//chrome/browser/video_tutorials:factory_java",
     "//chrome/browser/video_tutorials:java",
+    "//chrome/browser/webapps/android:java",
     "//chrome/browser/webauthn/android:java",
     "//chrome/browser/xsurface:java",
     "//components/autofill/android:autofill_java",
@@ -866,6 +868,7 @@
     "//chrome/browser/video_tutorials:java",
     "//chrome/browser/video_tutorials:test_support_java",
     "//chrome/browser/video_tutorials/internal:junit",
+    "//chrome/browser/webapps/android:java",
     "//chrome/browser/xsurface:java",
     "//chrome/test/android:chrome_java_test_support",
     "//components/background_task_scheduler:background_task_scheduler_java",
@@ -1117,6 +1120,7 @@
     "//chrome/browser/uid/android:javatests",
     "//chrome/browser/util:java",
     "//chrome/browser/version:java",
+    "//chrome/browser/webapps/android:java",
     "//chrome/test:sync_integration_test_support_java",
     "//chrome/test/android:chrome_java_test_pagecontroller",
     "//chrome/test/android:chrome_java_test_support",
@@ -3470,8 +3474,6 @@
     "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenCoordinator.java",
     "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenInstaller.java",
     "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenMediator.java",
-    "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaBottomSheetController.java",
-    "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaBottomSheetControllerProvider.java",
     "java/src/org/chromium/chrome/browser/webauth/AuthenticatorImpl.java",
     "java/src/org/chromium/chrome/browser/webauth/Fido2Helper.java",
   ]
diff --git a/chrome/android/DEPS b/chrome/android/DEPS
index ace544b..ace4f6d 100644
--- a/chrome/android/DEPS
+++ b/chrome/android/DEPS
@@ -30,6 +30,7 @@
   "+chrome/browser/util/android/java",
   "+chrome/browser/version",
   "+chrome/browser/video_tutorials",
+  "+chrome/browser/webapps/android",
   "+chrome/browser/webauthn/android",
   "+components/browser_ui/android/bottomsheet",
   "+components/browser_ui/banners/android",
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni
index ca4cdb82..3d22dba 100644
--- a/chrome/android/chrome_java_resources.gni
+++ b/chrome/android/chrome_java_resources.gni
@@ -791,7 +791,6 @@
   "java/res/layout/contextual_search_promo_view.xml",
   "java/res/layout/contextual_search_quick_action_icon_view.xml",
   "java/res/layout/contextual_search_term_view.xml",
-  "java/res/layout/control_container.xml",
   "java/res/layout/custom_preference.xml",
   "java/res/layout/custom_tabs_bottombar.xml",
   "java/res/layout/custom_tabs_bottombar_item.xml",
@@ -895,8 +894,6 @@
   "java/res/layout/passwords_progress_dialog.xml",
   "java/res/layout/powered_by_chrome_footer.xml",
   "java/res/layout/preference_text_scale.xml",
-  "java/res/layout/pwa_install_bottom_sheet_content.xml",
-  "java/res/layout/pwa_install_bottom_sheet_toolbar.xml",
   "java/res/layout/radio_button_group_homepage_preference.xml",
   "java/res/layout/radio_button_group_theme_preference.xml",
   "java/res/layout/recent_tabs_group_item.xml",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index f4983f68..8fa1cff8 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -181,7 +181,6 @@
   "java/src/org/chromium/chrome/browser/browserservices/ClientAppBroadcastReceiver.java",
   "java/src/org/chromium/chrome/browser/browserservices/ClientAppDataRegister.java",
   "java/src/org/chromium/chrome/browser/browserservices/ManageTrustedWebActivityDataActivity.java",
-  "java/src/org/chromium/chrome/browser/browserservices/OriginVerifier.java",
   "java/src/org/chromium/chrome/browser/browserservices/PostMessageHandler.java",
   "java/src/org/chromium/chrome/browser/browserservices/QualityEnforcer.java",
   "java/src/org/chromium/chrome/browser/browserservices/SessionDataHolder.java",
@@ -1514,19 +1513,11 @@
   "java/src/org/chromium/chrome/browser/webapps/WebappLauncherActivity.java",
   "java/src/org/chromium/chrome/browser/webapps/WebappLocator.java",
   "java/src/org/chromium/chrome/browser/webapps/WebappRegistry.java",
-  "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenBottomSheetViewBinder.java",
   "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenCoordinator.java",
   "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenDialogView.java",
   "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenInstaller.java",
   "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenMediator.java",
-  "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenProperties.java",
   "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenViewBinder.java",
-  "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenViewDelegate.java",
-  "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaBottomSheetController.java",
-  "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaBottomSheetControllerFactory.java",
-  "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaBottomSheetControllerProvider.java",
-  "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaInstallBottomSheetContent.java",
-  "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaInstallBottomSheetView.java",
   "java/src/org/chromium/chrome/browser/webauth/AuthenticatorFactory.java",
   "java/src/org/chromium/chrome/browser/webauth/AuthenticatorImpl.java",
   "java/src/org/chromium/chrome/browser/webauth/Fido2ApiHandler.java",
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 9bfdf8b4..e6fd0b1 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -189,8 +189,6 @@
     <dimen name="find_in_page_popup_height">60dp</dimen>
     <dimen name="find_in_page_popup_margin_end">62dp</dimen>
 
-    <dimen name="webapk_screenshot_margin">20dp</dimen>
-
     <!-- Toolbar dimensions -->
     <dimen name="toolbar_tab_count_text_size_1_digit">12dp</dimen>
     <dimen name="toolbar_tab_count_text_size_2_digit">10dp</dimen>
diff --git a/chrome/android/java/src/PRESUBMIT.py b/chrome/android/java/src/PRESUBMIT.py
index fd7198da..5a9765a 100644
--- a/chrome/android/java/src/PRESUBMIT.py
+++ b/chrome/android/java/src/PRESUBMIT.py
@@ -90,7 +90,6 @@
       BROWSER_ROOT + 'password_manager/AutoSigninFirstRunDialog.java',
       BROWSER_ROOT + r'settings[\\\/].*',
       BROWSER_ROOT + 'signin/AccountPickerDialogFragment.java',
-      BROWSER_ROOT + 'signin/AccountSigninView.java',
       SIGNIN_UI_BROWSER_ROOT + 'ConfirmImportSyncDataDialog.java',
       SIGNIN_UI_BROWSER_ROOT + 'ConfirmManagedSyncDataDialog.java',
       SIGNIN_UI_BROWSER_ROOT + 'ConfirmSyncDataStateMachineDelegate.java',
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/OriginVerifier.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/OriginVerifier.java
deleted file mode 100644
index accc3d1..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/OriginVerifier.java
+++ /dev/null
@@ -1,38 +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.browserservices;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.browser.customtabs.CustomTabsService;
-
-import org.chromium.components.embedder_support.util.Origin;
-
-/**
- * This class forwards calls to
- * {@link org.chromium.chrome.browser.browserservices.verification.OriginVerifier}. It will only
- * exist temporarily to make downstream not break while moving that class.
- */
-public class OriginVerifier {
-    /** See ...verification.OriginVerifier#clearCachedVerificationsForTesting. */
-    @VisibleForTesting
-    public static void clearCachedVerificationsForTesting() {
-        org.chromium.chrome.browser.browserservices.verification.OriginVerifier
-                .clearCachedVerificationsForTesting();
-    }
-
-    /** See ...verification.OriginVerifier#wasPreviouslyVerified. */
-    public static boolean wasPreviouslyVerified(
-            String packageName, Origin origin, @CustomTabsService.Relation int relation) {
-        return org.chromium.chrome.browser.browserservices.verification.OriginVerifier
-                .wasPreviouslyVerified(packageName, origin, relation);
-    }
-
-    /** See ...verification.OriginVerifier#addVerificationOverride. */
-    public static void addVerificationOverride(
-            String packageName, Origin origin, int relationship) {
-        org.chromium.chrome.browser.browserservices.verification.OriginVerifier
-                .addVerificationOverride(packageName, origin, relationship);
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
index c8489ebb..658de0e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -64,8 +64,8 @@
 import org.chromium.chrome.browser.ui.default_browser_promo.DefaultBrowserPromoUtils;
 import org.chromium.chrome.browser.ui.tablet.emptybackground.EmptyBackgroundViewWrapper;
 import org.chromium.chrome.browser.vr.VrModuleProvider;
-import org.chromium.chrome.browser.webapps.addtohomescreen.PwaBottomSheetController;
-import org.chromium.chrome.browser.webapps.addtohomescreen.PwaBottomSheetControllerFactory;
+import org.chromium.chrome.browser.webapps.PwaBottomSheetController;
+import org.chromium.chrome.browser.webapps.PwaBottomSheetControllerFactory;
 import org.chromium.chrome.features.start_surface.StartSurface;
 import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver;
 import org.chromium.components.browser_ui.util.ComposedBrowserControlsVisibilityDelegate;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenCoordinator.java
index dd3f4dc..f485b3c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenCoordinator.java
@@ -7,13 +7,19 @@
 import android.app.Activity;
 import android.content.Context;
 import android.os.Bundle;
+
 import androidx.annotation.StringRes;
 import androidx.annotation.VisibleForTesting;
+
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.banners.AppBannerManager;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.webapps.AddToHomescreenProperties;
+import org.chromium.chrome.browser.webapps.AddToHomescreenViewDelegate;
+import org.chromium.chrome.browser.webapps.PwaBottomSheetController;
+import org.chromium.chrome.browser.webapps.PwaBottomSheetControllerProvider;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.modaldialog.ModalDialogManager;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenDialogView.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenDialogView.java
index 334c89c..3bb3bab 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenDialogView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenDialogView.java
@@ -26,6 +26,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.banners.AppBannerManager;
+import org.chromium.chrome.browser.webapps.AddToHomescreenViewDelegate;
 import org.chromium.ui.modaldialog.DialogDismissalCause;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenMediator.java
index 119dd77..b2d77c8e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenMediator.java
@@ -12,6 +12,8 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.browser.banners.AppData;
+import org.chromium.chrome.browser.webapps.AddToHomescreenProperties;
+import org.chromium.chrome.browser.webapps.AddToHomescreenViewDelegate;
 import org.chromium.components.webapps.WebappsIconUtils;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.WindowAndroid;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenProperties.java
deleted file mode 100644
index c053e20..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenProperties.java
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.webapps.addtohomescreen;
-
-import android.graphics.Bitmap;
-import android.util.Pair;
-import android.view.View.OnClickListener;
-
-import org.chromium.ui.modelutil.PropertyKey;
-import org.chromium.ui.modelutil.PropertyModel;
-
-/**
- * Contains the properties that an add-to-homescreen {@link PropertyModel} can have.
- */
-class AddToHomescreenProperties {
-    static final PropertyModel.WritableObjectPropertyKey<String> TITLE =
-            new PropertyModel.WritableObjectPropertyKey<>();
-    static final PropertyModel.WritableObjectPropertyKey<String> URL =
-            new PropertyModel.WritableObjectPropertyKey<>();
-    static final PropertyModel.WritableObjectPropertyKey<String> CATEGORIES =
-            new PropertyModel.WritableObjectPropertyKey<>();
-    static final PropertyModel.WritableObjectPropertyKey<String> DESCRIPTION =
-            new PropertyModel.WritableObjectPropertyKey<>();
-    static final PropertyModel.WritableObjectPropertyKey<Pair<Bitmap, Boolean>> ICON =
-            new PropertyModel.WritableObjectPropertyKey<>();
-    static final PropertyModel.WritableIntPropertyKey TYPE =
-            new PropertyModel.WritableIntPropertyKey();
-    static final PropertyModel.WritableBooleanPropertyKey CAN_SUBMIT =
-            new PropertyModel.WritableBooleanPropertyKey();
-    static final PropertyModel.WritableObjectPropertyKey<OnClickListener> CLICK_LISTENER =
-            new PropertyModel.WritableObjectPropertyKey<>();
-    static final PropertyModel.WritableObjectPropertyKey<String> NATIVE_INSTALL_BUTTON_TEXT =
-            new PropertyModel.WritableObjectPropertyKey<>();
-    static final PropertyModel.WritableFloatPropertyKey NATIVE_APP_RATING =
-            new PropertyModel.WritableFloatPropertyKey();
-
-    static final PropertyKey[] ALL_KEYS = {TITLE, URL, CATEGORIES, DESCRIPTION, ICON, TYPE,
-            CAN_SUBMIT, CLICK_LISTENER, NATIVE_INSTALL_BUTTON_TEXT, NATIVE_APP_RATING};
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenViewBinder.java
index 01ca49b..1daf8960 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenViewBinder.java
@@ -7,6 +7,7 @@
 import android.graphics.Bitmap;
 import android.util.Pair;
 
+import org.chromium.chrome.browser.webapps.AddToHomescreenProperties;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenTest.java
index 8a45271d..c18b3694 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenTest.java
@@ -35,6 +35,7 @@
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModel;
+import org.chromium.chrome.browser.webapps.AddToHomescreenViewDelegate;
 import org.chromium.chrome.browser.webapps.WebappDataStorage;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenDialogViewTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenDialogViewTest.java
index 4c659b3..90107e8 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenDialogViewTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenDialogViewTest.java
@@ -20,6 +20,7 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.banners.AppBannerManager;
+import org.chromium.chrome.browser.webapps.AddToHomescreenViewDelegate;
 import org.chromium.ui.modaldialog.DialogDismissalCause;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenMediatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenMediatorTest.java
index cf667ac9..469c1e69 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenMediatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenMediatorTest.java
@@ -22,6 +22,7 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.browser.banners.AppData;
+import org.chromium.chrome.browser.webapps.AddToHomescreenProperties;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.modelutil.PropertyModel;
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenViewBinderTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenViewBinderTest.java
index c367d18..ed2f32a 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenViewBinderTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenViewBinderTest.java
@@ -12,6 +12,7 @@
 import org.mockito.Mockito;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.webapps.AddToHomescreenProperties;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 
diff --git a/chrome/app/framework.order b/chrome/app/framework.order
index c24c6304..839144aa 100644
--- a/chrome/app/framework.order
+++ b/chrome/app/framework.order
@@ -23,3 +23,8 @@
 
 # _ChromeMain must be listed last.  That's the whole point of this file.
 _ChromeMain
+
+# For coverage builds.
+_lprofDirMode
+___llvm_profile_filename
+___llvm_profile_raw_version
diff --git a/chrome/app/theme/chrome_unscaled_resources.grd b/chrome/app/theme/chrome_unscaled_resources.grd
index 08da3f7..b4e4545 100644
--- a/chrome/app/theme/chrome_unscaled_resources.grd
+++ b/chrome/app/theme/chrome_unscaled_resources.grd
@@ -121,9 +121,8 @@
         <!-- Borealis icons -->
         <include name="IDR_LOGO_BOREALIS_DEFAULT_192" file="borealis/logo_borealis_default_192.png" type="BINDATA" />
         <!-- Crostini icons -->
-        <include name="IDR_LOGO_CROSTINI_TERMINAL" file="crostini/logo_crostini_terminal.png" type="BINDATA" />
-        <include name="IDR_LOGO_CROSTINI_DEFAULT_32" file="crostini/logo_crostini_default_32.png" type="BINDATA" />
-        <include name="IDR_LOGO_CROSTINI_DEFAULT_192" file="crostini/logo_crostini_default_192.png" type="BINDATA" />
+        <include name="IDR_LOGO_CROSTINI_TERMINAL" file="crostini/ic_terminal_256.png" type="BINDATA" />
+        <include name="IDR_LOGO_CROSTINI_DEFAULT" file="crostini/ic_linux_256.png" type="BINDATA" />
         <include name="IDR_CROSTINI_MASCOT" file="crostini/crostini_mascot_1x.svg" type="BINDATA" />
         <include name="IDR_LINUX_ILLUSTRATION" file="crostini/linux_illustration_2x.png" type="BINDATA" />
         <include name="IDR_LINUX_SUCCESS_ILLUSTRATION" file="crostini/linux_success_illustration.svg" type="BINDATA" />
diff --git a/chrome/app/theme/crostini/ic_linux_256.png b/chrome/app/theme/crostini/ic_linux_256.png
new file mode 100644
index 0000000..94a8a63
--- /dev/null
+++ b/chrome/app/theme/crostini/ic_linux_256.png
Binary files differ
diff --git a/chrome/app/theme/crostini/ic_terminal_256.png b/chrome/app/theme/crostini/ic_terminal_256.png
new file mode 100644
index 0000000..2c997e1
--- /dev/null
+++ b/chrome/app/theme/crostini/ic_terminal_256.png
Binary files differ
diff --git a/chrome/app/theme/crostini/logo_crostini_default_192.png b/chrome/app/theme/crostini/logo_crostini_default_192.png
deleted file mode 100644
index 6c78bef..0000000
--- a/chrome/app/theme/crostini/logo_crostini_default_192.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/crostini/logo_crostini_default_32.png b/chrome/app/theme/crostini/logo_crostini_default_32.png
deleted file mode 100644
index ba23d1d1a..0000000
--- a/chrome/app/theme/crostini/logo_crostini_default_32.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index d84b2af..c8ee214 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2961,8 +2961,6 @@
       "android/webapps/add_to_homescreen_mediator.h",
       "android/webapps/add_to_homescreen_params.cc",
       "android/webapps/add_to_homescreen_params.h",
-      "android/webapps/pwa_bottom_sheet_controller.cc",
-      "android/webapps/pwa_bottom_sheet_controller.h",
       "android/webapps/webapp_registry.cc",
       "android/webapps/webapp_registry.h",
       "android/webauth/fido2helper_native_android.cc",
@@ -3284,6 +3282,8 @@
       "//chrome/browser/updates:factory",
       "//chrome/browser/video_tutorials/internal",
       "//chrome/browser/video_tutorials/internal:jni_headers",
+      "//chrome/browser/webapps/android:android",
+      "//chrome/browser/webapps/android:jni_headers",
       "//chrome/common:non_code_constants",
       "//chrome/services/media_gallery_util/public/cpp",
       "//components/assist_ranker/proto",
@@ -3369,7 +3369,14 @@
       "//url:gurl_android",
       "//url:origin_android",
     ]
-    allow_circular_includes_from += [ "//chrome/browser/share" ]
+    allow_circular_includes_from += [
+      # chrome/browser depends on webapps, but that module needs
+      # app_banner_manager_android.h from chrome. However, the .h file will soon
+      # be moved to a component (when WebLayer starts relying on it). Allow the
+      # circular dependency until then.
+      "//chrome/browser/webapps/android:android",
+      "//chrome/browser/share",
+    ]
 
     deps += [ "//chrome/browser/engagement/android:jni_headers" ]
     deps -= [ "//components/storage_monitor" ]
diff --git a/chrome/browser/apps/app_service/app_icon_factory.cc b/chrome/browser/apps/app_service/app_icon_factory.cc
index 13411b9..80a3bec 100644
--- a/chrome/browser/apps/app_service/app_icon_factory.cc
+++ b/chrome/browser/apps/app_service/app_icon_factory.cc
@@ -697,7 +697,7 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (icon_resource == IDR_LOGO_CROSTINI_DEFAULT_192 ||
+  if (icon_resource == IDR_LOGO_CROSTINI_DEFAULT ||
       icon_resource == IDR_APP_DEFAULT_ICON) {
     // For the Crostini penguin icon, clear the standard icon effects, and use
     // the raw icon.
diff --git a/chrome/browser/apps/app_service/app_icon_factory_unittest.cc b/chrome/browser/apps/app_service/app_icon_factory_unittest.cc
index 4989837..18fd147 100644
--- a/chrome/browser/apps/app_service/app_icon_factory_unittest.cc
+++ b/chrome/browser/apps/app_service/app_icon_factory_unittest.cc
@@ -210,8 +210,7 @@
                                apps::IconEffects icon_effects,
                                apps::mojom::IconValuePtr& output_icon) {
     bool is_placeholder_icon = false;
-    apps::LoadIconFromResource(icon_type, kSizeInDip,
-                               IDR_LOGO_CROSTINI_DEFAULT_192,
+    apps::LoadIconFromResource(icon_type, kSizeInDip, IDR_LOGO_CROSTINI_DEFAULT,
                                is_placeholder_icon, icon_effects,
                                base::BindOnce(
                                    [](apps::mojom::IconValuePtr* result,
@@ -227,7 +226,7 @@
   void GenerateCrostiniPenguinIcon(gfx::ImageSkia& output_image_skia) {
     output_image_skia =
         *(ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-            IDR_LOGO_CROSTINI_DEFAULT_192));
+            IDR_LOGO_CROSTINI_DEFAULT));
     output_image_skia = gfx::ImageSkiaOperations::CreateResizedImage(
         output_image_skia, skia::ImageOperations::RESIZE_BEST,
         gfx::Size(kSizeInDip, kSizeInDip));
@@ -238,7 +237,7 @@
   void GenerateCrostiniPenguinCompressedIcon(std::vector<uint8_t>& output) {
     base::StringPiece data =
         ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
-            IDR_LOGO_CROSTINI_DEFAULT_192);
+            IDR_LOGO_CROSTINI_DEFAULT);
     output = std::vector<uint8_t>(data.begin(), data.end());
   }
 #endif
diff --git a/chrome/browser/apps/app_service/arc_apps.cc b/chrome/browser/apps/app_service/arc_apps.cc
index a89dbdc..8456a8c8 100644
--- a/chrome/browser/apps/app_service/arc_apps.cc
+++ b/chrome/browser/apps/app_service/arc_apps.cc
@@ -229,6 +229,18 @@
   return extras;
 }
 
+const char* GetArcIntentAction(const std::string& action) {
+  if (action == apps_util::kIntentActionView) {
+    return arc::kIntentActionView;
+  } else if (action == apps_util::kIntentActionSend) {
+    return arc::kIntentActionSend;
+  } else if (action == apps_util::kIntentActionSendMultiple) {
+    return arc::kIntentActionSendMultiple;
+  } else {
+    return arc::kIntentActionView;
+  }
+}
+
 arc::mojom::IntentInfoPtr CreateArcIntent(apps::mojom::IntentPtr intent) {
   arc::mojom::IntentInfoPtr arc_intent;
   if (!intent->url.has_value() && !intent->share_text.has_value()) {
@@ -236,15 +248,7 @@
   }
   arc_intent = arc::mojom::IntentInfo::New();
   if (intent->action.has_value()) {
-    if (intent->action.value() == apps_util::kIntentActionView) {
-      arc_intent->action = arc::kIntentActionView;
-    } else if (intent->action.value() == apps_util::kIntentActionSend) {
-      arc_intent->action = arc::kIntentActionSend;
-    } else if (intent->action.value() == apps_util::kIntentActionSendMultiple) {
-      arc_intent->action = arc::kIntentActionSendMultiple;
-    } else {
-      arc_intent->action = arc::kIntentActionView;
-    }
+    arc_intent->action = GetArcIntentAction(intent->action.value());
   } else {
     arc_intent->action = arc::kIntentActionView;
   }
@@ -362,7 +366,6 @@
   std::vector<arc::IntentFilter::AuthorityEntry> authorities;
   std::vector<arc::IntentFilter::PatternMatcher> paths;
   std::vector<std::string> mime_types;
-  // TODO(crbug.com/853604): Add conversion for actions and mime types.
   for (auto& condition : intent_filter->conditions) {
     switch (condition->condition_type) {
       case apps::mojom::ConditionType::kScheme:
@@ -398,13 +401,19 @@
               condition_value->value, match_type));
         }
         break;
-      // TODO(crbug.com/1092784): Handle action and mime type.
       case apps::mojom::ConditionType::kAction:
+        for (auto& condition_value : condition->condition_values) {
+          actions.push_back(GetArcIntentAction(condition_value->value));
+        }
+        break;
       case apps::mojom::ConditionType::kMimeType:
-        NOTIMPLEMENTED();
+        for (auto& condition_value : condition->condition_values) {
+          mime_types.push_back(condition_value->value);
+        }
+        break;
     }
   }
-  // TODO(crbug.com/853604): Add support for other action and category types.
+  // TODO(crbug.com/853604): Add support for other category types.
   return arc::IntentFilter(package_name, std::move(actions),
                            std::move(authorities), std::move(paths),
                            std::move(schemes), std::move(mime_types));
diff --git a/chrome/browser/apps/app_service/crostini_apps.cc b/chrome/browser/apps/app_service/crostini_apps.cc
index cf417ec8..5b8a3bce 100644
--- a/chrome/browser/apps/app_service/crostini_apps.cc
+++ b/chrome/browser/apps/app_service/crostini_apps.cc
@@ -133,7 +133,7 @@
                             bool allow_placeholder_icon,
                             LoadIconCallback callback) {
   registry_->LoadIcon(app_id, std::move(icon_key), icon_type, size_hint_in_dip,
-                      allow_placeholder_icon, IDR_LOGO_CROSTINI_DEFAULT_192,
+                      allow_placeholder_icon, IDR_LOGO_CROSTINI_DEFAULT,
                       std::move(callback));
 }
 
diff --git a/chrome/browser/autofill/autofill_browsertest.cc b/chrome/browser/autofill/autofill_browsertest.cc
index b730d63..392fa8c8 100644
--- a/chrome/browser/autofill/autofill_browsertest.cc
+++ b/chrome/browser/autofill/autofill_browsertest.cc
@@ -647,7 +647,8 @@
 };
 
 // Test that autofill available state is correctly set on accessibility node.
-IN_PROC_BROWSER_TEST_F(AutofillAccessibilityTest, TestAutofillState) {
+// crbug.com/1162484
+IN_PROC_BROWSER_TEST_F(AutofillAccessibilityTest, DISABLED_TestAutofillState) {
   content::BrowserAccessibilityState::GetInstance()->EnableAccessibility();
 
   // Navigate to url.
diff --git a/chrome/browser/autofill/form_structure_browsertest.cc b/chrome/browser/autofill/form_structure_browsertest.cc
index 5debbc4..c5f8fae 100644
--- a/chrome/browser/autofill/form_structure_browsertest.cc
+++ b/chrome/browser/autofill/form_structure_browsertest.cc
@@ -177,7 +177,9 @@
        // TODO(crbug.com/1076175) Remove once launched.
        autofill::features::kAutofillUseNewSectioningMethod,
        // Remove once launched
-       autofill::features::kAutofillEnableAugmentedPhoneCountryCode},
+       autofill::features::kAutofillEnableAugmentedPhoneCountryCode,
+       // TODO(crbug.com/1157405) Remove once launched.
+       autofill::features::kAutofillEnableDependentLocalityParsing},
       // Disabled
       {autofill::features::kAutofillRestrictUnownedFieldsToFormlessCheckout});
 }
diff --git a/chrome/browser/banners/android/BUILD.gn b/chrome/browser/banners/android/BUILD.gn
index a1a93bf..f2c8bfd 100644
--- a/chrome/browser/banners/android/BUILD.gn
+++ b/chrome/browser/banners/android/BUILD.gn
@@ -65,6 +65,7 @@
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/tab:java",
     "//chrome/browser/ui/android/appmenu/test:test_support_java",
+    "//chrome/browser/webapps/android:java",
     "//chrome/test/android:chrome_java_test_support",
     "//components/browser_ui/android/bottomsheet:java",
     "//components/feature_engagement/public:public_java",
diff --git a/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java b/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
index d67a919..e420cf2 100644
--- a/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
+++ b/chrome/browser/banners/android/java/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
@@ -74,6 +74,7 @@
 import org.chromium.chrome.browser.tab.TabUtils;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuCoordinator;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuTestSupport;
+import org.chromium.chrome.browser.webapps.PwaInstallBottomSheetView;
 import org.chromium.chrome.browser.webapps.WebappDataStorage;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
@@ -757,10 +758,14 @@
 
         waitUntilBottomSheetStatus(mTabbedActivityTestRule, BottomSheetController.SheetState.HALF);
 
-        TextView appName = toolbar.findViewById(R.id.app_name);
-        TextView appOrigin = toolbar.findViewById(R.id.app_origin);
-        TextView description = content.findViewById(R.id.description);
-        TextView categories = content.findViewById(R.id.categories);
+        TextView appName =
+                toolbar.findViewById(PwaInstallBottomSheetView.getAppNameViewIdForTesting());
+        TextView appOrigin =
+                toolbar.findViewById(PwaInstallBottomSheetView.getAppOriginViewIdForTesting());
+        TextView description =
+                content.findViewById(PwaInstallBottomSheetView.getDescViewIdForTesting());
+        TextView categories =
+                content.findViewById(PwaInstallBottomSheetView.getCategoriesViewIdForTesting());
 
         Assert.assertEquals("PWA Bottom Sheet", appName.getText());
         Assert.assertTrue(appOrigin.getText().toString().startsWith("http://127.0.0.1:"));
diff --git a/chrome/browser/banners/app_banner_manager_android.cc b/chrome/browser/banners/app_banner_manager_android.cc
index 30bba40..4c0a6c8 100644
--- a/chrome/browser/banners/app_banner_manager_android.cc
+++ b/chrome/browser/banners/app_banner_manager_android.cc
@@ -20,13 +20,14 @@
 #include "chrome/browser/android/webapk/webapk_ukm_recorder.h"
 #include "chrome/browser/android/webapps/add_to_homescreen_coordinator.h"
 #include "chrome/browser/android/webapps/add_to_homescreen_params.h"
-#include "chrome/browser/android/webapps/pwa_bottom_sheet_controller.h"
 #include "chrome/browser/banners/android/jni_headers/AppBannerInProductHelpControllerProvider_jni.h"
 #include "chrome/browser/banners/android/jni_headers/AppBannerManager_jni.h"
 #include "chrome/browser/banners/app_banner_metrics.h"
 #include "chrome/browser/banners/app_banner_settings_helper.h"
 #include "chrome/browser/flags/android/chrome_feature_list.h"
 #include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/webapps/android/features.h"
+#include "chrome/browser/webapps/android/pwa_bottom_sheet_controller.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_features.h"
 #include "components/feature_engagement/public/feature_constants.h"
@@ -169,7 +170,8 @@
       AppBannerManager::ParamsToPerformInstallableWebAppCheck();
   params.prefer_maskable_icon =
       WebappsIconUtils::DoesAndroidSupportMaskableIcons();
-  if (base::FeatureList::IsEnabled(chrome::android::kPwaInstallUseBottomSheet))
+  if (base::FeatureList::IsEnabled(
+          webapps::features::kPwaInstallUseBottomSheet))
     params.fetch_screenshots = true;
 
   return params;
@@ -509,7 +511,8 @@
     return;
   }
 
-  if (!base::FeatureList::IsEnabled(features::kInstallableAmbientBadgeInfoBar))
+  if (!base::FeatureList::IsEnabled(
+          ::features::kInstallableAmbientBadgeInfoBar))
     return;
 
   // Do not show the ambient badge if it was recently dismissed.
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index a9b6429..2f8511e 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -704,10 +704,6 @@
 
 namespace {
 
-#if !defined(OS_ANDROID)
-constexpr base::TimeDelta kKeepaliveDuration = base::TimeDelta::FromSeconds(1);
-#endif
-
 #if defined(OS_WIN) && !defined(COMPONENT_BUILD) && !defined(ADDRESS_SANITIZER)
 // Enables pre-launch Code Integrity Guard (CIG) for Chrome renderers, when
 // running on Windows 10 1511 and above. See
@@ -1305,6 +1301,19 @@
   return metadata;
 }
 
+#if !defined(OS_ANDROID)
+base::TimeDelta GetKeepaliveTimerTimeout() {
+  constexpr base::TimeDelta kDefaultValue = base::TimeDelta::FromSeconds(1);
+
+  const int seconds = base::GetFieldTrialParamByFeatureAsInt(
+      features::kShutdownSupportForKeepalive, "timeout", -1);
+  if (seconds < 0 || seconds > 60) {
+    return kDefaultValue;
+  }
+  return base::TimeDelta::FromSeconds(seconds);
+}
+#endif
+
 ChromeContentBrowserClient::ChromeContentBrowserClient() {
 #if BUILDFLAG(ENABLE_PLUGINS)
   extra_parts_.push_back(new ChromeContentBrowserClientPluginsPart);
@@ -5931,13 +5940,22 @@
 void ChromeContentBrowserClient::OnKeepaliveRequestStarted() {
 #if !defined(OS_ANDROID)
   if (base::FeatureList::IsEnabled(features::kShutdownSupportForKeepalive)) {
+    // TODO(crbug.com/1161996): Remove this entry once the investigation is
+    // done.
+    VLOG(1) << "OnKeepaliveRequestStarted: " << num_keepalive_requests_
+            << " ==> " << num_keepalive_requests_ + 1;
     ++num_keepalive_requests_;
 
     DCHECK_GT(num_keepalive_requests_, 0u);
     last_keepalive_request_time_ = base::TimeTicks::Now();
     if (!keepalive_timer_.IsRunning()) {
+      const auto timeout = GetKeepaliveTimerTimeout();
+      // TODO(crbug.com/1161996): Remove this entry once the investigation is
+      // done.
+      VLOG(1) << "Starting a keepalive timer(" << timeout.InSecondsF()
+              << " seconds)";
       keepalive_timer_.Start(
-          FROM_HERE, kKeepaliveDuration,
+          FROM_HERE, timeout,
           base::BindOnce(
               &ChromeContentBrowserClient::OnKeepaliveTimerFired,
               weak_factory_.GetWeakPtr(),
@@ -5952,8 +5970,15 @@
 #if !defined(OS_ANDROID)
   if (base::FeatureList::IsEnabled(features::kShutdownSupportForKeepalive)) {
     DCHECK_GT(num_keepalive_requests_, 0u);
+    // TODO(crbug.com/1161996): Remove this entry once the investigation is
+    // done.
+    VLOG(1) << "OnKeepaliveRequestFinished: " << num_keepalive_requests_
+            << " ==> " << num_keepalive_requests_ - 1;
     --num_keepalive_requests_;
     if (num_keepalive_requests_ == 0) {
+      // TODO(crbug.com/1161996): Remove this entry once the investigation is
+      // done.
+      VLOG(1) << "Stopping the keepalive timer";
       keepalive_timer_.Stop();
       // This deletes the keep alive handle attached to the timer function and
       // unblock the shutdown sequence.
@@ -6009,10 +6034,15 @@
 void ChromeContentBrowserClient::OnKeepaliveTimerFired(
     std::unique_ptr<ScopedKeepAlive> keep_alive_handle) {
 #if !defined(OS_ANDROID)
+  // TODO(crbug.com/1161996): Remove this entry once the investigation is done.
+  VLOG(1) << "OnKeepaliveTimerFired";
   DCHECK(base::FeatureList::IsEnabled(features::kShutdownSupportForKeepalive));
   const auto now = base::TimeTicks::Now();
-  const auto then = last_keepalive_request_time_ + kKeepaliveDuration;
+  const auto then = last_keepalive_request_time_ + GetKeepaliveTimerTimeout();
   if (now < then) {
+    // TODO(crbug.com/1161996): Remove this entry once the investigation is
+    // done.
+    VLOG(1) << "Extending keepalive timer";
     keepalive_timer_.Start(
         FROM_HERE, then - now,
         base::BindOnce(&ChromeContentBrowserClient::OnKeepaliveTimerFired,
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index 1fd290e9..c9b9141 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -16,7 +16,6 @@
 #include "ash/public/cpp/accessibility_controller_enums.h"
 #include "ash/public/cpp/accessibility_focus_ring_controller.h"
 #include "ash/public/cpp/accessibility_focus_ring_info.h"
-#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
@@ -29,7 +28,6 @@
 #include "base/memory/singleton.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/path_service.h"
-#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -1691,17 +1689,25 @@
 }
 
 void AccessibilityManager::SetSwitchAccessKeysForTest(
-    const std::set<int>& action_keys,
-    const std::string& pref_name) {
-  DictionaryPrefUpdate pref_update(profile_->GetPrefs(), pref_name);
-  base::ListValue devices;
-  devices.Append(ash::kSwitchAccessInternalDevice);
-  devices.Append(ash::kSwitchAccessUsbDevice);
-  devices.Append(ash::kSwitchAccessBluetoothDevice);
-  for (int key : action_keys) {
-    const std::string& key_str = base::NumberToString(key);
-    pref_update->SetPath(key_str, devices.Clone());
-  }
+    const std::set<int>& select_keys,
+    const std::set<int>& next_keys,
+    const std::set<int>& previous_keys) {
+  ListPrefUpdate select_update(
+      profile_->GetPrefs(),
+      ash::prefs::kAccessibilitySwitchAccessSelectKeyCodes);
+  for (int key : select_keys)
+    select_update->AppendInteger(key);
+
+  ListPrefUpdate next_update(
+      profile_->GetPrefs(), ash::prefs::kAccessibilitySwitchAccessNextKeyCodes);
+  for (int key : next_keys)
+    next_update->AppendInteger(key);
+
+  ListPrefUpdate previous_update(
+      profile_->GetPrefs(),
+      ash::prefs::kAccessibilitySwitchAccessPreviousKeyCodes);
+  for (int key : previous_keys)
+    previous_update->AppendInteger(key);
 
   profile_->GetPrefs()->CommitPendingWrite();
 }
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.h b/chrome/browser/chromeos/accessibility/accessibility_manager.h
index 21b41fc5..8bc8f59e0 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.h
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.h
@@ -349,8 +349,9 @@
       base::RepeatingCallback<void()> observer);
   void SetCaretBoundsObserverForTest(
       base::RepeatingCallback<void(const gfx::Rect&)> observer);
-  void SetSwitchAccessKeysForTest(const std::set<int>& action_keys,
-                                  const std::string& pref_name);
+  void SetSwitchAccessKeysForTest(const std::set<int>& select_keys,
+                                  const std::set<int>& next_keys,
+                                  const std::set<int>& previous_keys);
 
   const std::set<std::string>& GetAccessibilityCommonEnabledFeaturesForTest() {
     return accessibility_common_enabled_features_;
diff --git a/chrome/browser/chromeos/accessibility/switch_access_browsertest.cc b/chrome/browser/chromeos/accessibility/switch_access_browsertest.cc
index f481a44..f435fa3 100644
--- a/chrome/browser/chromeos/accessibility/switch_access_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/switch_access_browsertest.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "ash/public/cpp/accessibility_controller.h"
-#include "ash/public/cpp/ash_pref_names.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/path_service.h"
@@ -39,15 +38,8 @@
                           const std::set<int>& previous_key_codes) {
     AccessibilityManager* manager = AccessibilityManager::Get();
     manager->SetSwitchAccessEnabled(true);
-    manager->SetSwitchAccessKeysForTest(
-        select_key_codes,
-        ash::prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes);
-    manager->SetSwitchAccessKeysForTest(
-        next_key_codes,
-        ash::prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes);
-    manager->SetSwitchAccessKeysForTest(
-        previous_key_codes,
-        ash::prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes);
+    manager->SetSwitchAccessKeysForTest(select_key_codes, next_key_codes,
+                                        previous_key_codes);
 
     EXPECT_TRUE(manager->IsSwitchAccessEnabled());
 
diff --git a/chrome/browser/chromeos/extensions/input_method_api.cc b/chrome/browser/chromeos/extensions/input_method_api.cc
index c6385d5..c92c0b7 100644
--- a/chrome/browser/chromeos/extensions/input_method_api.cc
+++ b/chrome/browser/chromeos/extensions/input_method_api.cc
@@ -184,7 +184,7 @@
     auto val = std::make_unique<base::DictionaryValue>();
     val->SetString("id", input_method.id());
     val->SetString("name", util->GetInputMethodLongName(input_method));
-    val->SetString("indicator", util->GetInputMethodShortName(input_method));
+    val->SetString("indicator", input_method.GetIndicator());
     output->Append(std::move(val));
   }
   return RespondNow(
diff --git a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
index 66868268..d0acf14 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
@@ -42,11 +42,11 @@
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, DeviceHandlerTest) {
-  RunTestURL("background/js/device_handler_unittest_gen.html");
+  RunTestURL("background/js/device_handler_unittest.m_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, DirectoryContentsTest) {
-  RunTestURL("foreground/js/directory_contents_unittest_gen.html");
+  RunTestURL("foreground/js/directory_contents_unittest.m_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, DirectoryTreeTest) {
@@ -71,11 +71,11 @@
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, FileListModel) {
-  RunTestURL("foreground/js/file_list_model_unittest_gen.html");
+  RunTestURL("foreground/js/file_list_model_unittest.m_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, FileListSelectionModelTest) {
-  RunTestURL("foreground/js/ui/file_list_selection_model_unittest_gen.html");
+  RunTestURL("foreground/js/ui/file_list_selection_model_unittest.m_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, FileManagerCommandsTest) {
@@ -218,7 +218,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, NavigationListModelTest) {
-  RunTestURL("foreground/js/navigation_list_model_unittest_gen.html");
+  RunTestURL("foreground/js/navigation_list_model_unittest.m_gen.html");
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ProvidersModel) {
@@ -254,5 +254,5 @@
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, VolumeManagerTest) {
-  RunTestURL("background/js/volume_manager_unittest_gen.html");
+  RunTestURL("background/js/volume_manager_unittest.m_gen.html");
 }
diff --git a/chrome/browser/chromeos/settings/stats_reporting_controller.cc b/chrome/browser/chromeos/settings/stats_reporting_controller.cc
index 399ced2..d3e6374e 100644
--- a/chrome/browser/chromeos/settings/stats_reporting_controller.cc
+++ b/chrome/browser/chromeos/settings/stats_reporting_controller.cc
@@ -85,9 +85,12 @@
 bool StatsReportingController::IsEnabled() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   bool value = false;
-  if (GetOwnershipStatus() == DeviceSettingsService::OWNERSHIP_NONE &&
+  if ((GetOwnershipStatus() == DeviceSettingsService::OWNERSHIP_NONE ||
+       GetOwnershipStatus() == DeviceSettingsService::OWNERSHIP_UNKNOWN ||
+       is_value_being_set_with_service_) &&
       GetPendingValue(&value)) {
-    // Return the pending value if it exists and we are sure there is no owner:
+    // Return the pending value if it exists and we are sure there is no owner
+    // or the value has not been stored correctly in signed store:
     return value;
   }
   // Otherwise, always return the value from the signed store.
@@ -116,6 +119,20 @@
   }
 }
 
+void StatsReportingController::OnSignedPolicyStored(bool success) {
+  if (!success)
+    return;
+  bool pending_value;
+  bool signed_value;
+  if (GetPendingValue(&pending_value) && GetSignedStoredValue(&signed_value) &&
+      pending_value == signed_value) {
+    is_value_being_set_with_service_ = false;
+    owner_settings_service_observation_.Reset();
+    ClearPendingValue();
+    NotifyObservers();
+  }
+}
+
 StatsReportingController::StatsReportingController(PrefService* local_state)
     : local_state_(local_state) {
   setting_subscription_ = CrosSettings::Get()->AddSettingsObserver(
@@ -126,6 +143,7 @@
 }
 
 StatsReportingController::~StatsReportingController() {
+  owner_settings_service_observation_.Reset();
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
@@ -162,9 +180,11 @@
     bool enabled) {
   VLOG(1) << "SetWithService(" << std::boolalpha << enabled << ")";
   if (service && service->IsOwner()) {
+    if (!owner_settings_service_observation_.IsObserving())
+      owner_settings_service_observation_.Observe(service);
+    is_value_being_set_with_service_ = true;
     service->SetBoolean(kStatsReportingPref, enabled);
-    ClearPendingValue();
-    NotifyObservers();
+    local_state_->SetBoolean(kPendingPref, enabled);
   } else {
     // Do nothing since we are not the owner.
     LOG(WARNING) << "Changing settings from non-owner, setting="
diff --git a/chrome/browser/chromeos/settings/stats_reporting_controller.h b/chrome/browser/chromeos/settings/stats_reporting_controller.h
index 91edeb27..05c018a 100644
--- a/chrome/browser/chromeos/settings/stats_reporting_controller.h
+++ b/chrome/browser/chromeos/settings/stats_reporting_controller.h
@@ -7,9 +7,11 @@
 
 #include "base/callback_list.h"
 #include "base/memory/weak_ptr.h"
+#include "base/scoped_observation.h"
 #include "base/sequence_checker.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
+#include "components/ownership/owner_settings_service.h"
 
 class PrefRegistrySimple;
 class PrefService;
@@ -39,7 +41,8 @@
 // IsEnabled will return the pending value until ownership is taken and the
 // pending value is written - from then on it will return the signed, stored
 // value from CrosSettings.
-class StatsReportingController {
+class StatsReportingController
+    : public ownership::OwnerSettingsService::Observer {
  public:
   // Manage singleton instance.
   static void Initialize(PrefService* local_state);
@@ -68,11 +71,14 @@
   // ownership.
   void OnOwnershipTaken(ownership::OwnerSettingsService* service);
 
+  // ownership::OwnerSettingsService::Observer implementation:
+  void OnSignedPolicyStored(bool success) override;
+
  private:
   friend class StatsReportingControllerTest;
 
   explicit StatsReportingController(PrefService* local_state);
-  ~StatsReportingController();
+  ~StatsReportingController() override;
 
   // Delegates immediately to SetWithService if |service| is ready, otherwise
   // runs SetWithService asynchronously once |service| is ready.
@@ -125,6 +131,17 @@
   base::CallbackList<void(void)> callback_list_;
   base::CallbackListSubscription setting_subscription_;
 
+  // Indicates if the setting value is in the process of being set with the
+  // service. There is a small period of time needed between start saving the
+  // value and before the value is stored correctly in the service. We should
+  // not use the setting value from the service if it is still in the process
+  // of being saved.
+  bool is_value_being_set_with_service_ = false;
+
+  base::ScopedObservation<ownership::OwnerSettingsService,
+                          ownership::OwnerSettingsService::Observer>
+      owner_settings_service_observation_{this};
+
   base::WeakPtrFactory<StatsReportingController> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(StatsReportingController);
diff --git a/chrome/browser/chromeos/settings/stats_reporting_controller_unittest.cc b/chrome/browser/chromeos/settings/stats_reporting_controller_unittest.cc
index 4a44c60..09173a8 100644
--- a/chrome/browser/chromeos/settings/stats_reporting_controller_unittest.cc
+++ b/chrome/browser/chromeos/settings/stats_reporting_controller_unittest.cc
@@ -122,10 +122,8 @@
 
   std::unique_ptr<TestingProfile> user = CreateUser(no_keys);
   StatsReportingController::Get()->SetEnabled(user.get(), true);
-  // A pending value is written in case there is no owner, in which case it will
-  // be written properly when ownership is taken - but we don't read the
-  // pending value, in case there actually is an owner already.
-  EXPECT_FALSE(StatsReportingController::Get()->IsEnabled());
+  // Read from the pending value when ownership is not taken.
+  EXPECT_TRUE(StatsReportingController::Get()->IsEnabled());
   ExpectThatPendingValueIs(true);
   ExpectThatSignedStoredValueIs(false);
 
@@ -180,11 +178,22 @@
   StatsReportingController::Get()->SetEnabled(owner.get(), true);
   EXPECT_TRUE(StatsReportingController::Get()->IsEnabled());
   EXPECT_TRUE(value_at_last_notification_);
+  ExpectThatPendingValueIs(true);
+
+  StatsReportingController::Get()->OnSignedPolicyStored(true);
+  EXPECT_TRUE(StatsReportingController::Get()->IsEnabled());
+  EXPECT_TRUE(value_at_last_notification_);
   ExpectThatPendingValueIsNotSet();
   ExpectThatSignedStoredValueIs(true);
 
   StatsReportingController::Get()->SetEnabled(owner.get(), false);
   EXPECT_FALSE(StatsReportingController::Get()->IsEnabled());
+  EXPECT_FALSE(value_at_last_notification_);
+  ExpectThatPendingValueIs(false);
+
+  StatsReportingController::Get()->OnSignedPolicyStored(true);
+  EXPECT_FALSE(StatsReportingController::Get()->IsEnabled());
+  EXPECT_FALSE(value_at_last_notification_);
   ExpectThatPendingValueIsNotSet();
   ExpectThatSignedStoredValueIs(false);
 }
@@ -221,8 +230,8 @@
   // Before device is owned, setting the value means writing a pending value:
   std::unique_ptr<TestingProfile> pre_ownership_user = CreateUser(no_keys);
   StatsReportingController::Get()->SetEnabled(pre_ownership_user.get(), true);
-  EXPECT_FALSE(StatsReportingController::Get()->IsEnabled());
-  EXPECT_FALSE(value_at_last_notification_);
+  EXPECT_TRUE(StatsReportingController::Get()->IsEnabled());
+  EXPECT_TRUE(value_at_last_notification_);
   ExpectThatPendingValueIs(true);
   ExpectThatSignedStoredValueIs(false);
 
@@ -237,6 +246,11 @@
       OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(owner.get()));
   EXPECT_TRUE(StatsReportingController::Get()->IsEnabled());
   EXPECT_TRUE(value_at_last_notification_);
+  ExpectThatPendingValueIs(true);
+
+  StatsReportingController::Get()->OnSignedPolicyStored(true);
+  EXPECT_TRUE(StatsReportingController::Get()->IsEnabled());
+  EXPECT_TRUE(value_at_last_notification_);
   ExpectThatPendingValueIsNotSet();
   ExpectThatSignedStoredValueIs(true);
 }
diff --git a/chrome/browser/chromeos/web_applications/terminal_system_web_app_info.cc b/chrome/browser/chromeos/web_applications/terminal_system_web_app_info.cc
index e19d4eb..aeeee85 100644
--- a/chrome/browser/chromeos/web_applications/terminal_system_web_app_info.cc
+++ b/chrome/browser/chromeos/web_applications/terminal_system_web_app_info.cc
@@ -26,7 +26,7 @@
     info->scope = GURL(chrome::kChromeUIUntrustedTerminalURL);
   info->title = l10n_util::GetStringUTF16(IDS_CROSTINI_TERMINAL_APP_NAME);
   web_app::CreateIconInfoForSystemWebApp(
-      info->start_url, {{"app_icon_192.png", 192, IDR_LOGO_CROSTINI_TERMINAL}},
+      info->start_url, {{"app_icon_256.png", 256, IDR_LOGO_CROSTINI_TERMINAL}},
       *info);
   info->background_color = 0xFF202124;
   info->display_mode = blink::mojom::DisplayMode::kStandalone;
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index ae163fa..6598c55 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -887,6 +887,10 @@
   if (!browser_)
     CreateDevToolsBrowser();
 
+  // Ignore action if browser does not exist and could not be created.
+  if (!browser_)
+    return;
+
   RegisterModalDialogManager(browser_);
 
   if (should_show_window) {
@@ -1607,6 +1611,10 @@
     wp_prefs->SetKey(kDevToolsApp, std::move(dev_tools_defaults));
   }
 
+  if (Browser::GetBrowserCreationStatusForProfile(profile_) !=
+      Browser::BrowserCreationStatus::kOk) {
+    return;
+  }
   browser_ =
       Browser::Create(Browser::CreateParams::CreateForDevTools(profile_));
   browser_->tab_strip_model()->AddWebContents(
diff --git a/chrome/browser/devtools/devtools_window.h b/chrome/browser/devtools/devtools_window.h
index 8660dc5..688ff3a 100644
--- a/chrome/browser/devtools/devtools_window.h
+++ b/chrome/browser/devtools/devtools_window.h
@@ -397,8 +397,8 @@
 
   void ColorPickedInEyeDropper(int r, int g, int b, int a);
 
-  // This method create a new Browser object, and passes ownership of
-  // owned_main_web_contents_ to the tab strip of the Browser.
+  // This method creates a new Browser object (if possible), and passes
+  // ownership of owned_main_web_contents_ to the tab strip of the Browser.
   void CreateDevToolsBrowser();
   BrowserWindow* GetInspectedBrowserWindow();
   void ScheduleShow(const DevToolsToggleAction& action);
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc
index 487b377..854062c 100644
--- a/chrome/browser/extensions/api/identity/identity_apitest.cc
+++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -612,9 +612,11 @@
   }
 
  protected:
-  // Returns the account ID of the created account.
+  // Signs in (at sync consent level) and returns the account ID of the primary
+  // account.
   CoreAccountId SignIn(const std::string& email) {
     auto account_info = identity_test_env()->MakePrimaryAccountAvailable(email);
+    EXPECT_TRUE(identity_test_env()->identity_manager()->HasPrimaryAccount());
     return account_info.account_id;
   }
 
diff --git a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
index bf93a80..37b0b73 100644
--- a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
+++ b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
@@ -691,13 +691,20 @@
   return false;
 }
 
-void IdentityGetAuthTokenFunction::OnPrimaryAccountSet(
-    const CoreAccountInfo& primary_account_info) {
+void IdentityGetAuthTokenFunction::OnPrimaryAccountChanged(
+    const signin::PrimaryAccountChangeEvent& event_details) {
+  if (event_details.GetEventTypeFor(signin::ConsentLevel::kSync) !=
+      signin::PrimaryAccountChangeEvent::Type::kSet)
+    return;
+
   if (account_listening_mode_ != AccountListeningMode::kListeningPrimaryAccount)
     return;
 
-  TRACE_EVENT_NESTABLE_ASYNC_INSTANT0("identity", "OnPrimaryAccountSet", this);
+  TRACE_EVENT_NESTABLE_ASYNC_INSTANT0("identity",
+                                      "OnPrimaryAccountChanged (set)", this);
 
+  const CoreAccountInfo& primary_account_info =
+      event_details.GetCurrentState().primary_account;
   DCHECK(token_key_.account_info.IsEmpty());
   token_key_.account_info = primary_account_info;
 
diff --git a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.h b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.h
index 17be47f..ef9fe82 100644
--- a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.h
+++ b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.h
@@ -165,8 +165,8 @@
   void OnAccountsInCookieUpdated(
       const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
       const GoogleServiceAuthError& error) override;
-  void OnPrimaryAccountSet(
-      const CoreAccountInfo& primary_account_info) override;
+  void OnPrimaryAccountChanged(
+      const signin::PrimaryAccountChangeEvent& event_details) override;
 
   // Attempts to show the signin UI after the service auth error if this error
   // isn't transient.
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 23c5bbf..736a2ef 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -483,12 +483,12 @@
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
   (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessEnabled] =
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
-  (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes] =
-      settings_api::PrefType::PREF_TYPE_DICTIONARY;
-  (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes] =
-      settings_api::PrefType::PREF_TYPE_DICTIONARY;
-  (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes] =
-      settings_api::PrefType::PREF_TYPE_DICTIONARY;
+  (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessSelectKeyCodes] =
+      settings_api::PrefType::PREF_TYPE_LIST;
+  (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessNextKeyCodes] =
+      settings_api::PrefType::PREF_TYPE_LIST;
+  (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessPreviousKeyCodes] =
+      settings_api::PrefType::PREF_TYPE_LIST;
   (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessAutoScanEnabled] =
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
   (*s_allowlist)[ash::prefs::kAccessibilitySwitchAccessAutoScanSpeedMs] =
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index c435b005..70ca389 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/share/features.h"
 #include "chrome/browser/sharing/shared_clipboard/feature_flags.h"
 #include "chrome/browser/video_tutorials/switches.h"
+#include "chrome/browser/webapps/android/features.h"
 #include "chrome/common/chrome_features.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/autofill/core/common/autofill_payments_features.h"
@@ -198,7 +199,6 @@
     &kPhotoPickerVideoSupport,
     &kPhotoPickerZoom,
     &kProbabilisticCryptidRenderer,
-    &kPwaInstallUseBottomSheet,
     &kReachedCodeProfiler,
     &kReaderModeInCCT,
     &kReengagementNotification,
@@ -299,6 +299,7 @@
     &switches::kSyncUseSessionsUnregisterDelay,
     &subresource_filter::kSafeBrowsingSubresourceFilter,
     &video_tutorials::features::kVideoTutorials,
+    &webapps::features::kPwaInstallUseBottomSheet,
 };
 
 const base::Feature* FindFeatureExposedToJava(const std::string& feature_name) {
@@ -570,9 +571,6 @@
 const base::Feature kProbabilisticCryptidRenderer{
     "ProbabilisticCryptidRenderer", base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kPwaInstallUseBottomSheet{
-    "PwaInstallUseBottomSheet", base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kReachedCodeProfiler{"ReachedCodeProfiler",
                                          base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index 0ae9939..3d81f07 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -98,7 +98,6 @@
 extern const base::Feature kPhotoPickerVideoSupport;
 extern const base::Feature kPhotoPickerZoom;
 extern const base::Feature kProbabilisticCryptidRenderer;
-extern const base::Feature kPwaInstallUseBottomSheet;
 extern const base::Feature kReachedCodeProfiler;
 extern const base::Feature kReengagementNotification;
 extern const base::Feature kReaderModeInCCT;
diff --git a/chrome/browser/media/router/discovery/dial/dial_app_discovery_service.cc b/chrome/browser/media/router/discovery/dial/dial_app_discovery_service.cc
index 82d9954..75b5f38 100644
--- a/chrome/browser/media/router/discovery/dial/dial_app_discovery_service.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_app_discovery_service.cc
@@ -115,6 +115,8 @@
     int response_code,
     const std::string& error_message) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // FIXME: |response_code| uses internal codes from net/base/net_error_list.h
+  // instead of HTTP status codes, so |kNotFound| is never used.
   if (response_code == net::HTTP_NOT_FOUND ||
       response_code >= net::HTTP_INTERNAL_SERVER_ERROR ||
       response_code == net::HTTP_OK) {
diff --git a/chrome/browser/media/router/providers/dial/dial_internal_message_util.cc b/chrome/browser/media/router/providers/dial/dial_internal_message_util.cc
index 946a100..4f6668d 100644
--- a/chrome/browser/media/router/providers/dial/dial_internal_message_util.cc
+++ b/chrome/browser/media/router/providers/dial/dial_internal_message_util.cc
@@ -11,7 +11,6 @@
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/strings/string_number_conversions.h"
-#include "chrome/browser/media/router/providers/dial/dial_activity_manager.h"
 #include "components/media_router/browser/route_message_util.h"
 #include "components/media_router/common/discovery/media_sink_internal.h"
 #include "net/base/escape.h"
@@ -49,6 +48,8 @@
       return "custom_dial_launch";
     case DialInternalMessageType::kDialAppInfo:
       return "dial_app_info";
+    case DialInternalMessageType::kError:
+      return "error";
     case DialInternalMessageType::kOther:
       break;
   }
@@ -76,6 +77,9 @@
   if (str_type == "dial_app_info")
     return DialInternalMessageType::kDialAppInfo;
 
+  if (str_type == "error")
+    return DialInternalMessageType::kError;
+
   return DialInternalMessageType::kOther;
 }
 
@@ -90,6 +94,22 @@
   return "";
 }
 
+std::string DialAppInfoErrorToString(DialAppInfoResultCode error) {
+  switch (error) {
+    case DialAppInfoResultCode::kNotFound:
+      return "not_found";
+    case DialAppInfoResultCode::kNetworkError:
+      return "network_error";
+    case DialAppInfoResultCode::kParsingError:
+      return "parsing_error";
+    case DialAppInfoResultCode::kOk:
+    case DialAppInfoResultCode::kCount:
+      NOTREACHED() << "Unexpected DialAppInfoResultCode: "
+                   << static_cast<int>(error);
+      return "";
+  }
+}
+
 }  // namespace
 
 // static
@@ -203,69 +223,67 @@
 }
 
 mojom::RouteMessagePtr DialInternalMessageUtil::CreateNewSessionMessage(
-    const DialLaunchInfo& launch_info,
+    const std::string& app_name,
+    const std::string& client_id,
     const MediaSinkInternal& sink) const {
-  base::Value message = CreateDialMessageCommon(
-      DialInternalMessageType::kNewSession,
-      CreateNewSessionBody(launch_info, sink), launch_info.client_id);
-
-  std::string str;
-  CHECK(base::JSONWriter::Write(message, &str));
-  return message_util::RouteMessageFromString(std::move(str));
+  base::Value message =
+      CreateDialMessageCommon(DialInternalMessageType::kNewSession,
+                              CreateNewSessionBody(app_name, sink), client_id);
+  return message_util::RouteMessageFromValue(std::move(message));
 }
 
 mojom::RouteMessagePtr DialInternalMessageUtil::CreateReceiverActionCastMessage(
-    const DialLaunchInfo& launch_info,
+    const std::string& client_id,
     const MediaSinkInternal& sink) const {
   base::Value message = CreateDialMessageCommon(
       DialInternalMessageType::kReceiverAction,
-      CreateReceiverActionBody(sink, DialReceiverAction::kCast),
-      launch_info.client_id);
-
-  std::string str;
-  CHECK(base::JSONWriter::Write(message, &str));
-  return message_util::RouteMessageFromString(std::move(str));
+      CreateReceiverActionBody(sink, DialReceiverAction::kCast), client_id);
+  return message_util::RouteMessageFromValue(std::move(message));
 }
 
 mojom::RouteMessagePtr DialInternalMessageUtil::CreateReceiverActionStopMessage(
-    const DialLaunchInfo& launch_info,
+    const std::string& client_id,
     const MediaSinkInternal& sink) const {
   base::Value message = CreateDialMessageCommon(
       DialInternalMessageType::kReceiverAction,
-      CreateReceiverActionBody(sink, DialReceiverAction::kStop),
-      launch_info.client_id);
-
-  std::string str;
-  CHECK(base::JSONWriter::Write(message, &str));
-  return message_util::RouteMessageFromString(std::move(str));
+      CreateReceiverActionBody(sink, DialReceiverAction::kStop), client_id);
+  return message_util::RouteMessageFromValue(std::move(message));
 }
 
 std::pair<mojom::RouteMessagePtr, int>
 DialInternalMessageUtil::CreateCustomDialLaunchMessage(
-    const DialLaunchInfo& launch_info,
+    const std::string& client_id,
     const MediaSinkInternal& sink,
     const ParsedDialAppInfo& app_info) const {
   int seq_number = GetNextDialLaunchSequenceNumber();
   // A CUSTOM_DIAL_LAUNCH message is the same as A DIAL_APP_INFO response except
   // for the message type.
-  return {CreateDialAppInfoMessage(launch_info, sink, app_info, seq_number,
+  return {CreateDialAppInfoMessage(client_id, sink, app_info, seq_number,
                                    DialInternalMessageType::kCustomDialLaunch),
           seq_number};
 }
 
 mojom::RouteMessagePtr DialInternalMessageUtil::CreateDialAppInfoMessage(
-    const DialLaunchInfo& launch_info,
+    const std::string& client_id,
     const MediaSinkInternal& sink,
     const ParsedDialAppInfo& app_info,
     int sequence_number,
     DialInternalMessageType type) const {
   base::Value message = CreateDialMessageCommon(
-      type, CreateDialAppInfoBody(sink, app_info), launch_info.client_id);
-  message.SetKey("sequenceNumber", base::Value(sequence_number));
+      type, CreateDialAppInfoBody(sink, app_info), client_id, sequence_number);
+  return message_util::RouteMessageFromValue(std::move(message));
+}
 
-  std::string str;
-  CHECK(base::JSONWriter::Write(message, &str));
-  return message_util::RouteMessageFromString(std::move(str));
+mojom::RouteMessagePtr DialInternalMessageUtil::CreateDialAppInfoErrorMessage(
+    DialAppInfoResultCode result_code,
+    const std::string& client_id,
+    int sequence_number) const {
+  base::Value body(base::Value::Type::DICTIONARY);
+  body.SetKey("code", base::Value(DialAppInfoErrorToString(result_code)));
+  base::Value message =
+      CreateDialMessageCommon(DialInternalMessageType::kError, std::move(body),
+                              client_id, sequence_number);
+  return message_util::RouteMessageFromValue(std::move(message));
 }
 
 base::Value DialInternalMessageUtil::CreateReceiver(
@@ -301,12 +319,12 @@
 }
 
 base::Value DialInternalMessageUtil::CreateNewSessionBody(
-    const DialLaunchInfo& launch_info,
+    const std::string& app_name,
     const MediaSinkInternal& sink) const {
   base::Value message_body(base::Value::Type::DICTIONARY);
   message_body.SetKey("sessionId", base::Value(GetNextSessionId()));
   message_body.SetKey("appId", base::Value(""));
-  message_body.SetKey("displayName", base::Value(launch_info.app_name));
+  message_body.SetKey("displayName", base::Value(app_name));
   message_body.SetKey("statusText", base::Value(""));
   message_body.SetKey("appImages", base::ListValue());
   message_body.SetKey("receiver", CreateReceiver(sink));
@@ -337,12 +355,13 @@
 base::Value DialInternalMessageUtil::CreateDialMessageCommon(
     DialInternalMessageType type,
     base::Value body,
-    const std::string& client_id) const {
+    const std::string& client_id,
+    int sequence_number) const {
   base::Value message(base::Value::Type::DICTIONARY);
   message.SetKey("type", base::Value(DialInternalMessageTypeToString(type)));
   message.SetKey("message", std::move(body));
   message.SetKey("clientId", base::Value(client_id));
-  message.SetKey("sequenceNumber", base::Value(-1));
+  message.SetKey("sequenceNumber", base::Value(sequence_number));
   message.SetKey("timeoutMillis", base::Value(0));
   return message;
 }
diff --git a/chrome/browser/media/router/providers/dial/dial_internal_message_util.h b/chrome/browser/media/router/providers/dial/dial_internal_message_util.h
index 6d875e2..cf373460 100644
--- a/chrome/browser/media/router/providers/dial/dial_internal_message_util.h
+++ b/chrome/browser/media/router/providers/dial/dial_internal_message_util.h
@@ -10,12 +10,12 @@
 
 #include "base/macros.h"
 #include "base/values.h"
+#include "chrome/browser/media/router/discovery/dial/dial_app_discovery_service.h"
 #include "chrome/browser/media/router/discovery/dial/parsed_dial_app_info.h"
 #include "components/media_router/common/mojom/media_router.mojom.h"
 
 namespace media_router {
 
-struct DialLaunchInfo;
 class MediaSinkInternal;
 
 // Types of internal messages that are used in a custom DIAL launch workflow.
@@ -27,6 +27,7 @@
   // MR -> Cast SDK
   kNewSession,
   kReceiverAction,
+  kError,
 
   // MR <-> Cast SDK
   kCustomDialLaunch,
@@ -101,26 +102,27 @@
   // Returns a NEW_SESSION message to be sent to the page when the user requests
   // an app launch.
   mojom::RouteMessagePtr CreateNewSessionMessage(
-      const DialLaunchInfo& launch_info,
+      const std::string& app_name,
+      const std::string& client_id,
       const MediaSinkInternal& sink) const;
 
   // Returns a RECEIVER_ACTION / CAST message to be sent to the page when the
   // user requests an app launch.
   mojom::RouteMessagePtr CreateReceiverActionCastMessage(
-      const DialLaunchInfo& launch_info,
+      const std::string& client_id,
       const MediaSinkInternal& sink) const;
 
   // Returns a RECEIVER_ACTION / STOP message to be sent to the page when an app
   // is stopped by DialMediaRouteProvider.
   mojom::RouteMessagePtr CreateReceiverActionStopMessage(
-      const DialLaunchInfo& launch_info,
+      const std::string& client_id,
       const MediaSinkInternal& sink) const;
 
   // Returns a CUSTOM_DIAL_LAUNCH request message to be sent to the page.
   // Generates and returns the next number to associate a DIAL launch sequence
   // with.
   std::pair<mojom::RouteMessagePtr, int> CreateCustomDialLaunchMessage(
-      const DialLaunchInfo& launch_info,
+      const std::string& client_id,
       const MediaSinkInternal& sink,
       const ParsedDialAppInfo& app_info) const;
 
@@ -128,23 +130,34 @@
   // CUSTOM_DIAL_LAUNCH (called via CreateCustomDialLaunchMessage() above)
   // message.
   mojom::RouteMessagePtr CreateDialAppInfoMessage(
-      const DialLaunchInfo& launch_info,
+      const std::string& client_id,
       const MediaSinkInternal& sink,
       const ParsedDialAppInfo& app_info,
       int sequence_number,
       DialInternalMessageType type) const;
 
+  mojom::RouteMessagePtr CreateDialAppInfoErrorMessage(
+      DialAppInfoResultCode result_code,
+      const std::string& client_id,
+      int sequence_number) const;
+
  private:
   base::Value CreateReceiver(const MediaSinkInternal& sink) const;
   base::Value CreateReceiverActionBody(const MediaSinkInternal& sink,
                                        DialReceiverAction action) const;
-  base::Value CreateNewSessionBody(const DialLaunchInfo& launch_info,
+  base::Value CreateNewSessionBody(const std::string& app_name,
                                    const MediaSinkInternal& sink) const;
   base::Value CreateDialAppInfoBody(const MediaSinkInternal& sink,
                                     const ParsedDialAppInfo& app_info) const;
+
+  // |sequence_number| is used by the Cast SDK to match up requests from the SDK
+  // to Chrome with responses from Chrome. If a message from Chrome has no
+  // corresponding request, then its |sequence_number| is an invalid value of
+  // -1.
   base::Value CreateDialMessageCommon(DialInternalMessageType type,
                                       base::Value body,
-                                      const std::string& client_id) const;
+                                      const std::string& client_id,
+                                      int sequence_number = -1) const;
 
   std::string hash_token_;
   DISALLOW_COPY_AND_ASSIGN(DialInternalMessageUtil);
diff --git a/chrome/browser/media/router/providers/dial/dial_internal_message_util_unittest.cc b/chrome/browser/media/router/providers/dial/dial_internal_message_util_unittest.cc
index a395bc1c..c5dd93c 100644
--- a/chrome/browser/media/router/providers/dial/dial_internal_message_util_unittest.cc
+++ b/chrome/browser/media/router/providers/dial/dial_internal_message_util_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/json/json_reader.h"
 #include "base/strings/stringprintf.h"
+#include "chrome/browser/media/router/discovery/dial/dial_app_discovery_service.h"
 #include "chrome/browser/media/router/providers/dial/dial_activity_manager.h"
 #include "chrome/browser/media/router/test/provider_test_helpers.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -47,7 +48,7 @@
 };
 
 TEST_F(DialInternalMessageUtilTest, ParseClientConnectMessage) {
-  const char kClientConnectMessage[] = R"(
+  constexpr char kClientConnectMessage[] = R"(
         {
           "type":"client_connect",
           "message":"15212681945883010",
@@ -65,7 +66,7 @@
 }
 
 TEST_F(DialInternalMessageUtilTest, ParseCustomDialLaunchMessage) {
-  const char kCustomDialLaunchMessage[] = R"(
+  constexpr char kCustomDialLaunchMessage[] = R"(
   {
     "type":"custom_dial_launch",
     "message": {
@@ -90,7 +91,7 @@
 }
 
 TEST_F(DialInternalMessageUtilTest, ParseV2StopSessionMessage) {
-  const char kV2StopSessionMessage[] = R"(
+  constexpr char kV2StopSessionMessage[] = R"(
   {
     "type":"v2_message",
     "message": {
@@ -111,7 +112,7 @@
 }
 
 TEST_F(DialInternalMessageUtilTest, CreateReceiverActionCastMessage) {
-  const char kReceiverActionCastMessage[] = R"(
+  constexpr char kReceiverActionCastMessage[] = R"(
     {
       "clientId":"152127444812943594",
       "message": {
@@ -132,13 +133,14 @@
       "type":"receiver_action"
     })";
 
-  auto message = util_.CreateReceiverActionCastMessage(launch_info_, sink_);
+  auto message =
+      util_.CreateReceiverActionCastMessage(launch_info_.client_id, sink_);
   ASSERT_TRUE(message->message);
   ExpectMessagesEqual(kReceiverActionCastMessage, message->message.value());
 }
 
 TEST_F(DialInternalMessageUtilTest, CreateReceiverActionStopMessage) {
-  const char kReceiverActionStopMessage[] = R"(
+  constexpr char kReceiverActionStopMessage[] = R"(
     {
       "clientId":"152127444812943594",
       "message": {
@@ -159,13 +161,14 @@
       "type":"receiver_action"
     })";
 
-  auto message = util_.CreateReceiverActionStopMessage(launch_info_, sink_);
+  auto message =
+      util_.CreateReceiverActionStopMessage(launch_info_.client_id, sink_);
   ASSERT_TRUE(message->message);
   ExpectMessagesEqual(kReceiverActionStopMessage, message->message.value());
 }
 
 TEST_F(DialInternalMessageUtilTest, CreateNewSessionMessage) {
-  const char kNewSessionMessage[] = R"(
+  constexpr char kNewSessionMessage[] = R"(
   {
     "clientId":"152127444812943594",
     "message": {
@@ -195,13 +198,14 @@
     "type":"new_session"
   })";
 
-  auto message = util_.CreateNewSessionMessage(launch_info_, sink_);
+  auto message = util_.CreateNewSessionMessage(launch_info_.app_name,
+                                               launch_info_.client_id, sink_);
   ASSERT_TRUE(message->message);
   ExpectMessagesEqual(kNewSessionMessage, message->message.value());
 }
 
 TEST_F(DialInternalMessageUtilTest, CreateCustomDialLaunchMessage) {
-  const char kCustomDialLaunchMessage[] = R"(
+  constexpr char kCustomDialLaunchMessage[] = R"(
   {
     "clientId":"152127444812943594",
     "message": {
@@ -225,8 +229,8 @@
 
   ParsedDialAppInfo app_info =
       CreateParsedDialAppInfo("YouTube", DialAppState::kStopped);
-  auto message_and_seq_num =
-      util_.CreateCustomDialLaunchMessage(launch_info_, sink_, app_info);
+  auto message_and_seq_num = util_.CreateCustomDialLaunchMessage(
+      launch_info_.client_id, sink_, app_info);
   const auto& message = message_and_seq_num.first;
   int seq_num = message_and_seq_num.second;
   ASSERT_TRUE(message->message);
@@ -234,4 +238,25 @@
                       message->message.value());
 }
 
+TEST_F(DialInternalMessageUtilTest, CreateDialAppInfoErrorMessage) {
+  constexpr char kClientId[] = "152127444812943594";
+  constexpr char kErrorMessage[] = R"(
+  {
+    "clientId": "%s",
+    "type": "error",
+    "message": {
+      "code": "parsing_error"
+    },
+    "sequenceNumber": %d,
+    "timeoutMillis": 0
+  })";
+  const int kSequenceNumber = 42;
+
+  auto message = util_.CreateDialAppInfoErrorMessage(
+      DialAppInfoResultCode::kParsingError, kClientId, kSequenceNumber);
+  ExpectMessagesEqual(
+      base::StringPrintf(kErrorMessage, kClientId, kSequenceNumber),
+      message->message.value());
+}
+
 }  // namespace media_router
diff --git a/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc b/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc
index c212836..83ec50f 100644
--- a/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc
+++ b/chrome/browser/media/router/providers/dial/dial_media_route_provider.cc
@@ -147,10 +147,10 @@
   // the Cast SDK to complete the launch sequence. The first messages that the
   // MRP needs to send are the RECEIVER_ACTION and NEW_SESSION.
   std::vector<mojom::RouteMessagePtr> messages;
-  messages.emplace_back(internal_message_util_.CreateReceiverActionCastMessage(
-      activity->launch_info, *sink));
-  messages.emplace_back(internal_message_util_.CreateNewSessionMessage(
-      activity->launch_info, *sink));
+  messages.push_back(internal_message_util_.CreateReceiverActionCastMessage(
+      activity->launch_info.client_id, *sink));
+  messages.push_back(internal_message_util_.CreateNewSessionMessage(
+      activity->launch_info.app_name, activity->launch_info.client_id, *sink));
   message_sender_->SendMessages(route_id, std::move(messages));
 }
 
@@ -358,14 +358,14 @@
 
   auto message_and_seq_number =
       internal_message_util_.CreateCustomDialLaunchMessage(
-          activity->launch_info, *sink, *result.app_info);
+          activity->launch_info.client_id, *sink, *result.app_info);
   pending_dial_launches_.insert(message_and_seq_number.second);
   if (pending_dial_launches_.size() > kMaxPendingDialLaunches) {
     pending_dial_launches_.erase(pending_dial_launches_.begin());
   }
 
   std::vector<mojom::RouteMessagePtr> messages;
-  messages.emplace_back(std::move(message_and_seq_number.first));
+  messages.push_back(std::move(message_and_seq_number.first));
   message_sender_->SendMessages(route_id, std::move(messages));
 }
 
@@ -379,17 +379,22 @@
 
   auto* activity = activity_manager_->GetActivity(route_id);
   auto* sink = media_sink_service_->GetSinkById(sink_id);
-  // TODO(crbug.com/1153895): If |result.app_info| is null, we may want to send
-  // an error message to the sender client.
-  if (!result.app_info || !activity || !sink) {
+  // If the activity no longer exists, there is no need to inform the sender
+  // client of the activity status.
+  if (!activity || !sink) {
     return;
   }
-  mojom::RouteMessagePtr message =
-      internal_message_util_.CreateDialAppInfoMessage(
-          activity->launch_info, *sink, *result.app_info, sequence_number,
-          DialInternalMessageType::kDialAppInfo);
+  mojom::RouteMessagePtr message;
+  if (result.app_info) {
+    message = internal_message_util_.CreateDialAppInfoMessage(
+        activity->launch_info.client_id, *sink, *result.app_info,
+        sequence_number, DialInternalMessageType::kDialAppInfo);
+  } else {
+    message = internal_message_util_.CreateDialAppInfoErrorMessage(
+        result.result_code, activity->launch_info.client_id, sequence_number);
+  }
   std::vector<mojom::RouteMessagePtr> messages;
-  messages.emplace_back(std::move(message));
+  messages.push_back(std::move(message));
   message_sender_->SendMessages(route_id, std::move(messages));
 }
 
@@ -447,9 +452,8 @@
       can_stop_app = activity_manager_->CanStopApp(route_id);
   if (can_stop_app.second == RouteRequestResult::OK) {
     std::vector<mojom::RouteMessagePtr> messages;
-    messages.emplace_back(
-        internal_message_util_.CreateReceiverActionStopMessage(
-            activity.launch_info, sink));
+    messages.push_back(internal_message_util_.CreateReceiverActionStopMessage(
+        activity.launch_info.client_id, sink));
     message_sender_->SendMessages(route_id, std::move(messages));
     activity_manager_->StopApp(
         route_id,
diff --git a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc
index e5fcde8..8177688 100644
--- a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.cc
@@ -57,21 +57,6 @@
     "PageLoad.Clients.ServiceWorker2.PaintTiming."
     "NavigationToLargestContentfulPaint2";
 
-const char kHistogramServiceWorkerParseStartInbox[] =
-    "PageLoad.Clients.ServiceWorker2.ParseTiming.NavigationToParseStart.inbox";
-const char kHistogramServiceWorkerFirstContentfulPaintInbox[] =
-    "PageLoad.Clients.ServiceWorker2.PaintTiming."
-    "NavigationToFirstContentfulPaint.inbox";
-const char kHistogramServiceWorkerParseStartToFirstContentfulPaintInbox[] =
-    "PageLoad.Clients.ServiceWorker2.PaintTiming."
-    "ParseStartToFirstContentfulPaint.inbox";
-const char kHistogramServiceWorkerDomContentLoadedInbox[] =
-    "PageLoad.Clients.ServiceWorker2.DocumentTiming."
-    "NavigationToDOMContentLoadedEventFired.inbox";
-const char kHistogramServiceWorkerLoadInbox[] =
-    "PageLoad.Clients.ServiceWorker2.DocumentTiming.NavigationToLoadEventFired."
-    "inbox";
-
 const char kHistogramServiceWorkerParseStartSearch[] =
     "PageLoad.Clients.ServiceWorker2.ParseTiming.NavigationToParseStart.search";
 const char kHistogramServiceWorkerFirstContentfulPaintSearch[] =
@@ -111,10 +96,6 @@
 
 namespace {
 
-bool IsInboxSite(const GURL& url) {
-  return url.host_piece() == "inbox.google.com";
-}
-
 bool IsDocsSite(const GURL& url) {
   return url.host_piece() == "docs.google.com";
 }
@@ -202,16 +183,7 @@
     }
   }
 
-  if (IsInboxSite(GetDelegate().GetUrl())) {
-    PAGE_LOAD_HISTOGRAM(
-        internal::kHistogramServiceWorkerFirstContentfulPaintInbox,
-        timing.paint_timing->first_contentful_paint.value());
-    PAGE_LOAD_HISTOGRAM(
-        internal::kHistogramServiceWorkerParseStartToFirstContentfulPaintInbox,
-        timing.paint_timing->first_contentful_paint.value() -
-            timing.parse_timing->parse_start.value());
-  } else if (page_load_metrics::IsGoogleSearchResultUrl(
-                 GetDelegate().GetUrl())) {
+  if (page_load_metrics::IsGoogleSearchResultUrl(GetDelegate().GetUrl())) {
     PAGE_LOAD_HISTOGRAM(
         internal::kHistogramServiceWorkerFirstContentfulPaintSearch,
         timing.paint_timing->first_contentful_paint.value());
@@ -244,12 +216,7 @@
   PAGE_LOAD_HISTOGRAM(
       internal::kHistogramServiceWorkerDomContentLoaded,
       timing.document_timing->dom_content_loaded_event_start.value());
-  if (IsInboxSite(GetDelegate().GetUrl())) {
-    PAGE_LOAD_HISTOGRAM(
-        internal::kHistogramServiceWorkerDomContentLoadedInbox,
-        timing.document_timing->dom_content_loaded_event_start.value());
-  } else if (page_load_metrics::IsGoogleSearchResultUrl(
-                 GetDelegate().GetUrl())) {
+  if (page_load_metrics::IsGoogleSearchResultUrl(GetDelegate().GetUrl())) {
     PAGE_LOAD_HISTOGRAM(
         internal::kHistogramServiceWorkerDomContentLoadedSearch,
         timing.document_timing->dom_content_loaded_event_start.value());
@@ -270,11 +237,7 @@
   }
   PAGE_LOAD_HISTOGRAM(internal::kHistogramServiceWorkerLoad,
                       timing.document_timing->load_event_start.value());
-  if (IsInboxSite(GetDelegate().GetUrl())) {
-    PAGE_LOAD_HISTOGRAM(internal::kHistogramServiceWorkerLoadInbox,
-                        timing.document_timing->load_event_start.value());
-  } else if (page_load_metrics::IsGoogleSearchResultUrl(
-                 GetDelegate().GetUrl())) {
+  if (page_load_metrics::IsGoogleSearchResultUrl(GetDelegate().GetUrl())) {
     PAGE_LOAD_HISTOGRAM(internal::kHistogramServiceWorkerLoadSearch,
                         timing.document_timing->load_event_start.value());
   }
@@ -317,11 +280,7 @@
     PAGE_LOAD_HISTOGRAM(internal::kHistogramServiceWorkerParseStart,
                         timing.parse_timing->parse_start.value());
 
-    if (IsInboxSite(GetDelegate().GetUrl())) {
-      PAGE_LOAD_HISTOGRAM(internal::kHistogramServiceWorkerParseStartInbox,
-                          timing.parse_timing->parse_start.value());
-    } else if (page_load_metrics::IsGoogleSearchResultUrl(
-                   GetDelegate().GetUrl())) {
+    if (page_load_metrics::IsGoogleSearchResultUrl(GetDelegate().GetUrl())) {
       PAGE_LOAD_HISTOGRAM(internal::kHistogramServiceWorkerParseStartSearch,
                           timing.parse_timing->parse_start.value());
     }
diff --git a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h
index 3afb96c..2e009ef 100644
--- a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h
@@ -26,15 +26,7 @@
 extern const char kHistogramServiceWorkerDomContentLoaded[];
 extern const char kHistogramServiceWorkerLoad[];
 extern const char kHistogramServiceWorkerLargestContentfulPaint[];
-
-extern const char kHistogramServiceWorkerParseStartInbox[];
-extern const char kHistogramServiceWorkerFirstContentfulPaintInbox[];
 extern const char kHistogramServiceWorkerFirstInputDelay[];
-extern const char
-    kHistogramServiceWorkerParseStartToFirstContentfulPaintInbox[];
-extern const char kHistogramServiceWorkerDomContentLoadedInbox[];
-extern const char kHistogramServiceWorkerLoadInbox[];
-
 extern const char kHistogramServiceWorkerParseStartSearch[];
 extern const char kHistogramServiceWorkerFirstContentfulPaintSearch[];
 extern const char
diff --git a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer_unittest.cc
index 06df7aad..b63260f 100644
--- a/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer_unittest.cc
@@ -16,7 +16,6 @@
 namespace {
 
 const char kDefaultTestUrl[] = "https://google.com/";
-const char kInboxTestUrl[] = "https://inbox.google.com/test";
 const char kSearchTestUrl[] = "https://www.google.com/search?q=test";
 
 }  // namespace
@@ -67,20 +66,6 @@
         internal::kHistogramServiceWorkerLargestContentfulPaint, 0);
   }
 
-  void AssertNoInboxHistogramsLogged() {
-    tester()->histogram_tester().ExpectTotalCount(
-        internal::kHistogramServiceWorkerParseStartInbox, 0);
-    tester()->histogram_tester().ExpectTotalCount(
-        internal::kHistogramServiceWorkerFirstContentfulPaintInbox, 0);
-    tester()->histogram_tester().ExpectTotalCount(
-        internal::kHistogramServiceWorkerParseStartToFirstContentfulPaintInbox,
-        0);
-    tester()->histogram_tester().ExpectTotalCount(
-        internal::kHistogramServiceWorkerDomContentLoadedInbox, 0);
-    tester()->histogram_tester().ExpectTotalCount(
-        internal::kHistogramServiceWorkerLoadInbox, 0);
-  }
-
   void AssertNoSearchHistogramsLogged() {
     tester()->histogram_tester().ExpectTotalCount(
         internal::kHistogramServiceWorkerParseStartSearch, 0);
@@ -136,7 +121,6 @@
 
 TEST_F(ServiceWorkerPageLoadMetricsObserverTest, NoMetrics) {
   AssertNoServiceWorkerHistogramsLogged();
-  AssertNoInboxHistogramsLogged();
   AssertNoSearchHistogramsLogged();
   AssertNoSearchNoSWHistogramsLogged();
   EXPECT_EQ(0ul, tester()->test_ukm_recorder().entries_count());
@@ -150,7 +134,6 @@
   tester()->SimulateTimingUpdate(timing);
 
   AssertNoServiceWorkerHistogramsLogged();
-  AssertNoInboxHistogramsLogged();
   AssertNoSearchHistogramsLogged();
   AssertNoSearchNoSWHistogramsLogged();
   // Only a DocumentCreated entry and an Unload entry is logged for creation of
@@ -242,7 +225,6 @@
         entry, GURL(kDefaultTestUrl));
   }
 
-  AssertNoInboxHistogramsLogged();
   AssertNoSearchHistogramsLogged();
   AssertNoSearchNoSWHistogramsLogged();
 }
@@ -296,101 +278,6 @@
         entry, GURL(kDefaultTestUrl));
   }
 
-  AssertNoInboxHistogramsLogged();
-  AssertNoSearchHistogramsLogged();
-  AssertNoSearchNoSWHistogramsLogged();
-}
-
-TEST_F(ServiceWorkerPageLoadMetricsObserverTest, InboxSite) {
-  page_load_metrics::mojom::PageLoadTiming timing;
-  InitializeTestPageLoadTiming(&timing);
-
-  NavigateAndCommit(GURL(kInboxTestUrl));
-  page_load_metrics::mojom::FrameMetadata metadata;
-  metadata.behavior_flags |=
-      blink::LoadingBehaviorFlag::kLoadingBehaviorServiceWorkerControlled;
-  tester()->SimulateTimingAndMetadataUpdate(timing, metadata);
-
-  tester()->histogram_tester().ExpectTotalCount(
-      internal::kHistogramServiceWorkerParseStart, 1);
-  tester()->histogram_tester().ExpectBucketCount(
-      internal::kHistogramServiceWorkerParseStart,
-      timing.parse_timing->parse_start.value().InMilliseconds(), 1);
-  tester()->histogram_tester().ExpectTotalCount(
-      internal::kHistogramServiceWorkerParseStartInbox, 1);
-  tester()->histogram_tester().ExpectBucketCount(
-      internal::kHistogramServiceWorkerParseStartInbox,
-      timing.parse_timing->parse_start.value().InMilliseconds(), 1);
-
-  tester()->histogram_tester().ExpectTotalCount(
-      internal::kHistogramServiceWorkerFirstPaint, 1);
-  tester()->histogram_tester().ExpectBucketCount(
-      internal::kHistogramServiceWorkerFirstPaint,
-      timing.paint_timing->first_paint.value().InMilliseconds(), 1);
-
-  tester()->histogram_tester().ExpectTotalCount(
-      internal::kHistogramServiceWorkerFirstContentfulPaint, 1);
-  tester()->histogram_tester().ExpectBucketCount(
-      internal::kHistogramServiceWorkerFirstContentfulPaint,
-      timing.paint_timing->first_contentful_paint.value().InMilliseconds(), 1);
-  tester()->histogram_tester().ExpectTotalCount(
-      internal::kHistogramServiceWorkerFirstContentfulPaintInbox, 1);
-  tester()->histogram_tester().ExpectBucketCount(
-      internal::kHistogramServiceWorkerFirstContentfulPaintInbox,
-      timing.paint_timing->first_contentful_paint.value().InMilliseconds(), 1);
-
-  tester()->histogram_tester().ExpectTotalCount(
-      internal::kBackgroundHistogramServiceWorkerFirstContentfulPaint, 0);
-
-  tester()->histogram_tester().ExpectTotalCount(
-      internal::kHistogramServiceWorkerParseStartToFirstContentfulPaint, 1);
-  tester()->histogram_tester().ExpectBucketCount(
-      internal::kHistogramServiceWorkerParseStartToFirstContentfulPaint,
-      (timing.paint_timing->first_contentful_paint.value() -
-       timing.parse_timing->parse_start.value())
-          .InMilliseconds(),
-      1);
-  tester()->histogram_tester().ExpectTotalCount(
-      internal::kHistogramServiceWorkerParseStartToFirstContentfulPaintInbox,
-      1);
-  tester()->histogram_tester().ExpectBucketCount(
-      internal::kHistogramServiceWorkerParseStartToFirstContentfulPaintInbox,
-      (timing.paint_timing->first_contentful_paint.value() -
-       timing.parse_timing->parse_start.value())
-          .InMilliseconds(),
-      1);
-
-  tester()->histogram_tester().ExpectTotalCount(
-      internal::kHistogramServiceWorkerDomContentLoaded, 1);
-  tester()->histogram_tester().ExpectBucketCount(
-      internal::kHistogramServiceWorkerDomContentLoaded,
-      timing.document_timing->dom_content_loaded_event_start.value()
-          .InMilliseconds(),
-      1);
-  tester()->histogram_tester().ExpectTotalCount(
-      internal::kHistogramServiceWorkerDomContentLoadedInbox, 1);
-  tester()->histogram_tester().ExpectBucketCount(
-      internal::kHistogramServiceWorkerDomContentLoadedInbox,
-      timing.document_timing->dom_content_loaded_event_start.value()
-          .InMilliseconds(),
-      1);
-
-  tester()->histogram_tester().ExpectTotalCount(
-      internal::kHistogramServiceWorkerLoad, 1);
-  tester()->histogram_tester().ExpectBucketCount(
-      internal::kHistogramServiceWorkerLoad,
-      timing.document_timing->load_event_start.value().InMilliseconds(), 1);
-  tester()->histogram_tester().ExpectTotalCount(
-      internal::kHistogramServiceWorkerLoadInbox, 1);
-  tester()->histogram_tester().ExpectBucketCount(
-      internal::kHistogramServiceWorkerLoadInbox,
-      timing.document_timing->load_event_start.value().InMilliseconds(), 1);
-  tester()->histogram_tester().ExpectTotalCount(
-      internal::kHistogramServiceWorkerParseStart, 1);
-  tester()->histogram_tester().ExpectBucketCount(
-      internal::kHistogramServiceWorkerParseStart,
-      timing.parse_timing->parse_start.value().InMilliseconds(), 1);
-
   AssertNoSearchHistogramsLogged();
   AssertNoSearchNoSWHistogramsLogged();
 }
@@ -485,7 +372,6 @@
       internal::kHistogramServiceWorkerParseStart,
       timing.parse_timing->parse_start.value().InMilliseconds(), 1);
 
-  AssertNoInboxHistogramsLogged();
   AssertNoSearchNoSWHistogramsLogged();
 }
 
@@ -528,7 +414,6 @@
       timing.document_timing->load_event_start.value().InMilliseconds(), 1);
 
   AssertNoServiceWorkerHistogramsLogged();
-  AssertNoInboxHistogramsLogged();
   AssertNoSearchHistogramsLogged();
 }
 
diff --git a/chrome/browser/paint_preview/paint_preview_browsertest.cc b/chrome/browser/paint_preview/paint_preview_browsertest.cc
index c5ab507b..5fcdefb 100644
--- a/chrome/browser/paint_preview/paint_preview_browsertest.cc
+++ b/chrome/browser/paint_preview/paint_preview_browsertest.cc
@@ -24,17 +24,44 @@
 #include "components/paint_preview/common/test_utils.h"
 #include "components/ukm/test_ukm_recorder.h"
 #include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_process_host.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "third_party/skia/include/core/SkPicture.h"
 #include "third_party/skia/include/core/SkStream.h"
 #include "url/gurl.h"
 
 namespace paint_preview {
 
+class NoOpPaintPreviewRecorder : public mojom::PaintPreviewRecorder {
+ public:
+  NoOpPaintPreviewRecorder() = default;
+  ~NoOpPaintPreviewRecorder() override = default;
+
+  NoOpPaintPreviewRecorder(const NoOpPaintPreviewRecorder&) = delete;
+  NoOpPaintPreviewRecorder& operator=(const NoOpPaintPreviewRecorder&) = delete;
+
+  void CapturePaintPreview(
+      mojom::PaintPreviewCaptureParamsPtr params,
+      mojom::PaintPreviewRecorder::CapturePaintPreviewCallback callback)
+      override {
+    callback_ = std::move(callback);
+  }
+
+  void BindRequest(mojo::ScopedInterfaceEndpointHandle handle) {
+    binding_.Bind(mojo::PendingAssociatedReceiver<mojom::PaintPreviewRecorder>(
+        std::move(handle)));
+  }
+
+ private:
+  mojom::PaintPreviewRecorder::CapturePaintPreviewCallback callback_;
+  mojo::AssociatedReceiver<mojom::PaintPreviewRecorder> binding_{this};
+};
+
 // Test harness for a integration test of paint previews. In this test:
 // - Each RenderFrame has an instance of PaintPreviewRecorder attached.
 // - Each WebContents has an instance of PaintPreviewClient attached.
@@ -42,6 +69,10 @@
 class PaintPreviewBrowserTest
     : public InProcessBrowserTest,
       public testing::WithParamInterface<RecordingPersistence> {
+ public:
+  PaintPreviewBrowserTest(const PaintPreviewBrowserTest&) = delete;
+  PaintPreviewBrowserTest& operator=(const PaintPreviewBrowserTest&) = delete;
+
  protected:
   PaintPreviewBrowserTest() = default;
   ~PaintPreviewBrowserTest() override = default;
@@ -92,6 +123,15 @@
     return params;
   }
 
+  void OverrideInterface(NoOpPaintPreviewRecorder* service) {
+    blink::AssociatedInterfaceProvider* remote_interfaces =
+        GetWebContents()->GetMainFrame()->GetRemoteAssociatedInterfaces();
+    remote_interfaces->OverrideBinderForTesting(
+        mojom::PaintPreviewRecorder::Name_,
+        base::BindRepeating(&NoOpPaintPreviewRecorder::BindRequest,
+                            base::Unretained(service)));
+  }
+
   void WaitForLoadStopWithoutSuccessCheck() {
     // In many cases, the load may have finished before we get here.  Only wait
     // if the tab still has a pending navigation.
@@ -134,10 +174,6 @@
   base::ScopedTempDir temp_dir_;
   net::EmbeddedTestServer http_server_;
   net::EmbeddedTestServer http_server_different_origin_;
-
- private:
-  PaintPreviewBrowserTest(const PaintPreviewBrowserTest&) = delete;
-  PaintPreviewBrowserTest& operator=(const PaintPreviewBrowserTest&) = delete;
 };
 
 IN_PROC_BROWSER_TEST_P(PaintPreviewBrowserTest, CaptureFrame) {
@@ -324,6 +360,72 @@
   loop.Run();
 }
 
+// https://crbug.com/1146573 reproduction. If a renderer crashes,
+// WebContentsObserver::RenderFrameDeleted. Paint preview implements this in an
+// observer which in turn calls DecrementCapturerCount which can cause the
+// WebContents to be reloaded on Android where we have auto-reload. This reload
+// occurs *during* crash handling, leaving the frame in an invalid state and
+// leading to a crash when it subsequently unloaded.
+// This is fixed by deferring it to a PostTask.
+// This also
+IN_PROC_BROWSER_TEST_P(PaintPreviewBrowserTest, DontReloadInRenderProcessExit) {
+  LoadPage(http_server_.GetURL("a.com", "/title1.html"));
+
+  content::WebContents* web_contents = GetWebContents();
+
+  // Override remote interfaces with a no-op.
+  NoOpPaintPreviewRecorder noop_recorder;
+  OverrideInterface(&noop_recorder);
+
+  CreateClient();
+  auto* client = PaintPreviewClient::FromWebContents(web_contents);
+  // Do this twice to simulate conditions for crash.
+  web_contents->IncrementCapturerCount(gfx::Size(), true);
+  web_contents->IncrementCapturerCount(gfx::Size(), true);
+
+  // A callback that causes the frame to reload and end up in an invalid state
+  // if it is allowed to run during crash handling.
+  base::RunLoop loop;
+  auto params = MakeParams();
+  bool did_run = false;
+  client->CapturePaintPreview(
+      params, web_contents->GetMainFrame(),
+      // This callback is now posted so it shouldn't cause a crash.
+      base::BindOnce(
+          [](content::WebContents* web_contents, bool* did_run_ptr,
+             base::UnguessableToken guid, mojom::PaintPreviewStatus status,
+             std::unique_ptr<CaptureResult> result) {
+            EXPECT_EQ(status, mojom::PaintPreviewStatus::kFailed);
+            EXPECT_EQ(result, nullptr);
+            // On Android crashed frames are marked as needing reload.
+            web_contents->GetController().SetNeedsReload();
+            web_contents->DecrementCapturerCount(true);
+            web_contents->DecrementCapturerCount(true);
+            *did_run_ptr = true;
+          },
+          web_contents, &did_run)
+          .Then(loop.QuitClosure()));
+
+  // Crash the renderer.
+  {
+    base::ScopedAllowBlockingForTesting scope;
+    content::RenderProcessHost* process =
+        GetWebContents()->GetMainFrame()->GetProcess();
+    content::RenderProcessHostWatcher crash_observer(
+        process, content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+    process->Shutdown(0);
+    crash_observer.Wait();
+  }
+
+  // The browser would have crashed before the loop exited if the callback was
+  // not posted.
+  if (!did_run)
+    loop.Run();
+
+  // Now navigate away and ensure that the frame unloads successfully.
+  LoadPage(http_server_.GetURL("a.com", "/title2.html"));
+}
+
 INSTANTIATE_TEST_SUITE_P(All,
                          PaintPreviewBrowserTest,
                          testing::Values(RecordingPersistence::kFileSystem,
diff --git a/chrome/browser/prefs/pref_service_incognito_allowlist.cc b/chrome/browser/prefs/pref_service_incognito_allowlist.cc
index 449610c2..9369459 100644
--- a/chrome/browser/prefs/pref_service_incognito_allowlist.cc
+++ b/chrome/browser/prefs/pref_service_incognito_allowlist.cc
@@ -57,9 +57,9 @@
     ash::prefs::kAccessibilityFocusHighlightEnabled,
     ash::prefs::kAccessibilitySelectToSpeakEnabled,
     ash::prefs::kAccessibilitySwitchAccessEnabled,
-    ash::prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes,
-    ash::prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes,
-    ash::prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes,
+    ash::prefs::kAccessibilitySwitchAccessSelectKeyCodes,
+    ash::prefs::kAccessibilitySwitchAccessNextKeyCodes,
+    ash::prefs::kAccessibilitySwitchAccessPreviousKeyCodes,
     ash::prefs::kAccessibilitySwitchAccessAutoScanEnabled,
     ash::prefs::kAccessibilitySwitchAccessAutoScanSpeedMs,
     ash::prefs::kAccessibilitySwitchAccessAutoScanKeyboardSpeedMs,
diff --git a/chrome/browser/resources/PRESUBMIT.py b/chrome/browser/resources/PRESUBMIT.py
index 5579276..73400e7 100644
--- a/chrome/browser/resources/PRESUBMIT.py
+++ b/chrome/browser/resources/PRESUBMIT.py
@@ -93,13 +93,6 @@
       input_api, output_api, 80, lambda x: x.LocalPath().endswith('.html'))
 
 
-def RunOptimizeWebUiTests(input_api, output_api):
-  presubmit_path = input_api.PresubmitLocalPath()
-  sources = ['optimize_webui_test.py']
-  tests = [input_api.os_path.join(presubmit_path, s) for s in sources]
-  return input_api.canned_checks.RunUnitTests(input_api, output_api, tests)
-
-
 def _CheckSvgsOptimized(input_api, output_api):
   results = []
   try:
@@ -135,11 +128,6 @@
   affected = input_api.AffectedFiles()
   if any(f for f in affected if f.LocalPath().endswith('.html')):
     results += CheckHtml(input_api, output_api)
-
-  webui_sources = set(['optimize_webui.py'])
-  affected_files = [input_api.os_path.basename(f.LocalPath()) for f in affected]
-  if webui_sources.intersection(set(affected_files)):
-    results += RunOptimizeWebUiTests(input_api, output_api)
   results += _CheckSvgsOptimized(input_api, output_api)
   results += _CheckWebDevStyle(input_api, output_api)
   results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api,
diff --git a/chrome/browser/resources/bookmarks/BUILD.gn b/chrome/browser/resources/bookmarks/BUILD.gn
index 156b3b0..410aab7 100644
--- a/chrome/browser/resources/bookmarks/BUILD.gn
+++ b/chrome/browser/resources/bookmarks/BUILD.gn
@@ -8,7 +8,7 @@
 import("//tools/grit/preprocess_if_expr.gni")
 import("//tools/polymer/html_to_js.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
-import("../optimize_webui.gni")
+import("../tools/optimize_webui.gni")
 
 preprocess_folder = "preprocessed"
 preprocess_manifest = "preprocessed_manifest.json"
diff --git a/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/BUILD.gn b/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/BUILD.gn
index e02e040..fca8703 100644
--- a/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/BUILD.gn
+++ b/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/BUILD.gn
@@ -7,7 +7,7 @@
 import("//tools/grit/preprocess_if_expr.gni")
 import("//tools/polymer/html_to_js.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
-import("../../optimize_webui.gni")
+import("../../tools/optimize_webui.gni")
 
 preprocess_folder = "preprocessed"
 preprocess_gen_manifest = "preprocessed_gen_manifest.json"
diff --git a/chrome/browser/resources/chromeos/internet_config_dialog/BUILD.gn b/chrome/browser/resources/chromeos/internet_config_dialog/BUILD.gn
index 3d01b49c..2edf27a 100644
--- a/chrome/browser/resources/chromeos/internet_config_dialog/BUILD.gn
+++ b/chrome/browser/resources/chromeos/internet_config_dialog/BUILD.gn
@@ -3,7 +3,7 @@
 # found in the LICENSE file.
 
 import("//third_party/closure_compiler/compile_js.gni")
-import("../../optimize_webui.gni")
+import("../../tools/optimize_webui.gni")
 
 optimize_webui("build") {
   host = "internet_config_dialog"
diff --git a/chrome/browser/resources/chromeos/internet_detail_dialog/BUILD.gn b/chrome/browser/resources/chromeos/internet_detail_dialog/BUILD.gn
index 1f92f2e5..a3f86ef 100644
--- a/chrome/browser/resources/chromeos/internet_detail_dialog/BUILD.gn
+++ b/chrome/browser/resources/chromeos/internet_detail_dialog/BUILD.gn
@@ -3,7 +3,7 @@
 # found in the LICENSE file.
 
 import("//third_party/closure_compiler/compile_js.gni")
-import("../../optimize_webui.gni")
+import("../../tools/optimize_webui.gni")
 
 optimize_webui("build") {
   host = "internet_detail_dialog"
diff --git a/chrome/browser/resources/chromeos/machine_learning/BUILD.gn b/chrome/browser/resources/chromeos/machine_learning/BUILD.gn
index a4f22168..71ce20d 100644
--- a/chrome/browser/resources/chromeos/machine_learning/BUILD.gn
+++ b/chrome/browser/resources/chromeos/machine_learning/BUILD.gn
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 
 import("//third_party/closure_compiler/compile_js.gni")
-import("../../optimize_webui.gni")
 
 js_type_check("closure_compile") {
   deps = [
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css b/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css
index 9eba633..65124df 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css
@@ -43,12 +43,22 @@
   -webkit-box-align: center;
   display: block;
   height: 100%;
-  overflow: visible;
+  overflow-x: visible;
+  overflow-y: auto;
   padding: unset;
   position: relative;
   width: 192px;
 }
 
+.dialog-topbar::-webkit-scrollbar-thumb {
+  background: #888;
+  display: none;
+}
+
+.dialog-topbar.show-scroll-bar::-webkit-scrollbar-thumb {
+  display: block;
+}
+
 .dialog-topbar .spacer {
   -webkit-box-flex: 1;
 }
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js
index cc972ed0c..7cd9d69 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js
@@ -406,6 +406,18 @@
       }, 500);
     };
   }());
+
+  var dialogTopbar = this.document_.body.querySelector('.dialog-topbar');
+  dialogTopbar.addEventListener('scroll', function() {
+    var scrollTimer;
+    return () => {
+      dialogTopbar.classList.add('show-scroll-bar');
+      window.clearTimeout(scrollTimer);
+      scrollTimer = window.setTimeout(() => {
+        dialogTopbar.classList.remove('show-scroll-bar');
+      }, 500);
+    };
+  }());
 };
 
 /**
diff --git a/chrome/browser/resources/downloads/BUILD.gn b/chrome/browser/resources/downloads/BUILD.gn
index 85ccbfd..57a79a7 100644
--- a/chrome/browser/resources/downloads/BUILD.gn
+++ b/chrome/browser/resources/downloads/BUILD.gn
@@ -8,7 +8,7 @@
 import("//tools/grit/preprocess_if_expr.gni")
 import("//tools/polymer/html_to_js.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
-import("../optimize_webui.gni")
+import("../tools/optimize_webui.gni")
 
 preprocess_folder = "preprocessed"
 preprocess_manifest = "preprocessed_manifest.json"
diff --git a/chrome/browser/resources/extensions/BUILD.gn b/chrome/browser/resources/extensions/BUILD.gn
index ab35681b..db0b18a 100644
--- a/chrome/browser/resources/extensions/BUILD.gn
+++ b/chrome/browser/resources/extensions/BUILD.gn
@@ -9,7 +9,7 @@
 import("//tools/grit/preprocess_if_expr.gni")
 import("//tools/polymer/html_to_js.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
-import("../optimize_webui.gni")
+import("../tools/optimize_webui.gni")
 
 preprocess_folder = "preprocessed"
 preprocess_manifest = "preprocessed_manifest.json"
diff --git a/chrome/browser/resources/history/BUILD.gn b/chrome/browser/resources/history/BUILD.gn
index 417efb4e..dad72c97 100644
--- a/chrome/browser/resources/history/BUILD.gn
+++ b/chrome/browser/resources/history/BUILD.gn
@@ -8,7 +8,7 @@
 import("//tools/grit/preprocess_if_expr.gni")
 import("//tools/polymer/html_to_js.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
-import("../optimize_webui.gni")
+import("../tools/optimize_webui.gni")
 
 preprocess_folder = "preprocessed"
 preprocess_manifest = "preprocessed_manifest.json"
diff --git a/chrome/browser/resources/invalidations/BUILD.gn b/chrome/browser/resources/invalidations/BUILD.gn
index 344836f..80646cc 100644
--- a/chrome/browser/resources/invalidations/BUILD.gn
+++ b/chrome/browser/resources/invalidations/BUILD.gn
@@ -4,12 +4,28 @@
 
 import("//chrome/common/features.gni")
 import("//tools/grit/grit_rule.gni")
+import("//ui/webui/resources/tools/generate_grd.gni")
+
+generate_grd("build_grd") {
+  grd_prefix = "invalidations"
+  out_grd = "$target_gen_dir/resources.grd"
+  input_files = [
+    "about_invalidations.css",
+    "about_invalidations.html",
+    "about_invalidations.js",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+}
 
 grit("invalidations_resources") {
-  source = "invalidations_resources.grd"
+  source = "$target_gen_dir/resources.grd"
+  deps = [ ":build_grd" ]
+  enable_input_discovery_for_gn_analyze = false
   defines = chrome_grit_defines
   outputs = [
     "grit/invalidations_resources.h",
+    "grit/invalidations_resources_map.h",
+    "grit/invalidations_resources_map.cc",
     "invalidations_resources.pak",
   ]
   output_dir = "$root_gen_dir/chrome"
diff --git a/chrome/browser/resources/invalidations/invalidations_resources.grd b/chrome/browser/resources/invalidations/invalidations_resources.grd
deleted file mode 100644
index 8fdd278a..0000000
--- a/chrome/browser/resources/invalidations/invalidations_resources.grd
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
-  <outputs>
-    <output filename="grit/invalidations_resources.h" type="rc_header">
-      <emit emit_type='prepend'></emit>
-    </output>
-    <output filename="invalidations_resources.pak" type="data_package" />
-  </outputs>
-  <release seq="1">
-    <includes>
-      <include name="IDR_ABOUT_INVALIDATIONS_HTML" file="about_invalidations.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
-      <include name="IDR_ABOUT_INVALIDATIONS_JS" file="about_invalidations.js" type="BINDATA" />
-      <include name="IDR_ABOUT_INVALIDATIONS_CSS" file="about_invalidations.css" type="BINDATA" />
-    </includes>
-  </release>
-</grit>
diff --git a/chrome/browser/resources/new_tab_page/BUILD.gn b/chrome/browser/resources/new_tab_page/BUILD.gn
index 4c678f5a..2c4a692 100644
--- a/chrome/browser/resources/new_tab_page/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/BUILD.gn
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//chrome/browser/resources/optimize_webui.gni")
+import("//chrome/browser/resources/tools/optimize_webui.gni")
 import("//chrome/common/features.gni")
 import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/grit/grit_rule.gni")
diff --git a/chrome/browser/resources/print_preview/BUILD.gn b/chrome/browser/resources/print_preview/BUILD.gn
index 9ea002d..04a0bbba 100644
--- a/chrome/browser/resources/print_preview/BUILD.gn
+++ b/chrome/browser/resources/print_preview/BUILD.gn
@@ -8,7 +8,7 @@
 import("//tools/grit/grit_rule.gni")
 import("//tools/grit/preprocess_if_expr.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
-import("../optimize_webui.gni")
+import("../tools/optimize_webui.gni")
 
 preprocess_folder = "preprocessed"
 preprocess_manifest = "preprocessed_manifest.json"
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index cad2c351..b7fb081 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -12,7 +12,7 @@
 import("//ui/webui/resources/tools/generate_grd.gni")
 import("//ui/webui/resources/tools/js_modulizer.gni")
 import("//ui/webui/webui_features.gni")
-import("../optimize_webui.gni")
+import("../tools/optimize_webui.gni")
 import("settings.gni")
 
 preprocess_folder = "preprocessed"
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn
index a097d99..4f98df8 100644
--- a/chrome/browser/resources/settings/chromeos/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -9,7 +9,7 @@
 import("//ui/webui/resources/tools/generate_grd.gni")
 import("//ui/webui/resources/tools/js_modulizer.gni")
 import("//ui/webui/webui_features.gni")
-import("../../optimize_webui.gni")
+import("../../tools/optimize_webui.gni")
 import("./os_settings.gni")
 
 preprocess_folder_v2 = "preprocess_v2"
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.html b/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.html
index c400a80c..63e28b9e 100644
--- a/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.html
+++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.html
@@ -91,7 +91,7 @@
                     class$="icon [[computeIcon_(assignment, assignmentState_)]]-icon"
                     aria-label="[[computeIconLabel_(assignment, assignmentState_)]]">
                 </iron-icon>
-                [[assignment.key]]
+                [[assignment]]
               </div>
             </template>
           </template>
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.js b/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.js
index ebabb01..14bc1514 100644
--- a/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.js
+++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_action_assignment_dialog.js
@@ -31,21 +31,9 @@
  * @private
  */
 /* #export */ const actionToPref = {
-  select: 'settings.a11y.switch_access.select.device_key_codes',
-  next: 'settings.a11y.switch_access.next.device_key_codes',
-  previous: 'settings.a11y.switch_access.previous.device_key_codes'
-};
-
-/**
- * Possible device types for Switch Access.
- * @enum {string}
- * @private
- */
-/* #export */ const SwitchAccessDeviceType = {
-  INTERNAL: 'internal',
-  USB: 'usb',
-  BLUETOOTH: 'bluetooth',
-  UNKNOWN: 'unknown'
+  select: 'settings.a11y.switch_access.select.key_codes',
+  next: 'settings.a11y.switch_access.next.key_codes',
+  previous: 'settings.a11y.switch_access.previous.key_codes'
 };
 
 /**
@@ -58,11 +46,6 @@
   REMOVE_ASSIGNMENT: 'remove-assignment',
 };
 
-/**
- * @typedef {!Array<!Object<string, !Array<!SwitchAccessDeviceType>>>}
- */
-let SwitchAccessKeyAssignmentInfoList;
-
 Polymer({
   is: 'settings-switch-access-action-assignment-dialog',
 
@@ -93,8 +76,7 @@
 
     /**
      * Assignments for the current action.
-     * @private {Array<!{key: string, devices:
-     *     !Array<!SwitchAccessDeviceType>}>}
+     * @private {Array<string>}
      */
     assignments_: {
       type: Array,
@@ -113,17 +95,12 @@
     /**
      * A dictionary containing all Switch Access key codes (mapped from
      * actions).
-     * Each key code is another object, mapping a stringified key code to a list
-     * of Switch Access device types for that key code.
-     * @private {{
-     *         select: SwitchAccessKeyAssignmentInfoList,
-     *         next: SwitchAccessKeyAssignmentInfoList,
-     *         previous: SwitchAccessKeyAssignmentInfoList
-     * }}
+     * @private {{select: !Array<string>, next: !Array<string>, previous:
+     *     !Array<string>}}
      */
     keyCodes_: {
       type: Object,
-      value: {select: {}, next: {}, previous: {}},
+      value: {select: [], next: [], previous: []},
     },
 
     /**
@@ -242,7 +219,7 @@
 
     // Check for pre-existing assignments in actions other than the current one.
     for (const action of Object.values(SwitchAccessCommand)) {
-      if (!this.keyCodes_[action][event.keyCode]) {
+      if (!this.keyCodes_[action].includes(event.keyCode)) {
         continue;
       }
 
@@ -274,12 +251,7 @@
   handleKeyEventInWaitForConfirmation_(event) {
     if (this.currentKeyCode_ === event.keyCode) {
       // Confirmed.
-      // TODO: resolve to specific device type once UI is hooked up;
-      // |event.device| has the Switch Access device type.
-      this.keyCodes_[this.action][this.currentKeyCode_] = [
-        SwitchAccessDeviceType.INTERNAL, SwitchAccessDeviceType.USB,
-        SwitchAccessDeviceType.BLUETOOTH
-      ];
+      this.keyCodes_[this.action].push(this.currentKeyCode_);
       this.$.switchAccessActionAssignmentDialog.close();
       return;
     }
@@ -304,8 +276,10 @@
     }
 
     // Remove this key code.
-    delete this.keyCodes_[this.action][this.currentKeyCode_];
-
+    const index = this.keyCodes_[this.action].indexOf(this.currentKeyCode_);
+    if (index !== -1) {
+      this.keyCodes_[this.action].splice(index, 1);
+    }
     this.$.switchAccessActionAssignmentDialog.close();
   },
 
@@ -315,12 +289,21 @@
   },
 
   /**
-   * @param {!Object<SwitchAccessCommand, !Array<!{key: string, devices:
-   *     !Array<SwitchAccessDeviceType>}>>} value
+   * @param {!Object<SwitchAccessCommand, !Array<string>>} value
    * @private
    */
   onAssignmentsChanged_(value) {
-    this.assignments_ = value[this.action];
+    switch (this.action) {
+      case SwitchAccessCommand.SELECT:
+        this.assignments_ = value.select;
+        break;
+      case SwitchAccessCommand.NEXT:
+        this.assignments_ = value.next;
+        break;
+      case SwitchAccessCommand.PREVIOUS:
+        this.assignments_ = value.previous;
+        break;
+    }
   },
 
   /**
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_subpage.js b/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_subpage.js
index 807aab2..cefc12d 100644
--- a/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_subpage.js
+++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/switch_access_subpage.js
@@ -206,11 +206,9 @@
    * @private
    */
   onAssignmentsChanged_(value) {
-    // TODO: include |v.devices| for each key in UI.
-    this.selectAssignments_ = value[SwitchAccessCommand.SELECT].map(v => v.key);
-    this.nextAssignments_ = value[SwitchAccessCommand.NEXT].map(v => v.key);
-    this.previousAssignments_ =
-        value[SwitchAccessCommand.PREVIOUS].map(v => v.key);
+    this.selectAssignments_ = value[SwitchAccessCommand.SELECT];
+    this.nextAssignments_ = value[SwitchAccessCommand.NEXT];
+    this.previousAssignments_ = value[SwitchAccessCommand.PREVIOUS];
   },
 
   /**
diff --git a/chrome/browser/resources/signin/profile_picker/BUILD.gn b/chrome/browser/resources/signin/profile_picker/BUILD.gn
index 47fa119c..1cd3987 100644
--- a/chrome/browser/resources/signin/profile_picker/BUILD.gn
+++ b/chrome/browser/resources/signin/profile_picker/BUILD.gn
@@ -8,7 +8,7 @@
 import("//tools/grit/preprocess_if_expr.gni")
 import("//tools/polymer/html_to_js.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
-import("../../optimize_webui.gni")
+import("../../tools/optimize_webui.gni")
 
 preprocess_folder = "preprocessed"
 preprocess_manifest = "preprocessed_manifest.json"
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html
index fb033e1d..b7de3118 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html
@@ -26,11 +26,24 @@
 
   .title-container {
     margin: 30px auto 0 auto;
+    max-width: 490px;
     padding-inline-end: calc(var(--banner-img-width) - 10px);
     padding-inline-start: calc(var(--banner-img-width) - 10px);
     text-align: center;
   }
 
+  #product-logo {
+    height: 32px;
+  }
+
+  .title-container h2 {
+    margin-bottom: 8px;
+  }
+
+  .title-container h3 {
+    margin-top: 8px;
+  }
+
   #wrapper {
     display: flex;
     height: calc(max(100vh, var(--view-min-size)) - 290px);
@@ -39,14 +52,16 @@
   }
 
   .profiles-container {
-    --grid-gutter: 24px;
+    --grid-gutter: 16px;
     --profile-item-height:178px;
+    --profile-item-margin: 4px;
     --profile-item-width: 162px;
     align-items: center;
     display: grid;
     grid-column-gap: var(--grid-gutter);
     grid-row-gap: var(--grid-gutter);
-    grid-template-columns: repeat(auto-fit, var(--profile-item-width));
+    grid-template-columns: repeat(auto-fit, calc(var(--profile-item-width) +
+      2 * var(--profile-item-margin)));
     justify-content: center;
     margin: auto;
     max-height: 100%;
@@ -79,6 +94,7 @@
     flex-direction: column;
     height: var(--profile-item-height);
     justify-content: center;
+    margin: var(--profile-item-margin);
     width: var(--profile-item-width);
   }
 
diff --git a/chrome/browser/resources/tab_search/BUILD.gn b/chrome/browser/resources/tab_search/BUILD.gn
index 3eec2df..a32940b 100644
--- a/chrome/browser/resources/tab_search/BUILD.gn
+++ b/chrome/browser/resources/tab_search/BUILD.gn
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//chrome/browser/resources/optimize_webui.gni")
+import("//chrome/browser/resources/tools/optimize_webui.gni")
 import("//chrome/common/features.gni")
 import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/grit/grit_rule.gni")
diff --git a/chrome/browser/resources/tools/PRESUBMIT.py b/chrome/browser/resources/tools/PRESUBMIT.py
new file mode 100644
index 0000000..cb42b0d
--- /dev/null
+++ b/chrome/browser/resources/tools/PRESUBMIT.py
@@ -0,0 +1,28 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+def _CheckChangeOnUploadOrCommit(input_api, output_api):
+  results = []
+  webui_sources = set(['optimize_webui.py', 'rollup_plugin.js'])
+  affected = input_api.AffectedFiles()
+  affected_files = [input_api.os_path.basename(f.LocalPath()) for f in affected]
+  if webui_sources.intersection(set(affected_files)):
+    results += RunOptimizeWebUiTests(input_api, output_api)
+  return results
+
+
+def RunOptimizeWebUiTests(input_api, output_api):
+  presubmit_path = input_api.PresubmitLocalPath()
+  sources = ['optimize_webui_test.py']
+  tests = [input_api.os_path.join(presubmit_path, s) for s in sources]
+  return input_api.canned_checks.RunUnitTests(input_api, output_api, tests)
+
+
+def CheckChangeOnUpload(input_api, output_api):
+  return _CheckChangeOnUploadOrCommit(input_api, output_api)
+
+
+def CheckChangeOnCommit(input_api, output_api):
+  return _CheckChangeOnUploadOrCommit(input_api, output_api)
+
diff --git a/chrome/browser/resources/optimize_webui.gni b/chrome/browser/resources/tools/optimize_webui.gni
similarity index 93%
rename from chrome/browser/resources/optimize_webui.gni
rename to chrome/browser/resources/tools/optimize_webui.gni
index 91dfbb9a..5bcdb42a7 100644
--- a/chrome/browser/resources/optimize_webui.gni
+++ b/chrome/browser/resources/tools/optimize_webui.gni
@@ -7,7 +7,8 @@
 template("node") {
   # TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
   python2_action(target_name) {
-    forward_variables_from(invoker, "*")
+    forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
+    forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
 
     # Declare dependencies to all involved tools.
     inputs += [
@@ -30,7 +31,7 @@
 
 template("optimize_webui") {
   node(target_name) {
-    script = "//chrome/browser/resources/optimize_webui.py"
+    script = "//chrome/browser/resources/tools/optimize_webui.py"
 
     # This depfile is generated by optimize_webui.py
     depfile = "${target_gen_dir}/${target_name}.d"
diff --git a/chrome/browser/resources/optimize_webui.py b/chrome/browser/resources/tools/optimize_webui.py
similarity index 99%
rename from chrome/browser/resources/optimize_webui.py
rename to chrome/browser/resources/tools/optimize_webui.py
index ffcab4c..8d9c7da 100755
--- a/chrome/browser/resources/optimize_webui.py
+++ b/chrome/browser/resources/tools/optimize_webui.py
@@ -16,7 +16,7 @@
 
 
 _HERE_PATH = os.path.dirname(__file__)
-_SRC_PATH = os.path.normpath(os.path.join(_HERE_PATH, '..', '..', '..'))
+_SRC_PATH = os.path.normpath(os.path.join(_HERE_PATH, '..', '..', '..', '..'))
 _CWD = os.getcwd()  # NOTE(dbeam): this is typically out/<gn_name>/.
 
 sys.path.append(os.path.join(_SRC_PATH, 'third_party', 'node'))
@@ -209,7 +209,7 @@
   if not os.path.exists(tmp_out_dir):
     os.makedirs(tmp_out_dir)
   path_to_plugin = os.path.join(
-      os.path.abspath(_HERE_PATH), 'tools', 'rollup_plugin.js')
+      os.path.abspath(_HERE_PATH), 'rollup_plugin.js')
   rollup_config_file = _generate_rollup_config(tmp_out_dir, path_to_plugin,
                                                in_path, args.host, excludes,
                                                external_paths)
diff --git a/chrome/browser/resources/optimize_webui_test.py b/chrome/browser/resources/tools/optimize_webui_test.py
similarity index 100%
rename from chrome/browser/resources/optimize_webui_test.py
rename to chrome/browser/resources/tools/optimize_webui_test.py
diff --git a/chrome/browser/resources/webui_js_error/BUILD.gn b/chrome/browser/resources/webui_js_error/BUILD.gn
index fc2fe4f..994928f 100644
--- a/chrome/browser/resources/webui_js_error/BUILD.gn
+++ b/chrome/browser/resources/webui_js_error/BUILD.gn
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//chrome/browser/resources/optimize_webui.gni")
+import("//chrome/browser/resources/tools/optimize_webui.gni")
 import("//chrome/common/features.gni")
 import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/grit/grit_rule.gni")
diff --git a/chrome/browser/signin/dice_signed_in_profile_creator.cc b/chrome/browser/signin/dice_signed_in_profile_creator.cc
index 6227a46..6a57fc8f 100644
--- a/chrome/browser/signin/dice_signed_in_profile_creator.cc
+++ b/chrome/browser/signin/dice_signed_in_profile_creator.cc
@@ -134,10 +134,13 @@
     CoreAccountId account_id,
     const base::string16& local_profile_name,
     base::Optional<size_t> icon_index,
+    bool use_guest_profile,
     base::OnceCallback<void(Profile*)> callback)
     : source_profile_(source_profile),
       account_id_(account_id),
       callback_(std::move(callback)) {
+  // TODO(https://crbug.com/2587062): Use |use_guest_profile| param.
+  DCHECK(!use_guest_profile || Profile::IsEphemeralGuestProfileEnabled());
   ProfileAttributesStorage& storage =
       g_browser_process->profile_manager()->GetProfileAttributesStorage();
   if (!icon_index.has_value())
diff --git a/chrome/browser/signin/dice_signed_in_profile_creator.h b/chrome/browser/signin/dice_signed_in_profile_creator.h
index 7060ea05..4272a28 100644
--- a/chrome/browser/signin/dice_signed_in_profile_creator.h
+++ b/chrome/browser/signin/dice_signed_in_profile_creator.h
@@ -19,9 +19,10 @@
 // Extracts an account from an existing profile and moves it to a new profile.
 class DiceSignedInProfileCreator {
  public:
-  // Creates a new profile and moves the account from source_profile to the new
-  // profile. The callback is called with the new profile or nullptr in case of
-  // failure. The callback is never called synchronously.
+  // Creates a new profile or uses Guest profile if |use_guest_profile|, and
+  // moves the account from source_profile to it.
+  // The callback is called with the new profile or nullptr in case of failure.
+  // The callback is never called synchronously.
   // If |local_profile_name| is not empty, it will be set as local name for the
   // new profile.
   // If |icon_index| is nullopt, a random icon will be selected.
@@ -29,6 +30,7 @@
                              CoreAccountId account_id,
                              const base::string16& local_profile_name,
                              base::Optional<size_t> icon_index,
+                             bool use_guest_profile,
                              base::OnceCallback<void(Profile*)> callback);
 
   // Uses this version when the profile already exists at `target_profile_path`
diff --git a/chrome/browser/signin/dice_signed_in_profile_creator_unittest.cc b/chrome/browser/signin/dice_signed_in_profile_creator_unittest.cc
index c602985..98355d4 100644
--- a/chrome/browser/signin/dice_signed_in_profile_creator_unittest.cc
+++ b/chrome/browser/signin/dice_signed_in_profile_creator_unittest.cc
@@ -79,11 +79,14 @@
 
 }  // namespace
 
-class DiceSignedInProfileCreatorTest : public testing::Test,
-                                       public ProfileManagerObserver {
+class DiceSignedInProfileCreatorTest
+    : public testing::Test,
+      public ProfileManagerObserver,
+      public testing::WithParamInterface<bool> {
  public:
   DiceSignedInProfileCreatorTest()
-      : local_state_(TestingBrowserProcess::GetGlobal()) {
+      : local_state_(TestingBrowserProcess::GetGlobal()),
+        use_guest_profile_(GetParam()) {
     EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
     profile_manager_ = new UnittestProfileManager(temp_dir_.GetPath());
     TestingBrowserProcess::GetGlobal()->SetProfileManager(profile_manager_);
@@ -92,6 +95,10 @@
     identity_test_env_profile_adaptor_ =
         std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile());
     profile_manager()->AddObserver(this);
+    // Update |use_guest_profile_| if ephemeral Guest profiles is not supported.
+    use_guest_profile_ &=
+        TestingProfile::SetScopedFeatureListForEphemeralGuestProfiles(
+            scoped_feature_list_, use_guest_profile_);
   }
 
   ~DiceSignedInProfileCreatorTest() override { DeleteProfiles(); }
@@ -119,6 +126,8 @@
     profile_added_closure_ = std::move(closure);
   }
 
+  bool use_guest_profile() const { return use_guest_profile_; }
+
   void DeleteProfiles() {
     identity_test_env_profile_adaptor_.reset();
     if (profile_manager_) {
@@ -155,9 +164,11 @@
   Profile* added_profile_ = nullptr;
   base::OnceClosure profile_added_closure_;
   bool creator_callback_called_ = false;
+  base::test::ScopedFeatureList scoped_feature_list_;
+  bool use_guest_profile_;
 };
 
-TEST_F(DiceSignedInProfileCreatorTest, CreateWithTokensLoaded) {
+TEST_P(DiceSignedInProfileCreatorTest, CreateWithTokensLoaded) {
   AccountInfo account_info =
       identity_test_env()->MakeAccountAvailable("bob@example.com");
   size_t kTestIcon = profiles::GetModernAvatarIconStartIndex();
@@ -167,6 +178,7 @@
   std::unique_ptr<DiceSignedInProfileCreator> creator =
       std::make_unique<DiceSignedInProfileCreator>(
           profile(), account_info.account_id, kProfileTestName16, kTestIcon,
+          use_guest_profile(),
           base::BindOnce(&DiceSignedInProfileCreatorTest::OnProfileCreated,
                          base::Unretained(this), loop.QuitClosure()));
   loop.Run();
@@ -195,7 +207,7 @@
   EXPECT_EQ(kTestIcon, entry->GetAvatarIconIndex());
 }
 
-TEST_F(DiceSignedInProfileCreatorTest, CreateWithTokensNotLoaded) {
+TEST_P(DiceSignedInProfileCreatorTest, CreateWithTokensNotLoaded) {
   AccountInfo account_info =
       identity_test_env()->MakeAccountAvailable("bob@example.com");
   profile_manager()->set_tokens_loaded_at_creation(false);
@@ -206,6 +218,7 @@
   std::unique_ptr<DiceSignedInProfileCreator> creator =
       std::make_unique<DiceSignedInProfileCreator>(
           profile(), account_info.account_id, base::string16(), base::nullopt,
+          use_guest_profile(),
           base::BindOnce(&DiceSignedInProfileCreatorTest::OnProfileCreated,
                          base::Unretained(this), creator_loop.QuitClosure()));
   profile_added_loop.Run();
@@ -235,12 +248,13 @@
 }
 
 // Deleting the creator while it is running does not crash.
-TEST_F(DiceSignedInProfileCreatorTest, DeleteWhileCreating) {
+TEST_P(DiceSignedInProfileCreatorTest, DeleteWhileCreating) {
   AccountInfo account_info =
       identity_test_env()->MakeAccountAvailable("bob@example.com");
   std::unique_ptr<DiceSignedInProfileCreator> creator =
       std::make_unique<DiceSignedInProfileCreator>(
           profile(), account_info.account_id, base::string16(), base::nullopt,
+          use_guest_profile(),
           base::BindOnce(&DiceSignedInProfileCreatorTest::OnProfileCreated,
                          base::Unretained(this), base::OnceClosure()));
   EXPECT_FALSE(creator_callback_called());
@@ -249,7 +263,7 @@
 }
 
 // Deleting the profile while waiting for the tokens.
-TEST_F(DiceSignedInProfileCreatorTest, DeleteProfile) {
+TEST_P(DiceSignedInProfileCreatorTest, DeleteProfile) {
   AccountInfo account_info =
       identity_test_env()->MakeAccountAvailable("bob@example.com");
   profile_manager()->set_tokens_loaded_at_creation(false);
@@ -260,6 +274,7 @@
   std::unique_ptr<DiceSignedInProfileCreator> creator =
       std::make_unique<DiceSignedInProfileCreator>(
           profile(), account_info.account_id, base::string16(), base::nullopt,
+          use_guest_profile(),
           base::BindOnce(&DiceSignedInProfileCreatorTest::OnProfileCreated,
                          base::Unretained(this), creator_loop.QuitClosure()));
   profile_added_loop.Run();
@@ -278,3 +293,7 @@
   EXPECT_TRUE(creator_callback_called());
   EXPECT_FALSE(signed_in_profile());
 }
+
+INSTANTIATE_TEST_SUITE_P(AllGuestProfileTypes,
+                         DiceSignedInProfileCreatorTest,
+                         /*use_guest_profile=*/testing::Bool());
diff --git a/chrome/browser/signin/dice_web_signin_interceptor.cc b/chrome/browser/signin/dice_web_signin_interceptor.cc
index 3837243..9f9e6de 100644
--- a/chrome/browser/signin/dice_web_signin_interceptor.cc
+++ b/chrome/browser/signin/dice_web_signin_interceptor.cc
@@ -423,7 +423,8 @@
     const AccountInfo& account_info,
     SkColor profile_color,
     SigninInterceptionResult create) {
-  if (create != SigninInterceptionResult::kAccepted) {
+  if (create != SigninInterceptionResult::kAccepted &&
+      create != SigninInterceptionResult::kAcceptedWithGuest) {
     if (create == SigninInterceptionResult::kDeclined)
       RecordProfileCreationDeclined(account_info.email);
     Reset();
@@ -441,6 +442,7 @@
       std::make_unique<DiceSignedInProfileCreator>(
           profile_, account_id_, profile_name,
           profiles::GetPlaceholderAvatarIndex(),
+          create == SigninInterceptionResult::kAcceptedWithGuest,
           base::BindOnce(&DiceWebSigninInterceptor::OnNewSignedInProfileCreated,
                          base::Unretained(this), profile_color));
 }
@@ -489,7 +491,7 @@
     ThemeServiceFactory::GetForProfile(new_profile)
         ->BuildAutogeneratedThemeFromColor(*profile_color);
     // Show the customization UI to allow changing the color.
-    show_customization_bubble = true;
+    show_customization_bubble = !new_profile->IsEphemeralGuestProfile();
   } else {
     base::UmaHistogramTimes(
         "Signin.Intercept.ProfileSwitchDuration",
diff --git a/chrome/browser/signin/dice_web_signin_interceptor.h b/chrome/browser/signin/dice_web_signin_interceptor.h
index 098c608..033b549d 100644
--- a/chrome/browser/signin/dice_web_signin_interceptor.h
+++ b/chrome/browser/signin/dice_web_signin_interceptor.h
@@ -84,6 +84,9 @@
   kMaxValue = kAbortInterceptionDisabled,
 };
 
+// User selection in the interception bubble.
+enum class SigninInterceptionUserChoice { kAccept, kDecline, kGuest };
+
 // User action resulting from the interception bubble.
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused.
@@ -95,7 +98,10 @@
   // Used when the bubble was not shown because it's not implemented.
   kNotDisplayed = 3,
 
-  kMaxValue = kNotDisplayed,
+  // Accepted to be opened in Guest profile.
+  kAcceptedWithGuest = 4,
+
+  kMaxValue = kAcceptedWithGuest,
 };
 
 // The ScopedDiceWebSigninInterceptionBubbleHandle closes the signin intercept
diff --git a/chrome/browser/task_manager/providers/vm/crostini_process_task.cc b/chrome/browser/task_manager/providers/vm/crostini_process_task.cc
index b1e8506..c845a32 100644
--- a/chrome/browser/task_manager/providers/vm/crostini_process_task.cc
+++ b/chrome/browser/task_manager/providers/vm/crostini_process_task.cc
@@ -17,7 +17,7 @@
 CrostiniProcessTask::CrostiniProcessTask(base::ProcessId pid,
                                          const std::string& owner_id,
                                          const std::string& vm_name)
-    : VmProcessTask(FetchIcon(IDR_LOGO_CROSTINI_DEFAULT_32, &s_icon_),
+    : VmProcessTask(FetchIcon(IDR_LOGO_CROSTINI_DEFAULT, &s_icon_),
                     IDS_TASK_MANAGER_LINUX_VM_PREFIX,
                     pid,
                     owner_id,
diff --git a/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenu.java b/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenu.java
index 6fad28e..82bea4eb 100644
--- a/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenu.java
+++ b/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenu.java
@@ -263,9 +263,7 @@
         int footerHeight = inflateFooter(footerResourceId, contentView, menuWidth);
         int headerHeight = inflateHeader(headerResourceId, contentView, menuWidth);
 
-        if (highlightedItemId != null
-                && (highlightedItemId == footerResourceId
-                        || highlightedItemId == headerResourceId)) {
+        if (highlightedItemId != null) {
             View viewToHighlight = contentView.findViewById(highlightedItemId);
             ViewHighlighter.turnOnRectangularHighlight(viewToHighlight);
         }
diff --git a/chrome/browser/ui/android/toolbar/BUILD.gn b/chrome/browser/ui/android/toolbar/BUILD.gn
index d3d0046..882b9b6 100644
--- a/chrome/browser/ui/android/toolbar/BUILD.gn
+++ b/chrome/browser/ui/android/toolbar/BUILD.gn
@@ -63,6 +63,9 @@
     "java/res/drawable-xhdpi/btn_toolbar_home.png",
     "java/res/drawable-xxhdpi/btn_toolbar_home.png",
     "java/res/drawable-xxxhdpi/btn_toolbar_home.png",
+    "java/res/layout/control_container.xml",
+    "java/res/values-sw600dp/dimens.xml",
+    "java/res/values/dimens.xml",
   ]
 
   deps = [
diff --git a/chrome/browser/ui/android/toolbar/OWNERS b/chrome/browser/ui/android/toolbar/OWNERS
index 81c2db6d..85393cc 100644
--- a/chrome/browser/ui/android/toolbar/OWNERS
+++ b/chrome/browser/ui/android/toolbar/OWNERS
@@ -2,3 +2,6 @@
 tedchoc@chromium.org
 yusufo@chromium.org
 twellington@chromium.org
+
+per-file StartSurfaceToolbar*=file://chrome/android/java/src/org/chromium/chrome/browser/tasks/OWNERS
+per-file IncognitoSwitch*=file://chrome/android/java/src/org/chromium/chrome/browser/tasks/OWNERS
diff --git a/chrome/android/java/res/layout/control_container.xml b/chrome/browser/ui/android/toolbar/java/res/layout/control_container.xml
similarity index 100%
rename from chrome/android/java/res/layout/control_container.xml
rename to chrome/browser/ui/android/toolbar/java/res/layout/control_container.xml
diff --git a/components/browser_ui/styles/android/java/res/values-sw600dp/dimens.xml b/chrome/browser/ui/android/toolbar/java/res/values-sw600dp/dimens.xml
similarity index 80%
rename from components/browser_ui/styles/android/java/res/values-sw600dp/dimens.xml
rename to chrome/browser/ui/android/toolbar/java/res/values-sw600dp/dimens.xml
index 5b70c83f6..1d4f8fb6 100644
--- a/components/browser_ui/styles/android/java/res/values-sw600dp/dimens.xml
+++ b/chrome/browser/ui/android/toolbar/java/res/values-sw600dp/dimens.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2020 The Chromium Authors. All rights reserved.
+<!-- Copyright 2021 The Chromium Authors. All rights reserved.
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
diff --git a/components/browser_ui/styles/android/java/res/values-sw600dp/dimens.xml b/chrome/browser/ui/android/toolbar/java/res/values/dimens.xml
similarity index 65%
copy from components/browser_ui/styles/android/java/res/values-sw600dp/dimens.xml
copy to chrome/browser/ui/android/toolbar/java/res/values/dimens.xml
index 5b70c83f6..3d97ed8 100644
--- a/components/browser_ui/styles/android/java/res/values-sw600dp/dimens.xml
+++ b/chrome/browser/ui/android/toolbar/java/res/values/dimens.xml
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2020 The Chromium Authors. All rights reserved.
+<!-- Copyright 2021 The Chromium Authors. All rights reserved.
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
 <resources>
     <!-- Tab Strip Dimensions -->
-    <dimen name="tab_strip_height">40dp</dimen>
+    <dimen name="tab_strip_height">0dp</dimen>
 </resources>
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/OWNERS b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/OWNERS
deleted file mode 100644
index 5643c5c..0000000
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file StartSurfaceToolbar*=file://chrome/android/java/src/org/chromium/chrome/browser/tasks/OWNERS
-per-file IncognitoSwitch*=file://chrome/android/java/src/org/chromium/chrome/browser/tasks/OWNERS
diff --git a/chrome/browser/ui/ash/ime_controller_client.cc b/chrome/browser/ui/ash/ime_controller_client.cc
index 4fc9efe..142cb28 100644
--- a/chrome/browser/ui/ash/ime_controller_client.cc
+++ b/chrome/browser/ui/ash/ime_controller_client.cc
@@ -129,9 +129,7 @@
   // Get the short name of the changed input method (e.g. US, JA, etc.)
   const InputMethodDescriptor descriptor =
       input_method_manager_->GetActiveIMEState()->GetCurrentInputMethod();
-  const base::string16 short_name =
-      input_method_manager_->GetInputMethodUtil()->GetInputMethodShortName(
-          descriptor);
+  const base::string16 short_name = descriptor.GetIndicator();
 
   chromeos::IMECandidateWindowHandlerInterface* cw_handler =
       ui::IMEBridge::Get()->GetCandidateWindowHandler();
@@ -209,7 +207,7 @@
   ash::ImeInfo info;
   info.id = ime.id();
   info.name = util->GetInputMethodLongName(ime);
-  info.short_name = util->GetInputMethodShortName(ime);
+  info.short_name = ime.GetIndicator();
   info.third_party = chromeos::extension_ime_util::IsExtensionIME(ime.id());
   return info;
 }
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 44820d4..592ec8b 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -715,7 +715,7 @@
   log_manager_ =
       LogManager::Create(AutofillLogRouterFactory::GetForBrowserContext(
                              web_contents->GetBrowserContext()),
-                         base::Closure());
+                         base::NullCallback());
   // Initialize StrikeDatabase so its cache will be loaded and ready to use when
   // when requested by other Autofill classes.
   GetStrikeDatabase();
diff --git a/chrome/browser/ui/bluetooth/bluetooth_chooser_controller_unittest.cc b/chrome/browser/ui/bluetooth/bluetooth_chooser_controller_unittest.cc
index e41ae6a..42ce011 100644
--- a/chrome/browser/ui/bluetooth/bluetooth_chooser_controller_unittest.cc
+++ b/chrome/browser/ui/bluetooth/bluetooth_chooser_controller_unittest.cc
@@ -19,8 +19,9 @@
   BluetoothChooserControllerTest()
       : bluetooth_chooser_controller_(
             nullptr,
-            base::Bind(&BluetoothChooserControllerTest::OnBluetoothChooserEvent,
-                       base::Unretained(this))) {
+            base::BindRepeating(
+                &BluetoothChooserControllerTest::OnBluetoothChooserEvent,
+                base::Unretained(this))) {
     bluetooth_chooser_controller_.set_view(&mock_bluetooth_chooser_view_);
   }
 
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index cab05432..43c0a74e 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -147,7 +147,7 @@
     local_pref_registrar_.Init(local_state);
     local_pref_registrar_.Add(
         prefs::kAllowFileSelectionDialogs,
-        base::Bind(
+        base::BindRepeating(
             &BrowserCommandController::UpdateCommandsForFileSelectionDialogs,
             base::Unretained(this)));
   }
@@ -155,30 +155,33 @@
   profile_pref_registrar_.Init(profile()->GetPrefs());
   profile_pref_registrar_.Add(
       prefs::kDevToolsAvailability,
-      base::Bind(&BrowserCommandController::UpdateCommandsForDevTools,
-                 base::Unretained(this)));
+      base::BindRepeating(&BrowserCommandController::UpdateCommandsForDevTools,
+                          base::Unretained(this)));
   profile_pref_registrar_.Add(
       bookmarks::prefs::kEditBookmarksEnabled,
-      base::Bind(&BrowserCommandController::UpdateCommandsForBookmarkEditing,
-                 base::Unretained(this)));
+      base::BindRepeating(
+          &BrowserCommandController::UpdateCommandsForBookmarkEditing,
+          base::Unretained(this)));
   profile_pref_registrar_.Add(
       bookmarks::prefs::kShowBookmarkBar,
-      base::Bind(&BrowserCommandController::UpdateCommandsForBookmarkBar,
-                 base::Unretained(this)));
+      base::BindRepeating(
+          &BrowserCommandController::UpdateCommandsForBookmarkBar,
+          base::Unretained(this)));
   profile_pref_registrar_.Add(
       prefs::kIncognitoModeAvailability,
-      base::Bind(
+      base::BindRepeating(
           &BrowserCommandController::UpdateCommandsForIncognitoAvailability,
           base::Unretained(this)));
   profile_pref_registrar_.Add(
       prefs::kPrintingEnabled,
-      base::Bind(&BrowserCommandController::UpdatePrintingState,
-                 base::Unretained(this)));
+      base::BindRepeating(&BrowserCommandController::UpdatePrintingState,
+                          base::Unretained(this)));
 #if !defined(OS_MAC)
   profile_pref_registrar_.Add(
       prefs::kFullscreenAllowed,
-      base::Bind(&BrowserCommandController::UpdateCommandsForFullscreenMode,
-                 base::Unretained(this)));
+      base::BindRepeating(
+          &BrowserCommandController::UpdateCommandsForFullscreenMode,
+          base::Unretained(this)));
 #endif
   pref_signin_allowed_.Init(
       prefs::kSigninAllowed, profile()->GetOriginalProfile()->GetPrefs(),
diff --git a/chrome/browser/ui/browser_dialogs.h b/chrome/browser/ui/browser_dialogs.h
index 9e01097d..3f2ebe7 100644
--- a/chrome/browser/ui/browser_dialogs.h
+++ b/chrome/browser/ui/browser_dialogs.h
@@ -93,7 +93,7 @@
     gfx::NativeWindow parent_window,
     Profile* profile,
     const extensions::Extension* app,
-    const base::Callback<void(bool /* created */)>& close_callback);
+    base::OnceCallback<void(bool /* created */)> close_callback);
 
 // Shows the create chrome app shortcut dialog box. Same as above but for a
 // WebApp instead of an Extension. |close_callback| may be null.
@@ -101,7 +101,7 @@
     gfx::NativeWindow parent_window,
     Profile* profile,
     const std::string& web_app_id,
-    const base::Callback<void(bool /* created */)>& close_callback);
+    base::OnceCallback<void(bool /* created */)> close_callback);
 
 // Callback used to indicate whether a user has accepted the installation of a
 // web app. The boolean parameter is true when the user accepts the dialog. The
diff --git a/chrome/browser/ui/browser_instant_controller.cc b/chrome/browser/ui/browser_instant_controller.cc
index 16b3c4cc..d953be8 100644
--- a/chrome/browser/ui/browser_instant_controller.cc
+++ b/chrome/browser/ui/browser_instant_controller.cc
@@ -82,8 +82,9 @@
     search_engine_base_url_tracker_ =
         std::make_unique<SearchEngineBaseURLTracker>(
             template_url_service, std::make_unique<UIThreadSearchTermsData>(),
-            base::Bind(&BrowserInstantController::OnSearchEngineBaseURLChanged,
-                       base::Unretained(this)));
+            base::BindRepeating(
+                &BrowserInstantController::OnSearchEngineBaseURLChanged,
+                base::Unretained(this)));
   }
 }
 
diff --git a/chrome/browser/ui/browser_list.cc b/chrome/browser/ui/browser_list.cc
index e6bb0e7..1b89fc1c 100644
--- a/chrome/browser/ui/browser_list.cc
+++ b/chrome/browser/ui/browser_list.cc
@@ -203,9 +203,10 @@
        ++it) {
     if ((*it)->TryToCloseWindow(
             skip_beforeunload,
-            base::Bind(&BrowserList::PostTryToCloseBrowserWindow,
-                       browsers_to_close, on_close_success, on_close_aborted,
-                       profile_path, skip_beforeunload))) {
+            base::BindRepeating(&BrowserList::PostTryToCloseBrowserWindow,
+                                browsers_to_close, on_close_success,
+                                on_close_aborted, profile_path,
+                                skip_beforeunload))) {
       return;
     }
   }
diff --git a/chrome/browser/ui/crypto_module_delegate_nss.cc b/chrome/browser/ui/crypto_module_delegate_nss.cc
index 5f44b55e..0a11d3be 100644
--- a/chrome/browser/ui/crypto_module_delegate_nss.cc
+++ b/chrome/browser/ui/crypto_module_delegate_nss.cc
@@ -51,11 +51,11 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   ShowCryptoModulePasswordDialog(
       slot_name, retry, reason_, server_.host(),
-      NULL,  // TODO(mattm): Supply parent window.
-      base::Bind(&ChromeNSSCryptoModuleDelegate::GotPassword,
-                 // RequestPassword is blocked on |event_| until GotPassword is
-                 // called, so there's no need to ref-count.
-                 base::Unretained(this)));
+      nullptr,  // TODO(mattm): Supply parent window.
+      base::BindOnce(&ChromeNSSCryptoModuleDelegate::GotPassword,
+                     // RequestPassword is blocked on |event_| until GotPassword
+                     // is called, so there's no need to ref-count.
+                     base::Unretained(this)));
 }
 
 void ChromeNSSCryptoModuleDelegate::GotPassword(const std::string& password) {
diff --git a/chrome/browser/ui/crypto_module_password_dialog.h b/chrome/browser/ui/crypto_module_password_dialog.h
index 50c02c5d..073d4c1 100644
--- a/chrome/browser/ui/crypto_module_password_dialog.h
+++ b/chrome/browser/ui/crypto_module_password_dialog.h
@@ -19,18 +19,18 @@
   kCryptoModulePasswordCertExport,
 };
 
-typedef base::Callback<void(const std::string&)> CryptoModulePasswordCallback;
+typedef base::OnceCallback<void(const std::string&)>
+    CryptoModulePasswordCallback;
 
 // Display a dialog, prompting the user to authenticate to unlock
 // |module|. |reason| describes the purpose of the authentication and
 // affects the message displayed in the dialog. |hostname| is the hostname
 // of the server which requested the access.
-void ShowCryptoModulePasswordDialog(
-    const std::string& module_name,
-    bool retry,
-    CryptoModulePasswordReason reason,
-    const std::string& hostname,
-    gfx::NativeWindow parent,
-    const CryptoModulePasswordCallback& callback);
+void ShowCryptoModulePasswordDialog(const std::string& module_name,
+                                    bool retry,
+                                    CryptoModulePasswordReason reason,
+                                    const std::string& hostname,
+                                    gfx::NativeWindow parent,
+                                    CryptoModulePasswordCallback callback);
 
 #endif  // CHROME_BROWSER_UI_CRYPTO_MODULE_PASSWORD_DIALOG_H_
diff --git a/chrome/browser/ui/crypto_module_password_dialog_nss.cc b/chrome/browser/ui/crypto_module_password_dialog_nss.cc
index 2e5c854..83399f9 100644
--- a/chrome/browser/ui/crypto_module_password_dialog_nss.cc
+++ b/chrome/browser/ui/crypto_module_password_dialog_nss.cc
@@ -69,7 +69,7 @@
       ShowCryptoModulePasswordDialog(
           PK11_GetTokenName(modules_[current_].get()), retry_, reason_,
           server_.host(), parent_,
-          base::Bind(&SlotUnlocker::GotPassword, base::Unretained(this)));
+          base::BindOnce(&SlotUnlocker::GotPassword, base::Unretained(this)));
       return;
     }
   }
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc
index 22fdd138..76d50db 100644
--- a/chrome/browser/ui/extensions/application_launch.cc
+++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -82,12 +82,12 @@
                       ExtensionRegistry* registry,
                       Profile* profile,
                       const std::string& extension_id,
-                      const base::Closure& callback)
+                      base::OnceClosure callback)
       : service_(service),
         registry_(registry),
         profile_(profile),
         extension_id_(extension_id),
-        callback_(callback) {}
+        callback_(std::move(callback)) {}
 
   ~EnableViaDialogFlow() override {}
 
@@ -105,7 +105,7 @@
         registry_->GetExtensionById(extension_id_, ExtensionRegistry::ENABLED);
     if (!extension)
       return;
-    callback_.Run();
+    std::move(callback_).Run();
     delete this;
   }
 
@@ -115,7 +115,7 @@
   ExtensionRegistry* registry_;
   Profile* profile_;
   std::string extension_id_;
-  base::Closure callback_;
+  base::OnceClosure callback_;
   std::unique_ptr<ExtensionEnableFlow> flow_;
 
   DISALLOW_COPY_AND_ASSIGN(EnableViaDialogFlow);
@@ -504,13 +504,12 @@
   if (!service->IsExtensionEnabled(extension->id()) ||
       registry->GetExtensionById(extension->id(),
                                  ExtensionRegistry::TERMINATED)) {
-    base::Callback<gfx::NativeWindow(void)> dialog_parent_window_getter;
     // TODO(pkotwicz): Figure out which window should be used as the parent for
     // the "enable application" dialog in Athena.
     (new EnableViaDialogFlow(
          service, registry, profile, extension->id(),
-         base::Bind(base::IgnoreResult(OpenEnabledApplication), profile,
-                    base::Passed(std::move(params)))))
+         base::BindOnce(base::IgnoreResult(OpenEnabledApplication), profile,
+                        base::Passed(std::move(params)))))
         ->Run();
     return;
   }
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.cc b/chrome/browser/ui/extensions/extension_action_view_controller.cc
index 1896bbe..7c00f258 100644
--- a/chrome/browser/ui/extensions/extension_action_view_controller.cc
+++ b/chrome/browser/ui/extensions/extension_action_view_controller.cc
@@ -416,9 +416,10 @@
     extensions_container_->CloseOverflowMenuIfOpen();
     extensions_container_->PopOutAction(
         this, show_action == SHOW_POPUP_AND_INSPECT,
-        base::Bind(&ExtensionActionViewController::ShowPopup,
-                   weak_factory_.GetWeakPtr(), base::Passed(std::move(host)),
-                   grant_tab_permissions, show_action));
+        base::BindOnce(&ExtensionActionViewController::ShowPopup,
+                       weak_factory_.GetWeakPtr(),
+                       base::Passed(std::move(host)), grant_tab_permissions,
+                       show_action));
   } else {
     ShowPopup(std::move(host), grant_tab_permissions, show_action);
   }
diff --git a/chrome/browser/ui/extensions/extension_enable_flow.cc b/chrome/browser/ui/extensions/extension_enable_flow.cc
index e18e0f1..3a693485 100644
--- a/chrome/browser/ui/extensions/extension_enable_flow.cc
+++ b/chrome/browser/ui/extensions/extension_enable_flow.cc
@@ -154,8 +154,8 @@
   ExtensionInstallPrompt::PromptType type =
       ExtensionInstallPrompt::GetReEnablePromptTypeForExtension(profile_,
                                                                 extension);
-  prompt_->ShowDialog(base::Bind(&ExtensionEnableFlow::InstallPromptDone,
-                                 weak_ptr_factory_.GetWeakPtr()),
+  prompt_->ShowDialog(base::BindOnce(&ExtensionEnableFlow::InstallPromptDone,
+                                     weak_ptr_factory_.GetWeakPtr()),
                       extension, nullptr,
                       std::make_unique<ExtensionInstallPrompt::Prompt>(type),
                       ExtensionInstallPrompt::GetDefaultShowDialogCallback());
diff --git a/chrome/browser/ui/extensions/extension_enable_flow.h b/chrome/browser/ui/extensions/extension_enable_flow.h
index f3a0746..165d381 100644
--- a/chrome/browser/ui/extensions/extension_enable_flow.h
+++ b/chrome/browser/ui/extensions/extension_enable_flow.h
@@ -117,10 +117,6 @@
   // exclusive with |parent_contents_| above.
   gfx::NativeWindow parent_window_ = nullptr;
 
-  // Called to acquire a parent window for the prompt. This is used for clients
-  // who only want to create a window if it is required.
-  base::Callback<gfx::NativeWindow(void)> window_getter_;
-
   std::unique_ptr<ExtensionInstallPrompt> prompt_;
   content::NotificationRegistrar registrar_;
 
diff --git a/chrome/browser/ui/extensions/extension_installed_waiter.cc b/chrome/browser/ui/extensions/extension_installed_waiter.cc
index 0e528ac..98ccdb7 100644
--- a/chrome/browser/ui/extensions/extension_installed_waiter.cc
+++ b/chrome/browser/ui/extensions/extension_installed_waiter.cc
@@ -42,8 +42,8 @@
       extensions::ExtensionRegistry::Get(browser->profile()));
   removal_watcher_ = std::make_unique<ExtensionRemovalWatcher>(
       browser, extension,
-      base::Bind(&ExtensionInstalledWaiter::OnExtensionRemoved,
-                 weak_factory_.GetWeakPtr()));
+      base::BindOnce(&ExtensionInstalledWaiter::OnExtensionRemoved,
+                     weak_factory_.GetWeakPtr()));
 }
 
 ExtensionInstalledWaiter::~ExtensionInstalledWaiter() {
diff --git a/chrome/browser/ui/extensions/settings_overridden_params_providers_unittest.cc b/chrome/browser/ui/extensions/settings_overridden_params_providers_unittest.cc
index 22690af7..9611111 100644
--- a/chrome/browser/ui/extensions/settings_overridden_params_providers_unittest.cc
+++ b/chrome/browser/ui/extensions/settings_overridden_params_providers_unittest.cc
@@ -27,8 +27,9 @@
     // exists.
     extensions::ExtensionWebUIOverrideRegistrar::GetFactoryInstance()
         ->SetTestingFactoryAndUse(
-            profile(), base::Bind([](content::BrowserContext* context)
-                                      -> std::unique_ptr<KeyedService> {
+            profile(),
+            base::BindRepeating([](content::BrowserContext* context)
+                                    -> std::unique_ptr<KeyedService> {
               return std::make_unique<
                   extensions::ExtensionWebUIOverrideRegistrar>(context);
             }));
diff --git a/chrome/browser/ui/media_router/media_router_ui_unittest.cc b/chrome/browser/ui/media_router/media_router_ui_unittest.cc
index cdb97f3d..a750053 100644
--- a/chrome/browser/ui/media_router/media_router_ui_unittest.cc
+++ b/chrome/browser/ui/media_router/media_router_ui_unittest.cc
@@ -240,10 +240,10 @@
         std::make_unique<PresentationRequestCallbacks>(expected_error);
     start_presentation_context_ = std::make_unique<StartPresentationContext>(
         presentation_request_,
-        base::Bind(&PresentationRequestCallbacks::Success,
-                   base::Unretained(request_callbacks.get())),
-        base::Bind(&PresentationRequestCallbacks::Error,
-                   base::Unretained(request_callbacks.get())));
+        base::BindOnce(&PresentationRequestCallbacks::Success,
+                       base::Unretained(request_callbacks.get())),
+        base::BindOnce(&PresentationRequestCallbacks::Error,
+                       base::Unretained(request_callbacks.get())));
     StartPresentationContext* context_ptr = start_presentation_context_.get();
     ui_->set_start_presentation_context_for_test(
         std::move(start_presentation_context_));
diff --git a/chrome/browser/ui/page_info/page_info_unittest.cc b/chrome/browser/ui/page_info/page_info_unittest.cc
index 6e8af4b1..6414a7e1a 100644
--- a/chrome/browser/ui/page_info/page_info_unittest.cc
+++ b/chrome/browser/ui/page_info/page_info_unittest.cc
@@ -201,8 +201,8 @@
     mock_ui_ = std::make_unique<MockPageInfoUI>();
     // Use this rather than gmock's ON_CALL.WillByDefault(Invoke(... because
     // gmock doesn't handle move-only types well.
-    mock_ui_->set_permission_info_callback_ =
-        base::Bind(&PageInfoTest::SetPermissionInfo, base::Unretained(this));
+    mock_ui_->set_permission_info_callback_ = base::BindRepeating(
+        &PageInfoTest::SetPermissionInfo, base::Unretained(this));
   }
 
 
@@ -259,8 +259,8 @@
               incognito_web_contents_.get()));
 
       incognito_mock_ui_ = std::make_unique<MockPageInfoUI>();
-      incognito_mock_ui_->set_permission_info_callback_ =
-          base::Bind(&PageInfoTest::SetPermissionInfo, base::Unretained(this));
+      incognito_mock_ui_->set_permission_info_callback_ = base::BindRepeating(
+          &PageInfoTest::SetPermissionInfo, base::Unretained(this));
 
       auto delegate = std::make_unique<ChromePageInfoDelegate>(
           incognito_web_contents_.get());
diff --git a/chrome/browser/ui/page_info/permission_menu_model.cc b/chrome/browser/ui/page_info/permission_menu_model.cc
index 5d088d79..49e0529 100644
--- a/chrome/browser/ui/page_info/permission_menu_model.cc
+++ b/chrome/browser/ui/page_info/permission_menu_model.cc
@@ -41,12 +41,12 @@
 PermissionMenuModel::PermissionMenuModel(Profile* profile,
                                          const GURL& url,
                                          const PageInfo::PermissionInfo& info,
-                                         const ChangeCallback& callback)
+                                         ChangeCallback callback)
     : ui::SimpleMenuModel(this),
       host_content_settings_map_(
           HostContentSettingsMapFactory::GetForProfile(profile)),
       permission_(info),
-      callback_(callback) {
+      callback_(std::move(callback)) {
   DCHECK(!callback_.is_null());
   base::string16 label;
 
diff --git a/chrome/browser/ui/page_info/permission_menu_model.h b/chrome/browser/ui/page_info/permission_menu_model.h
index e4579f9..f96ba21 100644
--- a/chrome/browser/ui/page_info/permission_menu_model.h
+++ b/chrome/browser/ui/page_info/permission_menu_model.h
@@ -18,13 +18,14 @@
 class PermissionMenuModel : public ui::SimpleMenuModel,
                             public ui::SimpleMenuModel::Delegate {
  public:
-  typedef base::Callback<void(const PageInfo::PermissionInfo&)> ChangeCallback;
+  typedef base::RepeatingCallback<void(const PageInfo::PermissionInfo&)>
+      ChangeCallback;
 
   // Create a new menu model for permission settings.
   PermissionMenuModel(Profile* profile,
                       const GURL& url,
                       const PageInfo::PermissionInfo& info,
-                      const ChangeCallback& callback);
+                      ChangeCallback callback);
   ~PermissionMenuModel() override;
 
   // Overridden from ui::SimpleMenuModel::Delegate:
diff --git a/chrome/browser/ui/page_info/permission_menu_model_unittest.cc b/chrome/browser/ui/page_info/permission_menu_model_unittest.cc
index 1db213e8..12c664c8 100644
--- a/chrome/browser/ui/page_info/permission_menu_model_unittest.cc
+++ b/chrome/browser/ui/page_info/permission_menu_model_unittest.cc
@@ -17,7 +17,8 @@
   TestCallback() : current_(-1) {}
 
   PermissionMenuModel::ChangeCallback callback() {
-    return base::Bind(&TestCallback::PermissionChanged, base::Unretained(this));
+    return base::BindRepeating(&TestCallback::PermissionChanged,
+                               base::Unretained(this));
   }
   void PermissionChanged(const PageInfo::PermissionInfo& permission) {
     current_ = permission.setting;
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
index 59b6db10..0aef06e 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -530,7 +530,7 @@
       passwords_data_.client()->GetAccountPasswordStore(),
       Profile::FromBrowserContext(web_contents()->GetBrowserContext())
           ->GetPrefs(),
-      base::Bind(
+      base::BindOnce(
           &ManagePasswordsUIController::OnTriggerPostSaveCompromisedBubble,
           weak_ptr_factory_.GetWeakPtr()));
 
diff --git a/chrome/browser/ui/prefs/prefs_tab_helper.cc b/chrome/browser/ui/prefs/prefs_tab_helper.cc
index 45f928b1..5b89ba6 100644
--- a/chrome/browser/ui/prefs/prefs_tab_helper.cc
+++ b/chrome/browser/ui/prefs/prefs_tab_helper.cc
@@ -298,18 +298,19 @@
     ChromeZoomLevelPrefs* zoom_level_prefs =
         profile_to_track->GetZoomLevelPrefs();
 
-    base::Closure renderer_callback = base::Bind(
-        &PrefsTabHelper::UpdateRendererPreferences, base::Unretained(this));
     // Tests should not need to create a ZoomLevelPrefs.
     if (zoom_level_prefs) {
       default_zoom_level_subscription_ =
-          zoom_level_prefs->RegisterDefaultZoomLevelCallback(renderer_callback);
+          zoom_level_prefs->RegisterDefaultZoomLevelCallback(
+              base::BindRepeating(&PrefsTabHelper::UpdateRendererPreferences,
+                                  base::Unretained(this)));
     }
 
     // Unretained is safe because the registrar will be scoped to this class.
     font_change_registrar_.Register(
         FontPrefChangeNotifierFactory::GetForProfile(profile_),
-        base::Bind(&PrefsTabHelper::OnWebPrefChanged, base::Unretained(this)));
+        base::BindRepeating(&PrefsTabHelper::OnWebPrefChanged,
+                            base::Unretained(this)));
 #endif  // !defined(OS_ANDROID)
 
     PrefWatcher::Get(profile_)->RegisterHelper(this);
diff --git a/chrome/browser/ui/profile_picker.cc b/chrome/browser/ui/profile_picker.cc
index d991735..22589b89 100644
--- a/chrome/browser/ui/profile_picker.cc
+++ b/chrome/browser/ui/profile_picker.cc
@@ -41,9 +41,6 @@
 bool ProfilePicker::ShouldShowAtLaunch() {
   AvailabilityOnStartup availability_on_startup = GetAvailabilityOnStartup();
 
-  if (signin_util::IsForceSigninEnabled())
-    return false;
-
   if (!base::FeatureList::IsEnabled(features::kNewProfilePicker))
     return false;
 
diff --git a/chrome/browser/ui/search/instant_controller.cc b/chrome/browser/ui/search/instant_controller.cc
index 90471d5..dd808525 100644
--- a/chrome/browser/ui/search/instant_controller.cc
+++ b/chrome/browser/ui/search/instant_controller.cc
@@ -21,8 +21,10 @@
 
 class InstantController::TabObserver : public content::WebContentsObserver {
  public:
-  TabObserver(content::WebContents* web_contents, const base::Closure& callback)
-      : content::WebContentsObserver(web_contents), callback_(callback) {}
+  TabObserver(content::WebContents* web_contents,
+              base::RepeatingClosure callback)
+      : content::WebContentsObserver(web_contents),
+        callback_(std::move(callback)) {}
   ~TabObserver() override = default;
 
  private:
@@ -34,7 +36,7 @@
     }
   }
 
-  base::Closure callback_;
+  base::RepeatingClosure callback_;
 
   DISALLOW_COPY_AND_ASSIGN(TabObserver);
 };
@@ -64,8 +66,9 @@
 void InstantController::StartWatchingTab(content::WebContents* web_contents) {
   if (!tab_observer_ || tab_observer_->web_contents() != web_contents) {
     tab_observer_ = std::make_unique<TabObserver>(
-        web_contents, base::Bind(&InstantController::UpdateInfoForInstantTab,
-                                 base::Unretained(this)));
+        web_contents,
+        base::BindRepeating(&InstantController::UpdateInfoForInstantTab,
+                            base::Unretained(this)));
     // If this tab is an NTP, immediately send it the required info.
     if (search::IsInstantNTP(web_contents)) {
       UpdateInfoForInstantTab();
diff --git a/chrome/browser/ui/search/local_ntp_one_google_bar_browsertest.cc b/chrome/browser/ui/search/local_ntp_one_google_bar_browsertest.cc
index 77cdf143..626f8203 100644
--- a/chrome/browser/ui/search/local_ntp_one_google_bar_browsertest.cc
+++ b/chrome/browser/ui/search/local_ntp_one_google_bar_browsertest.cc
@@ -69,9 +69,9 @@
     create_services_subscription_ =
         BrowserContextDependencyManager::GetInstance()
             ->RegisterCreateServicesCallbackForTesting(
-                base::Bind(&LocalNTPOneGoogleBarSmokeTest::
-                               OnWillCreateBrowserContextServices,
-                           base::Unretained(this)));
+                base::BindRepeating(&LocalNTPOneGoogleBarSmokeTest::
+                                        OnWillCreateBrowserContextServices,
+                                    base::Unretained(this)));
   }
 
   static std::unique_ptr<KeyedService> CreateOneGoogleBarService(
diff --git a/chrome/browser/ui/search_engines/search_engine_tab_helper_browsertest.cc b/chrome/browser/ui/search_engines/search_engine_tab_helper_browsertest.cc
index 088ed8c..fc8f1bd 100644
--- a/chrome/browser/ui/search_engines/search_engine_tab_helper_browsertest.cc
+++ b/chrome/browser/ui/search_engines/search_engine_tab_helper_browsertest.cc
@@ -94,8 +94,8 @@
         base::FilePath(),
         base::FilePath().AppendASCII("simple_open_search.xml"));
     embedded_test_server()->RegisterRequestHandler(
-        base::Bind(&SearchEngineTabHelperBrowserTest::HandleRequest,
-                   base::Unretained(this), file_url));
+        base::BindRepeating(&SearchEngineTabHelperBrowserTest::HandleRequest,
+                            base::Unretained(this), file_url));
     return embedded_test_server()->Start();
   }
 
diff --git a/chrome/browser/ui/signin/profile_colors_util_unittest.cc b/chrome/browser/ui/signin/profile_colors_util_unittest.cc
index 77ea93f..eea10b1e 100644
--- a/chrome/browser/ui/signin/profile_colors_util_unittest.cc
+++ b/chrome/browser/ui/signin/profile_colors_util_unittest.cc
@@ -96,7 +96,7 @@
     // Instead of providing a random number generator, return an arbitrary value
     // and capture the count of options.
     GenerateNewProfileColorWithGenerator(
-        *storage(), base::Bind(&CaptureCountAndReturnZero, &count), entry);
+        *storage(), base::BindOnce(&CaptureCountAndReturnZero, &count), entry);
     return count;
   }
 
@@ -104,7 +104,7 @@
     // Instead of providing a random number generator, return the nth option
     // deterministically.
     return GenerateNewProfileColorWithGenerator(
-               *storage(), base::Bind(&ReturnNth, n), entry)
+               *storage(), base::BindOnce(&ReturnNth, n), entry)
         .id;
   }
 
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc
index 9f804c75..618dee3 100644
--- a/chrome/browser/ui/startup/startup_browser_creator.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -324,8 +324,7 @@
 
 void ShowUserManager(bool is_process_startup) {
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
-  if (!signin_util::IsForceSigninEnabled() &&
-      base::FeatureList::IsEnabled(features::kNewProfilePicker)) {
+  if (base::FeatureList::IsEnabled(features::kNewProfilePicker)) {
     ProfilePicker::Show(
         is_process_startup
             ? ProfilePicker::EntryPoint::kOnStartup
diff --git a/chrome/browser/ui/startup/startup_browser_creator_corrupt_profiles_browsertest_win.cc b/chrome/browser/ui/startup/startup_browser_creator_corrupt_profiles_browsertest_win.cc
index 7ea3bdfa..cbfd9b6 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_corrupt_profiles_browsertest_win.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_corrupt_profiles_browsertest_win.cc
@@ -26,6 +26,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_launcher.h"
 
@@ -108,9 +109,14 @@
 
 }  // namespace
 
-class StartupBrowserCreatorCorruptProfileTest : public InProcessBrowserTest {
+class StartupBrowserCreatorCorruptProfileTest
+    : public InProcessBrowserTest,
+      public ::testing::WithParamInterface<bool> {
  public:
-  StartupBrowserCreatorCorruptProfileTest() = default;
+  StartupBrowserCreatorCorruptProfileTest() {
+    TestingProfile::SetScopedFeatureListForEphemeralGuestProfiles(
+        scoped_feature_list_, GetParam());
+  }
   StartupBrowserCreatorCorruptProfileTest(
       const StartupBrowserCreatorCorruptProfileTest&) = delete;
   StartupBrowserCreatorCorruptProfileTest& operator=(
@@ -174,11 +180,14 @@
   // In this test fixture, SetUpUserDataDirectory must be handled for all
   // non-PRE_ tests.
   bool SetUpUserDataDirectory() override {
-#define SET_UP_USER_DATA_DIRECTORY_FOR(testname) \
-if (testing::UnitTest::GetInstance()->current_test_info()->name() == \
-    std::string(#testname)) {\
-  return this->SetUpUserDataDirectoryFor ## testname(); \
-}
+    // Drop the param from test name.
+    std::string test_name =
+        testing::UnitTest::GetInstance()->current_test_info()->name();
+    test_name.resize(test_name.length() - 2);
+#define SET_UP_USER_DATA_DIRECTORY_FOR(testname)        \
+  if (test_name == std::string(#testname)) {            \
+    return this->SetUpUserDataDirectoryFor##testname(); \
+  }
 
     SET_UP_USER_DATA_DIRECTORY_FOR(LastOpenedProfileMissing);
     SET_UP_USER_DATA_DIRECTORY_FOR(LastUsedProfileFallbackToLastOpenedProfiles);
@@ -213,6 +222,7 @@
  private:
   bool test_body_has_run_ = false;
   bool expect_test_body_to_run_ = true;
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 // Most of the tests below have three sections:
@@ -231,7 +241,7 @@
 // LastOpenedProfileMissing : If any last opened profile is missing, that
 // profile is skipped, but other last opened profiles should be opened in the
 // browser.
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
+IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorCorruptProfileTest,
                        PRE_LastOpenedProfileMissing) {
   CreateAndSwitchToProfile("Profile 1");
   CreateAndSwitchToProfile("Profile 2");
@@ -243,14 +253,14 @@
          RemoveCreateDirectoryPermissionForUserDataDirectory();
 }
 
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
+IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorCorruptProfileTest,
                        LastOpenedProfileMissing) {
   CheckBrowserWindows({"Default", "Profile 2"});
 }
 
 // LastUsedProfileFallbackToLastOpenedProfiles : If the last used profile is
 // missing, it should fall back to any last opened profiles.
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
+IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorCorruptProfileTest,
                        PRE_LastUsedProfileFallbackToLastOpenedProfiles) {
   CreateAndSwitchToProfile("Profile 1");
   CreateAndSwitchToProfile("Profile 2");
@@ -262,7 +272,7 @@
          RemoveCreateDirectoryPermissionForUserDataDirectory();
 }
 
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
+IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorCorruptProfileTest,
                        LastUsedProfileFallbackToLastOpenedProfiles) {
   CheckBrowserWindows({"Default", "Profile 1"});
 }
@@ -270,7 +280,7 @@
 // LastUsedProfileFallbackToUserManager : If all last opened profiles are
 // missing, it should fall back to user manager. To open the user manager, both
 // the guest profile and the system profile must be creatable.
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
+IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorCorruptProfileTest,
                        PRE_LastUsedProfileFallbackToUserManager) {
   CreateAndSwitchToProfile("Profile 1");
   CloseBrowsersSynchronouslyForProfileBasePath("Profile 1");
@@ -288,16 +298,23 @@
          RemoveCreateDirectoryPermissionForUserDataDirectory();
 }
 
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
+IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorCorruptProfileTest,
                        LastUsedProfileFallbackToUserManager) {
+  // TODO(https://crbug.com/1125474): Update the test to cover Ephemeral Guest
+  // profiles.
+  // The current test logic is not suitable when ephemeral test profiles are
+  // enabled. Ephemeral Guest profiles do not have a fixed directory and
+  // removing create-directory permission from user data directory will prevent
+  // creation of the Guest profile.
+  if (GetParam())
+    return;
   CheckBrowserWindows({});
   ExpectUserManagerToShow();
 }
 
-
 // CannotCreateSystemProfile : If the system profile cannot be created, the user
 // manager should not be shown. Fallback to any other profile.
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
+IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorCorruptProfileTest,
                        PRE_CannotCreateSystemProfile) {
   CreateAndSwitchToProfile("Profile 1");
   CloseBrowsersSynchronouslyForProfileBasePath("Profile 1");
@@ -317,14 +334,14 @@
          RemoveCreateDirectoryPermissionForUserDataDirectory();
 }
 
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
+IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorCorruptProfileTest,
                        CannotCreateSystemProfile) {
   CheckBrowserWindows({"Profile 1"});
 }
 
 // LastUsedProfileFallbackToAnyProfile : If all the last opened profiles and the
 // guest profile cannot be opened, fall back to any profile that is not locked.
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
+IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorCorruptProfileTest,
                        PRE_LastUsedProfileFallbackToAnyProfile) {
   CreateAndSwitchToProfile("Profile 1");
   CloseBrowsersSynchronouslyForProfileBasePath("Profile 1");
@@ -338,7 +355,7 @@
          RemoveCreateDirectoryPermissionForUserDataDirectory();
 }
 
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
+IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorCorruptProfileTest,
                        LastUsedProfileFallbackToAnyProfile) {
   CheckBrowserWindows({"Profile 1"});
 }
@@ -351,7 +368,7 @@
   return RemoveCreateDirectoryPermissionForUserDataDirectory();
 }
 
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
+IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorCorruptProfileTest,
                        LastUsedProfileFallbackFail) {
   ADD_FAILURE() << "Test body is not expected to run.";
 }
@@ -359,7 +376,7 @@
 // DoNotStartLockedProfile : Profiles that are locked should never be
 // initialized. Since there are no unlocked profiles, the browser should not
 // start.
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
+IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorCorruptProfileTest,
                        PRE_DoNotStartLockedProfile) {
   // Lock the default profile. The user manager is shown after the profile is
   // locked.
@@ -375,7 +392,7 @@
   return RemoveCreateDirectoryPermissionForUserDataDirectory();
 }
 
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
+IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorCorruptProfileTest,
                        DoNotStartLockedProfile) {
   ADD_FAILURE() << "Test body is not expected to run.";
 }
@@ -383,7 +400,7 @@
 // NoFallbackForUserSelectedProfile : No fallback should be attempted if the
 // profile is selected by the --profile-directory switch. The browser should not
 // start if the specified profile could not be initialized.
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
+IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorCorruptProfileTest,
                        PRE_NoFallbackForUserSelectedProfile) {
   CreateAndSwitchToProfile("Profile 1");
   CreateAndSwitchToProfile("Profile 2");
@@ -398,7 +415,7 @@
          RemoveCreateDirectoryPermissionForUserDataDirectory();
 }
 
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
+IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorCorruptProfileTest,
                        NoFallbackForUserSelectedProfile) {
   ADD_FAILURE() << "Test body is not expected to run.";
 }
@@ -407,7 +424,7 @@
 // ProfileAttributesStorage is missing, it means the profile is deleted. The
 // browser should not attempt to open the profile, but should show the user
 // manager instead.
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
+IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorCorruptProfileTest,
                        PRE_DeletedProfileFallbackToUserManager) {
   base::ScopedAllowBlockingForTesting allow_blocking;
   ASSERT_TRUE(base::CreateDirectory(ProfileManager::GetGuestProfilePath()));
@@ -423,8 +440,12 @@
 }
 
 // Flaky: https://crbug.com/951787
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
+IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorCorruptProfileTest,
                        DISABLED_DeletedProfileFallbackToUserManager) {
   CheckBrowserWindows({});
   ExpectUserManagerToShow();
 }
+
+INSTANTIATE_TEST_SUITE_P(AllGuestTypes,
+                         StartupBrowserCreatorCorruptProfileTest,
+                         /*is_ephemeral=*/testing::Bool());
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.cc b/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.cc
index 1c9a3f6..c8cd4c6 100644
--- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.cc
+++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.cc
@@ -124,9 +124,8 @@
 
 void AppInfoFooterPanel::CreateShortcuts() {
   DCHECK(CanCreateShortcuts(app_));
-  chrome::ShowCreateChromeAppShortcutsDialog(
-      GetWidget()->GetNativeWindow(), profile_, app_,
-      base::RepeatingCallback<void(bool)>());
+  chrome::ShowCreateChromeAppShortcutsDialog(GetWidget()->GetNativeWindow(),
+                                             profile_, app_, base::DoNothing());
 }
 
 // static
diff --git a/chrome/browser/ui/views/create_application_shortcut_view.cc b/chrome/browser/ui/views/create_application_shortcut_view.cc
index 40f15b75..7c4fb9bad 100644
--- a/chrome/browser/ui/views/create_application_shortcut_view.cc
+++ b/chrome/browser/ui/views/create_application_shortcut_view.cc
@@ -34,20 +34,22 @@
     gfx::NativeWindow parent_window,
     Profile* profile,
     const extensions::Extension* app,
-    const base::RepeatingCallback<void(bool)>& close_callback) {
+    base::OnceCallback<void(bool)> close_callback) {
   constrained_window::CreateBrowserModalDialogViews(
-      new CreateChromeApplicationShortcutView(profile, app, close_callback),
-      parent_window)->Show();
+      new CreateChromeApplicationShortcutView(profile, app,
+                                              std::move(close_callback)),
+      parent_window)
+      ->Show();
 }
 
 void ShowCreateChromeAppShortcutsDialog(
     gfx::NativeWindow parent_window,
     Profile* profile,
     const std::string& web_app_id,
-    const base::RepeatingCallback<void(bool)>& close_callback) {
+    base::OnceCallback<void(bool)> close_callback) {
   constrained_window::CreateBrowserModalDialogViews(
       new CreateChromeApplicationShortcutView(profile, web_app_id,
-                                              close_callback),
+                                              std::move(close_callback)),
       parent_window)
       ->Show();
 }
@@ -57,8 +59,8 @@
 CreateChromeApplicationShortcutView::CreateChromeApplicationShortcutView(
     Profile* profile,
     const extensions::Extension* app,
-    const base::RepeatingCallback<void(bool)>& close_callback)
-    : CreateChromeApplicationShortcutView(profile, close_callback) {
+    base::OnceCallback<void(bool)> close_callback)
+    : CreateChromeApplicationShortcutView(profile, std::move(close_callback)) {
   // Get shortcut and icon information; needed for creating the shortcut.
   web_app::GetShortcutInfoForApp(
       app, profile,
@@ -69,8 +71,8 @@
 CreateChromeApplicationShortcutView::CreateChromeApplicationShortcutView(
     Profile* profile,
     const std::string& web_app_id,
-    const base::RepeatingCallback<void(bool)>& close_callback)
-    : CreateChromeApplicationShortcutView(profile, close_callback) {
+    base::OnceCallback<void(bool)> close_callback)
+    : CreateChromeApplicationShortcutView(profile, std::move(close_callback)) {
   web_app::WebAppProvider* provider = web_app::WebAppProvider::Get(profile);
   provider->os_integration_manager().GetShortcutInfoForApp(
       web_app_id,
@@ -80,8 +82,8 @@
 
 CreateChromeApplicationShortcutView::CreateChromeApplicationShortcutView(
     Profile* profile,
-    const base::RepeatingCallback<void(bool)>& close_callback)
-    : profile_(profile), close_callback_(close_callback) {
+    base::OnceCallback<void(bool)> close_callback)
+    : profile_(profile), close_callback_(std::move(close_callback)) {
   SetButtonLabel(ui::DIALOG_BUTTON_OK,
                  l10n_util::GetStringUTF16(IDS_CREATE_SHORTCUTS_COMMIT));
   set_margins(ChromeLayoutProvider::Get()->GetDialogInsetsForContentType(
@@ -91,7 +93,7 @@
                      base::Unretained(this)));
   auto canceled = [](CreateChromeApplicationShortcutView* dialog) {
     if (!dialog->close_callback_.is_null())
-      dialog->close_callback_.Run(false);
+      std::move(dialog->close_callback_).Run(false);
   };
   SetCancelCallback(base::BindOnce(canceled, base::Unretained(this)));
   SetCloseCallback(base::BindOnce(canceled, base::Unretained(this)));
@@ -219,7 +221,7 @@
   DCHECK(IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
 
   if (!close_callback_.is_null())
-    close_callback_.Run(/*success=*/shortcut_info_ != nullptr);
+    std::move(close_callback_).Run(/*success=*/shortcut_info_ != nullptr);
 
   // Shortcut can't be created because app info hasn't been loaded.
   if (!shortcut_info_)
diff --git a/chrome/browser/ui/views/create_application_shortcut_view.h b/chrome/browser/ui/views/create_application_shortcut_view.h
index ac4eb5a..20c9b85f6 100644
--- a/chrome/browser/ui/views/create_application_shortcut_view.h
+++ b/chrome/browser/ui/views/create_application_shortcut_view.h
@@ -31,11 +31,11 @@
   CreateChromeApplicationShortcutView(
       Profile* profile,
       const extensions::Extension* app,
-      const base::RepeatingCallback<void(bool)>& close_callback);
+      base::OnceCallback<void(bool)> close_callback);
   CreateChromeApplicationShortcutView(
       Profile* profile,
       const std::string& web_app_id,
-      const base::RepeatingCallback<void(bool)>& close_callback);
+      base::OnceCallback<void(bool)> close_callback);
   ~CreateChromeApplicationShortcutView() override;
 
   // Initialize the controls on the dialog.
@@ -48,9 +48,8 @@
   base::string16 GetWindowTitle() const override;
 
  private:
-  CreateChromeApplicationShortcutView(
-      Profile* profile,
-      const base::RepeatingCallback<void(bool)>& cb);
+  CreateChromeApplicationShortcutView(Profile* profile,
+                                      base::OnceCallback<void(bool)> cb);
 
   // Creates a new check-box with the given text and checked state.
   std::unique_ptr<views::Checkbox> AddCheckbox(const base::string16& text,
@@ -66,7 +65,7 @@
   // Profile in which the shortcuts will be created.
   Profile* profile_;
 
-  base::RepeatingCallback<void(bool)> close_callback_;
+  base::OnceCallback<void(bool)> close_callback_;
 
   // May be null if the platform doesn't support a particular location.
   views::Checkbox* desktop_check_box_ = nullptr;
diff --git a/chrome/browser/ui/views/crypto_module_password_dialog_view.cc b/chrome/browser/ui/views/crypto_module_password_dialog_view.cc
index 0ceba25..ad467720 100644
--- a/chrome/browser/ui/views/crypto_module_password_dialog_view.cc
+++ b/chrome/browser/ui/views/crypto_module_password_dialog_view.cc
@@ -23,18 +23,22 @@
     const std::string& slot_name,
     CryptoModulePasswordReason reason,
     const std::string& hostname,
-    const CryptoModulePasswordCallback& callback)
-    : callback_(callback) {
+    CryptoModulePasswordCallback callback)
+    : callback_(std::move(callback)) {
   SetButtonLabel(
       ui::DIALOG_BUTTON_OK,
       l10n_util::GetStringUTF16(IDS_CRYPTO_MODULE_AUTH_DIALOG_OK_BUTTON_LABEL));
   SetAcceptCallback(base::BindOnce(
       [](CryptoModulePasswordDialogView* dialog) {
-        dialog->callback_.Run(
-            base::UTF16ToUTF8(dialog->password_entry_->GetText()));
+        std::move(dialog->callback_)
+            .Run(base::UTF16ToUTF8(dialog->password_entry_->GetText()));
       },
       base::Unretained(this)));
-  SetCancelCallback(base::BindOnce(callback_, std::string()));
+  SetCancelCallback(base::BindOnce(
+      [](CryptoModulePasswordDialogView* dialog) {
+        std::move(dialog->callback_).Run(std::string());
+      },
+      base::Unretained(this)));
   set_margins(ChromeLayoutProvider::Get()->GetDialogInsetsForContentType(
       views::TEXT, views::CONTROL));
   Init(hostname, slot_name, reason);
@@ -144,14 +148,13 @@
   password_entry_ = layout->AddView(std::move(password_entry));
 }
 
-void ShowCryptoModulePasswordDialog(
-    const std::string& slot_name,
-    bool retry,
-    CryptoModulePasswordReason reason,
-    const std::string& hostname,
-    gfx::NativeWindow parent,
-    const CryptoModulePasswordCallback& callback) {
-  CryptoModulePasswordDialogView* dialog =
-      new CryptoModulePasswordDialogView(slot_name, reason, hostname, callback);
-  views::DialogDelegate::CreateDialogWidget(dialog, NULL, parent)->Show();
+void ShowCryptoModulePasswordDialog(const std::string& slot_name,
+                                    bool retry,
+                                    CryptoModulePasswordReason reason,
+                                    const std::string& hostname,
+                                    gfx::NativeWindow parent,
+                                    CryptoModulePasswordCallback callback) {
+  CryptoModulePasswordDialogView* dialog = new CryptoModulePasswordDialogView(
+      slot_name, reason, hostname, std::move(callback));
+  views::DialogDelegate::CreateDialogWidget(dialog, nullptr, parent)->Show();
 }
diff --git a/chrome/browser/ui/views/crypto_module_password_dialog_view.h b/chrome/browser/ui/views/crypto_module_password_dialog_view.h
index 48fb0bc9..a6fd44fe2 100644
--- a/chrome/browser/ui/views/crypto_module_password_dialog_view.h
+++ b/chrome/browser/ui/views/crypto_module_password_dialog_view.h
@@ -24,7 +24,7 @@
   CryptoModulePasswordDialogView(const std::string& slot_name,
                                  CryptoModulePasswordReason reason,
                                  const std::string& server,
-                                 const CryptoModulePasswordCallback& callback);
+                                 CryptoModulePasswordCallback callback);
 
   ~CryptoModulePasswordDialogView() override;
 
@@ -54,7 +54,7 @@
   views::Label* password_label_;
   views::Textfield* password_entry_;
 
-  const CryptoModulePasswordCallback callback_;
+  CryptoModulePasswordCallback callback_;
 
   DISALLOW_COPY_AND_ASSIGN(CryptoModulePasswordDialogView);
 };
diff --git a/chrome/browser/ui/views/crypto_module_password_dialog_view_unittest.cc b/chrome/browser/ui/views/crypto_module_password_dialog_view_unittest.cc
index 82eb37f..2810331 100644
--- a/chrome/browser/ui/views/crypto_module_password_dialog_view_unittest.cc
+++ b/chrome/browser/ui/views/crypto_module_password_dialog_view_unittest.cc
@@ -17,9 +17,10 @@
 using CryptoModulePasswordDialogViewTest = ChromeViewsTestBase;
 
 std::unique_ptr<CryptoModulePasswordDialogView> CreateCryptoDialog(
-    const CryptoModulePasswordCallback& callback) {
+    CryptoModulePasswordCallback callback) {
   return std::make_unique<CryptoModulePasswordDialogView>(
-      "slot", kCryptoModulePasswordCertEnrollment, "server", callback);
+      "slot", kCryptoModulePasswordCertEnrollment, "server",
+      std::move(callback));
 }
 
 TEST_F(CryptoModulePasswordDialogViewTest, AcceptUsesPassword) {
diff --git a/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view.cc b/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view.cc
index a0423fa..940637d2 100644
--- a/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view.cc
+++ b/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view.cc
@@ -183,14 +183,26 @@
   return std::make_unique<ScopedHandle>(weak_factory_.GetWeakPtr());
 }
 
-void DiceWebSigninInterceptionBubbleView::OnWebUIUserChoice(bool accept) {
-  has_accepted_ = accept;
-  SigninInterceptionResult result = accept
-                                        ? SigninInterceptionResult::kAccepted
-                                        : SigninInterceptionResult::kDeclined;
+void DiceWebSigninInterceptionBubbleView::OnWebUIUserChoice(
+    SigninInterceptionUserChoice user_choice) {
+  SigninInterceptionResult result;
+  switch (user_choice) {
+    case SigninInterceptionUserChoice::kAccept:
+      result = SigninInterceptionResult::kAccepted;
+      has_accepted_ = true;
+      break;
+    case SigninInterceptionUserChoice::kDecline:
+      result = SigninInterceptionResult::kDeclined;
+      has_accepted_ = false;
+      break;
+    case SigninInterceptionUserChoice::kGuest:
+      result = SigninInterceptionResult::kAcceptedWithGuest;
+      has_accepted_ = true;
+  }
+
   RecordInterceptionResult(bubble_parameters_, profile_, result);
   std::move(callback_).Run(result);
-  if (!accept) {
+  if (!has_accepted_) {
     // Only close the dialog when the user declined. If the user accepted the
     // dialog displays a spinner until the handle is released.
     GetWidget()->CloseWithReason(
diff --git a/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view.h b/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view.h
index 43f22b8..afa9a41 100644
--- a/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view.h
+++ b/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view.h
@@ -88,9 +88,9 @@
   std::unique_ptr<ScopedDiceWebSigninInterceptionBubbleHandle> GetHandle()
       const;
 
-  // This bubble has no native buttons. The user accepts or cancels through this
-  // method, which is called by the inner web UI.
-  void OnWebUIUserChoice(bool accept);
+  // This bubble has no native buttons. The user accepts or cancels or selects
+  // Guest profile through this method, which is called by the inner web UI.
+  void OnWebUIUserChoice(SigninInterceptionUserChoice user_choice);
 
   Profile* profile_;
   bool has_accepted_ = false;
diff --git a/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view_browsertest.cc b/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view_browsertest.cc
index 365f523..6251360 100644
--- a/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view_browsertest.cc
@@ -113,7 +113,7 @@
 
   views::test::WidgetDestroyedWaiter waiter(widget);
   // Simulate clicking Cancel in the WebUI.
-  bubble->OnWebUIUserChoice(/*accept=*/false);
+  bubble->OnWebUIUserChoice(SigninInterceptionUserChoice::kDecline);
   waiter.Wait();
   ASSERT_TRUE(callback_result_.has_value());
   EXPECT_EQ(callback_result_, SigninInterceptionResult::kDeclined);
@@ -149,7 +149,7 @@
   views::test::WidgetClosingObserver closing_observer(widget);
   EXPECT_FALSE(bubble->HasAccepted());
   // Simulate clicking Accept in the WebUI.
-  bubble->OnWebUIUserChoice(/*accept=*/true);
+  bubble->OnWebUIUserChoice(SigninInterceptionUserChoice::kAccept);
   ASSERT_TRUE(callback_result_.has_value());
   EXPECT_EQ(callback_result_, SigninInterceptionResult::kAccepted);
   EXPECT_TRUE(bubble->HasAccepted());
@@ -169,3 +169,6 @@
   histogram_tester.ExpectTotalCount("Signin.InterceptResult.Enterprise", 0);
   histogram_tester.ExpectTotalCount("Signin.InterceptResult.Switch", 0);
 }
+
+// TODO(https://crbug.com/1157764): Add Test for Bubble Guest selection when
+// functionality is supported.
diff --git a/chrome/browser/ui/views/profiles/user_manager_view.cc b/chrome/browser/ui/views/profiles/user_manager_view.cc
index ddefcee..695e59ca 100644
--- a/chrome/browser/ui/views/profiles/user_manager_view.cc
+++ b/chrome/browser/ui/views/profiles/user_manager_view.cc
@@ -73,8 +73,7 @@
     profiles::UserManagerAction user_manager_action) {
   DCHECK(profile_path_to_focus != ProfileManager::GetGuestProfilePath());
 
-  if (!signin_util::IsForceSigninEnabled() &&
-      (user_manager_action == profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION ||
+  if ((user_manager_action == profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION ||
        user_manager_action == profiles::USER_MANAGER_OPEN_CREATE_USER_PAGE) &&
       base::FeatureList::IsEnabled(features::kNewProfilePicker)) {
     // Use the new profile picker instead.
@@ -170,10 +169,10 @@
 
 // static
 base::FilePath UserManager::GetSigninProfilePath() {
-  if (!g_user_manager_view)
-    return base::FilePath();
+  if (g_user_manager_view)
+    return g_user_manager_view->GetSigninProfilePath();
 
-  return g_user_manager_view->GetSigninProfilePath();
+  return ProfilePicker::GetForceSigninProfilePath();
 }
 
 // UserManagerProfileDialog
@@ -207,34 +206,54 @@
 void UserManagerProfileDialog::ShowForceSigninDialog(
     content::BrowserContext* browser_context,
     const base::FilePath& profile_path) {
-  if (!UserManager::IsShowing())
-    return;
   GURL url = signin::GetEmbeddedPromoURL(
       signin_metrics::AccessPoint::ACCESS_POINT_USER_MANAGER,
       signin_metrics::Reason::REASON_FORCED_SIGNIN_PRIMARY_ACCOUNT, true);
+
+  if (base::FeatureList::IsEnabled(features::kNewProfilePicker)) {
+    // Use the new profile picker instead.
+    ProfilePicker::ShowDialog(browser_context, url, profile_path);
+    return;
+  }
+
+  if (!UserManager::IsShowing())
+    return;
   g_user_manager_view->ShowDialog(browser_context, url, profile_path);
 }
 
 void UserManagerProfileDialog::ShowDialogAndDisplayErrorMessage(
     content::BrowserContext* browser_context) {
+  GURL url(chrome::kChromeUISigninErrorURL);
+
+  if (base::FeatureList::IsEnabled(features::kNewProfilePicker)) {
+    // Use the new profile picker instead.
+    ProfilePicker::ShowDialog(browser_context, url, base::FilePath());
+    return;
+  }
+
   if (!UserManager::IsShowing())
     return;
   // The error occurred before sign in happened, use an empty profile path
   // so that the error page will show the error message that is assoicated with
   // the system profile.
-  g_user_manager_view->ShowDialog(
-      browser_context, GURL(chrome::kChromeUISigninErrorURL), base::FilePath());
+  g_user_manager_view->ShowDialog(browser_context, url, base::FilePath());
 }
 
 // static
 void UserManagerProfileDialog::DisplayErrorMessage() {
-  // This method should only be called if the user manager is already showing.
-  DCHECK(g_user_manager_view);
-  g_user_manager_view->DisplayErrorMessage();
+  ProfilePicker::DisplayErrorMessage();
+
+  if (g_user_manager_view) {
+    g_user_manager_view->DisplayErrorMessage();
+  }
 }
 
 // static
 void UserManagerProfileDialog::HideDialog() {
+  // Hide the profile picker dialog, in case it was opened by
+  // UserManagerProfileDialog::ShowDialog*().
+  ProfilePicker::HideDialog();
+
   if (g_user_manager_view && g_user_manager_view->GetWidget()->IsVisible())
     g_user_manager_view->HideDialog();
 }
diff --git a/chrome/browser/ui/webui/invalidations/invalidations_ui.cc b/chrome/browser/ui/webui/invalidations/invalidations_ui.cc
index d76c0a0e..55cbab4 100644
--- a/chrome/browser/ui/webui/invalidations/invalidations_ui.cc
+++ b/chrome/browser/ui/webui/invalidations/invalidations_ui.cc
@@ -26,8 +26,11 @@
   source->OverrideContentSecurityPolicy(
       network::mojom::CSPDirectiveName::TrustedTypes,
       "trusted-types jstemplate;");
-  source->AddResourcePath("about_invalidations.js", IDR_ABOUT_INVALIDATIONS_JS);
-  source->SetDefaultResource(IDR_ABOUT_INVALIDATIONS_HTML);
+  source->AddResourcePath("about_invalidations.js",
+                          IDR_INVALIDATIONS_ABOUT_INVALIDATIONS_JS);
+  source->AddResourcePath("about_invalidations.css",
+                          IDR_INVALIDATIONS_ABOUT_INVALIDATIONS_CSS);
+  source->SetDefaultResource(IDR_INVALIDATIONS_ABOUT_INVALIDATIONS_HTML);
   return source;
 }
 
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
index 1e365ff5..38aa9336 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -956,7 +956,7 @@
         chrome::FindBrowserWithWebContents(web_ui()->GetWebContents());
     chrome::ShowCreateChromeAppShortcutsDialog(
         browser->window()->GetNativeWindow(), browser->profile(), app_id,
-        base::BindRepeating([](bool success) {
+        base::BindOnce([](bool success) {
           base::UmaHistogramBoolean(
               "Apps.AppInfoDialog.CreateWebAppShortcutSuccess", success);
         }));
@@ -977,7 +977,7 @@
         web_ui()->GetWebContents());
   chrome::ShowCreateChromeAppShortcutsDialog(
       browser->window()->GetNativeWindow(), browser->profile(), extension,
-      base::BindRepeating([](bool success) {
+      base::BindOnce([](bool success) {
         base::UmaHistogramBoolean(
             "Apps.AppInfoDialog.CreateExtensionShortcutSuccess", success);
       }));
diff --git a/chrome/browser/ui/webui/profile_helper.cc b/chrome/browser/ui/webui/profile_helper.cc
index e54db3e49..6327f7d 100644
--- a/chrome/browser/ui/webui/profile_helper.cc
+++ b/chrome/browser/ui/webui/profile_helper.cc
@@ -26,32 +26,6 @@
 namespace webui {
 namespace {
 
-void ShowUserManager(const ProfileManager::CreateCallback& callback) {
-  if (!UserManager::IsShowing()) {
-    UserManager::Show(base::FilePath(),
-                      profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
-  }
-
-  g_browser_process->profile_manager()->CreateProfileAsync(
-      ProfileManager::GetSystemProfilePath(), callback, base::string16(),
-      std::string());
-}
-
-std::string GetProfileUserName(Profile* profile) {
-  ProfileAttributesEntry* entry;
-  if (!g_browser_process->profile_manager()
-           ->GetProfileAttributesStorage()
-           .GetProfileAttributesWithPath(profile->GetPath(), &entry))
-    return std::string();
-  return base::UTF16ToUTF8(entry->GetUserName());
-}
-
-void ShowUnlockDialog(const std::string& user_name,
-                      Profile* system_profile,
-                      Profile::CreateStatus status) {
-  UserManagerProfileDialog::ShowUnlockDialog(system_profile, user_name);
-}
-
 void DeleteProfileCallback(std::unique_ptr<ScopedKeepAlive> keep_alive,
                            Profile* profile) {
   OpenNewWindowForProfile(profile);
@@ -61,17 +35,16 @@
 
 void OpenNewWindowForProfile(Profile* profile) {
   if (profiles::IsProfileLocked(profile->GetPath())) {
-    // The profile picker does not support locked profiles.
-    DCHECK(!ProfilePicker::IsOpen());
-
-    if (signin_util::IsForceSigninEnabled()) {
-      // If force-sign-in policy is enabled, UserManager will be displayed
-      // without any sign-in dialog opened.
-      ShowUserManager(ProfileManager::CreateCallback());
-    } else {
-      ShowUserManager(
-          base::BindRepeating(&ShowUnlockDialog, GetProfileUserName(profile)));
+    DCHECK(signin_util::IsForceSigninEnabled());
+    // Displays the UserManager without any sign-in dialog opened.
+    if (!UserManager::IsShowing() && !ProfilePicker::IsOpen()) {
+      UserManager::Show(base::FilePath(),
+                        profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
     }
+
+    g_browser_process->profile_manager()->CreateProfileAsync(
+        ProfileManager::GetSystemProfilePath(),
+        ProfileManager::CreateCallback(), base::string16(), std::string());
     return;
   }
 
diff --git a/chrome/browser/ui/webui/settings/chromeos/switch_access_handler.cc b/chrome/browser/ui/webui/settings/chromeos/switch_access_handler.cc
index 05b573b0..edb3a14 100644
--- a/chrome/browser/ui/webui/settings/chromeos/switch_access_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/switch_access_handler.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/ui/webui/settings/chromeos/switch_access_handler.h"
 
 #include "ash/public/cpp/accessibility_controller.h"
-#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "base/bind.h"
 #include "base/no_destructor.h"
@@ -15,8 +14,6 @@
 #include "content/public/browser/web_contents.h"
 #include "ui/aura/window.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/events/devices/device_data_manager.h"
-#include "ui/events/devices/input_device.h"
 #include "ui/events/event.h"
 #include "ui/events/event_constants.h"
 #include "ui/events/keycodes/dom/dom_code.h"
@@ -55,19 +52,6 @@
   return std::string();
 }
 
-std::string GetSwitchAccessDevice(ui::InputDeviceType source_device_type) {
-  switch (source_device_type) {
-    case ui::INPUT_DEVICE_INTERNAL:
-      return ash::kSwitchAccessInternalDevice;
-    case ui::INPUT_DEVICE_USB:
-      return ash::kSwitchAccessUsbDevice;
-    case ui::INPUT_DEVICE_BLUETOOTH:
-      return ash::kSwitchAccessBluetoothDevice;
-    case ui::INPUT_DEVICE_UNKNOWN:
-      return ash::kSwitchAccessUnknownDevice;
-  }
-}
-
 }  // namespace
 
 SwitchAccessHandler::SwitchAccessHandler(PrefService* prefs) : prefs_(prefs) {}
@@ -107,17 +91,17 @@
   pref_change_registrar_.reset(new PrefChangeRegistrar);
   pref_change_registrar_->Init(prefs_);
   pref_change_registrar_->Add(
-      ash::prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes,
+      ash::prefs::kAccessibilitySwitchAccessSelectKeyCodes,
       base::BindRepeating(
           &SwitchAccessHandler::OnSwitchAccessAssignmentsUpdated,
           base::Unretained(this)));
   pref_change_registrar_->Add(
-      ash::prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes,
+      ash::prefs::kAccessibilitySwitchAccessNextKeyCodes,
       base::BindRepeating(
           &SwitchAccessHandler::OnSwitchAccessAssignmentsUpdated,
           base::Unretained(this)));
   pref_change_registrar_->Add(
-      ash::prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes,
+      ash::prefs::kAccessibilitySwitchAccessPreviousKeyCodes,
       base::BindRepeating(
           &SwitchAccessHandler::OnSwitchAccessAssignmentsUpdated,
           base::Unretained(this)));
@@ -138,14 +122,9 @@
   response.SetIntPath("keyCode", static_cast<int>(event->key_code()));
   response.SetStringPath("key", GetStringForKeyboardCode(event->key_code()));
 
-  int source_device_id = event->source_device_id();
-  for (const auto& keyboard :
-       ui::DeviceDataManager::GetInstance()->GetKeyboardDevices()) {
-    if (source_device_id == keyboard.id) {
-      response.SetStringPath("device", GetSwitchAccessDevice(keyboard.type));
-      break;
-    }
-  }
+  // TODO(accessibility): also include the device type once Switch Access can
+  // distinguish between internal, usb, and bluetooth keyboards for each action
+  // type.
 
   FireWebUIListener("switch-access-got-key-press-for-assignment", response);
 }
@@ -176,27 +155,17 @@
   base::DictionaryValue response;
 
   static base::NoDestructor<std::vector<AssignmentInfo>> kAssignmentInfo({
-      {"select", ash::prefs::kAccessibilitySwitchAccessSelectDeviceKeyCodes},
-      {"next", ash::prefs::kAccessibilitySwitchAccessNextDeviceKeyCodes},
-      {"previous",
-       ash::prefs::kAccessibilitySwitchAccessPreviousDeviceKeyCodes},
+      {"select", ash::prefs::kAccessibilitySwitchAccessSelectKeyCodes},
+      {"next", ash::prefs::kAccessibilitySwitchAccessNextKeyCodes},
+      {"previous", ash::prefs::kAccessibilitySwitchAccessPreviousKeyCodes},
   });
 
   for (const AssignmentInfo& info : *kAssignmentInfo) {
-    auto* keycodes = prefs_->GetDictionary(info.pref_name);
+    auto* keycodes = prefs_->GetList(info.pref_name);
     base::ListValue keys;
-    for (const auto& item : keycodes->DictItems()) {
-      base::DictionaryValue key;
-      int key_code;
-      if (!base::StringToInt(item.first, &key_code)) {
-        NOTREACHED();
-        return;
-      }
-      key.SetStringPath("key", GetStringForKeyboardCode(
-                                   static_cast<ui::KeyboardCode>(key_code)));
-      key.SetPath("devices", item.second.Clone());
-
-      keys.Append(std::move(key));
+    for (size_t i = 0; i < keycodes->GetList().size(); i++) {
+      keys.Append(GetStringForKeyboardCode(
+          static_cast<ui::KeyboardCode>(keycodes->GetList()[i].GetInt())));
     }
     response.SetPath(info.action_name_for_js, std::move(keys));
   }
diff --git a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
index 53db045..50df7db 100644
--- a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
+++ b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
@@ -443,6 +443,7 @@
       std::make_unique<DiceSignedInProfileCreator>(
           profile_, account_info_.account_id,
           /*local_profile_name=*/base::string16(), /*icon_index=*/base::nullopt,
+          /*use_guest=*/false,
           base::BindOnce(&DiceTurnSyncOnHelper::OnNewSignedInProfileCreated,
                          base::Unretained(this)));
 }
diff --git a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler.cc b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler.cc
index d831da0..c09e8d0 100644
--- a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler.cc
+++ b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler.cc
@@ -35,7 +35,7 @@
 DiceWebSigninInterceptHandler::DiceWebSigninInterceptHandler(
     const DiceWebSigninInterceptor::Delegate::BubbleParameters&
         bubble_parameters,
-    base::OnceCallback<void(bool)> callback)
+    base::OnceCallback<void(SigninInterceptionUserChoice)> callback)
     : bubble_parameters_(bubble_parameters), callback_(std::move(callback)) {
   DCHECK(callback_);
 }
@@ -100,19 +100,17 @@
 
 void DiceWebSigninInterceptHandler::HandleAccept(const base::ListValue* args) {
   if (callback_)
-    std::move(callback_).Run(true);
+    std::move(callback_).Run(SigninInterceptionUserChoice::kAccept);
 }
 
 void DiceWebSigninInterceptHandler::HandleCancel(const base::ListValue* args) {
   if (callback_)
-    std::move(callback_).Run(false);
+    std::move(callback_).Run(SigninInterceptionUserChoice::kDecline);
 }
 
 void DiceWebSigninInterceptHandler::HandleGuest(const base::ListValue* args) {
-  // TODO(https://crbug.com/1157764): Update the callback to have 3 states and
-  // return 'Guest' state.
   if (callback_)
-    std::move(callback_).Run(true);
+    std::move(callback_).Run(SigninInterceptionUserChoice::kGuest);
 }
 
 void DiceWebSigninInterceptHandler::HandlePageLoaded(
diff --git a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler.h b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler.h
index 47b834a..14faaa0e 100644
--- a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler.h
+++ b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler.h
@@ -27,7 +27,7 @@
   DiceWebSigninInterceptHandler(
       const DiceWebSigninInterceptor::Delegate::BubbleParameters&
           bubble_parameters,
-      base::OnceCallback<void(bool)> callback);
+      base::OnceCallback<void(SigninInterceptionUserChoice)> callback);
   ~DiceWebSigninInterceptHandler() override;
 
   DiceWebSigninInterceptHandler(const DiceWebSigninInterceptHandler&) = delete;
@@ -63,7 +63,7 @@
       identity_observer_{this};
   DiceWebSigninInterceptor::Delegate::BubbleParameters bubble_parameters_;
 
-  base::OnceCallback<void(bool)> callback_;
+  base::OnceCallback<void(SigninInterceptionUserChoice)> callback_;
 };
 
 #endif  // CHROME_BROWSER_UI_WEBUI_SIGNIN_DICE_WEB_SIGNIN_INTERCEPT_HANDLER_H_
diff --git a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_ui.cc b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_ui.cc
index 4a2e829..f8e2153 100644
--- a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_ui.cc
+++ b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_ui.cc
@@ -58,7 +58,7 @@
 void DiceWebSigninInterceptUI::Initialize(
     const DiceWebSigninInterceptor::Delegate::BubbleParameters&
         bubble_parameters,
-    base::OnceCallback<void(bool)> callback) {
+    base::OnceCallback<void(SigninInterceptionUserChoice)> callback) {
   web_ui()->AddMessageHandler(std::make_unique<DiceWebSigninInterceptHandler>(
       bubble_parameters, std::move(callback)));
 }
diff --git a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_ui.h b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_ui.h
index 697d2551..c2aafa7d 100644
--- a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_ui.h
+++ b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_ui.h
@@ -23,9 +23,10 @@
   DiceWebSigninInterceptUI& operator=(const DiceWebSigninInterceptUI&) = delete;
 
   // Initializes the DiceWebSigninInterceptUI.
-  void Initialize(const DiceWebSigninInterceptor::Delegate::BubbleParameters&
-                      bubble_parameters,
-                  base::OnceCallback<void(bool)> callback);
+  void Initialize(
+      const DiceWebSigninInterceptor::Delegate::BubbleParameters&
+          bubble_parameters,
+      base::OnceCallback<void(SigninInterceptionUserChoice)> callback);
 
   static bool ShouldShowGuestOption();
 
diff --git a/chrome/browser/web_applications/extensions/web_app_extension_shortcut_mac.mm b/chrome/browser/web_applications/extensions/web_app_extension_shortcut_mac.mm
index ca6330c..84073ebb 100644
--- a/chrome/browser/web_applications/extensions/web_app_extension_shortcut_mac.mm
+++ b/chrome/browser/web_applications/extensions/web_app_extension_shortcut_mac.mm
@@ -149,28 +149,28 @@
     gfx::NativeWindow /*parent_window*/,
     Profile* profile,
     const extensions::Extension* app,
-    const base::Callback<void(bool)>& close_callback) {
+    base::OnceCallback<void(bool)> close_callback) {
   // On Mac, the Applications folder is the only option, so don't bother asking
   // the user anything. Just create shortcuts.
   CreateShortcuts(web_app::SHORTCUT_CREATION_BY_USER,
                   web_app::ShortcutLocations(), profile, app,
                   base::DoNothing());
   if (!close_callback.is_null())
-    close_callback.Run(true);
+    std::move(close_callback).Run(true);
 }
 
 void ShowCreateChromeAppShortcutsDialog(
     gfx::NativeWindow /*parent_window*/,
     Profile* profile,
     const std::string& app_id,
-    const base::Callback<void(bool)>& close_callback) {
+    base::OnceCallback<void(bool)> close_callback) {
   // On Mac, the Applications folder is the only option, so don't bother asking
   // the user anything. Just create shortcuts.
   CreateShortcutsForWebApp(web_app::SHORTCUT_CREATION_BY_USER,
                            web_app::ShortcutLocations(), profile, app_id,
                            base::DoNothing());
   if (!close_callback.is_null())
-    close_callback.Run(true);
+    std::move(close_callback).Run(true);
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/webapps/android/BUILD.gn b/chrome/browser/webapps/android/BUILD.gn
new file mode 100644
index 0000000..0c5451f1
--- /dev/null
+++ b/chrome/browser/webapps/android/BUILD.gn
@@ -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.
+
+import("//build/config/android/config.gni")
+import("//build/config/android/rules.gni")
+
+source_set("android") {
+  sources = [
+    "features.cc",
+    "features.h",
+    "pwa_bottom_sheet_controller.cc",
+    "pwa_bottom_sheet_controller.h",
+  ]
+
+  deps = [
+    "//base",
+    "//chrome/browser/webapps/android:jni_headers",
+    "//components/url_formatter:url_formatter",
+    "//components/webapps:webapps",
+    "//content/public/browser:browser",
+    "//services/device/public/mojom",
+    "//skia",
+    "//third_party/blink/public/common:common",
+  ]
+}
+
+android_library("java") {
+  resources_package = "org.chromium.chrome.browser.webapps"
+
+  sources = [
+    "java/src/org/chromium/chrome/browser/webapps/AddToHomescreenBottomSheetViewBinder.java",
+    "java/src/org/chromium/chrome/browser/webapps/AddToHomescreenProperties.java",
+    "java/src/org/chromium/chrome/browser/webapps/AddToHomescreenViewDelegate.java",
+    "java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetController.java",
+    "java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerFactory.java",
+    "java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerProvider.java",
+    "java/src/org/chromium/chrome/browser/webapps/PwaInstallBottomSheetContent.java",
+    "java/src/org/chromium/chrome/browser/webapps/PwaInstallBottomSheetView.java",
+  ]
+
+  deps = [
+    ":java_resources",
+    ":jni_headers",
+    "//base:base_java",
+    "//base:jni_java",
+    "//components/browser_ui/android/bottomsheet:java",
+    "//content/public/android:content_java",
+    "//third_party/android_deps:androidx_annotation_annotation_java",
+    "//third_party/android_deps:androidx_recyclerview_recyclerview_java",
+    "//ui/android:ui_no_recycler_view_java",
+  ]
+
+  annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
+}
+
+generate_jni("jni_headers") {
+  sources = [
+    "java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetController.java",
+    "java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerProvider.java",
+  ]
+}
+
+android_resources("java_resources") {
+  sources = [
+    "java/res/layout/pwa_install_bottom_sheet_content.xml",
+    "java/res/layout/pwa_install_bottom_sheet_toolbar.xml",
+    "java/res/values/dimens.xml",
+  ]
+  deps = [
+    "//chrome/browser/ui/android/strings:ui_strings_grd",
+    "//components/webapk/android/libs/common:splash_resources",
+  ]
+}
diff --git a/chrome/browser/webapps/android/DEPS b/chrome/browser/webapps/android/DEPS
new file mode 100644
index 0000000..512294e
--- /dev/null
+++ b/chrome/browser/webapps/android/DEPS
@@ -0,0 +1,5 @@
+# External directories and/or files that can be included from this module:
+include_rules = [
+  "+components/browser_ui/android/bottomsheet",
+  "+content/public/android/java/src/org/chromium/content_public/browser",
+]
diff --git a/chrome/browser/webapps/android/features.cc b/chrome/browser/webapps/android/features.cc
new file mode 100644
index 0000000..c1e4a107
--- /dev/null
+++ b/chrome/browser/webapps/android/features.cc
@@ -0,0 +1,14 @@
+// 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/webapps/android/features.h"
+
+namespace webapps {
+namespace features {
+
+const base::Feature kPwaInstallUseBottomSheet{
+    "PwaInstallUseBottomSheet", base::FEATURE_DISABLED_BY_DEFAULT};
+
+}  // namespace features
+}  // namespace webapps
diff --git a/chrome/browser/webapps/android/features.h b/chrome/browser/webapps/android/features.h
new file mode 100644
index 0000000..17a5be0
--- /dev/null
+++ b/chrome/browser/webapps/android/features.h
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEBAPPS_ANDROID_FEATURES_H_
+#define CHROME_BROWSER_WEBAPPS_ANDROID_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace webapps {
+namespace features {
+
+extern const base::Feature kPwaInstallUseBottomSheet;
+
+}  // namespace features
+}  // namespace webapps
+
+#endif  // CHROME_BROWSER_WEBAPPS_ANDROID_FEATURES_H_
diff --git a/chrome/android/java/res/layout/pwa_install_bottom_sheet_content.xml b/chrome/browser/webapps/android/java/res/layout/pwa_install_bottom_sheet_content.xml
similarity index 100%
rename from chrome/android/java/res/layout/pwa_install_bottom_sheet_content.xml
rename to chrome/browser/webapps/android/java/res/layout/pwa_install_bottom_sheet_content.xml
diff --git a/chrome/android/java/res/layout/pwa_install_bottom_sheet_toolbar.xml b/chrome/browser/webapps/android/java/res/layout/pwa_install_bottom_sheet_toolbar.xml
similarity index 100%
rename from chrome/android/java/res/layout/pwa_install_bottom_sheet_toolbar.xml
rename to chrome/browser/webapps/android/java/res/layout/pwa_install_bottom_sheet_toolbar.xml
diff --git a/chrome/browser/webapps/android/java/res/values/dimens.xml b/chrome/browser/webapps/android/java/res/values/dimens.xml
new file mode 100644
index 0000000..720dfd48
--- /dev/null
+++ b/chrome/browser/webapps/android/java/res/values/dimens.xml
@@ -0,0 +1,7 @@
+<!-- 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. -->
+
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <dimen name="webapk_screenshot_margin">20dp</dimen>
+</resources>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenBottomSheetViewBinder.java b/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenBottomSheetViewBinder.java
similarity index 96%
rename from chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenBottomSheetViewBinder.java
rename to chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenBottomSheetViewBinder.java
index de5e03f..92b13f9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenBottomSheetViewBinder.java
+++ b/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenBottomSheetViewBinder.java
@@ -2,7 +2,7 @@
 // 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.webapps.addtohomescreen;
+package org.chromium.chrome.browser.webapps;
 
 import android.graphics.Bitmap;
 import android.util.Pair;
diff --git a/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenProperties.java b/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenProperties.java
new file mode 100644
index 0000000..9b04bff
--- /dev/null
+++ b/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenProperties.java
@@ -0,0 +1,41 @@
+// 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.
+
+package org.chromium.chrome.browser.webapps;
+
+import android.graphics.Bitmap;
+import android.util.Pair;
+import android.view.View.OnClickListener;
+
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel;
+
+/**
+ * Contains the properties that an add-to-homescreen {@link PropertyModel} can have.
+ */
+public class AddToHomescreenProperties {
+    public static final PropertyModel.WritableObjectPropertyKey<String> TITLE =
+            new PropertyModel.WritableObjectPropertyKey<>();
+    public static final PropertyModel.WritableObjectPropertyKey<String> URL =
+            new PropertyModel.WritableObjectPropertyKey<>();
+    public static final PropertyModel.WritableObjectPropertyKey<String> CATEGORIES =
+            new PropertyModel.WritableObjectPropertyKey<>();
+    public static final PropertyModel.WritableObjectPropertyKey<String> DESCRIPTION =
+            new PropertyModel.WritableObjectPropertyKey<>();
+    public static final PropertyModel.WritableObjectPropertyKey<Pair<Bitmap, Boolean>> ICON =
+            new PropertyModel.WritableObjectPropertyKey<>();
+    public static final PropertyModel.WritableIntPropertyKey TYPE =
+            new PropertyModel.WritableIntPropertyKey();
+    public static final PropertyModel.WritableBooleanPropertyKey CAN_SUBMIT =
+            new PropertyModel.WritableBooleanPropertyKey();
+    public static final PropertyModel.WritableObjectPropertyKey<OnClickListener> CLICK_LISTENER =
+            new PropertyModel.WritableObjectPropertyKey<>();
+    public static final PropertyModel.WritableObjectPropertyKey<String> NATIVE_INSTALL_BUTTON_TEXT =
+            new PropertyModel.WritableObjectPropertyKey<>();
+    public static final PropertyModel.WritableFloatPropertyKey NATIVE_APP_RATING =
+            new PropertyModel.WritableFloatPropertyKey();
+
+    public static final PropertyKey[] ALL_KEYS = {TITLE, URL, CATEGORIES, DESCRIPTION, ICON, TYPE,
+            CAN_SUBMIT, CLICK_LISTENER, NATIVE_INSTALL_BUTTON_TEXT, NATIVE_APP_RATING};
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenViewDelegate.java b/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenViewDelegate.java
similarity index 87%
rename from chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenViewDelegate.java
rename to chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenViewDelegate.java
index d0ddcb4..9f5693b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenViewDelegate.java
+++ b/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenViewDelegate.java
@@ -2,13 +2,13 @@
 // 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.webapps.addtohomescreen;
+package org.chromium.chrome.browser.webapps;
 
 /**
  * Used by {@link AddToHomescreenDialogView} to propagate view events to {@link
  * AddToHomescreenMediator}.
  */
-interface AddToHomescreenViewDelegate {
+public interface AddToHomescreenViewDelegate {
     /**
      * Called when the user accepts adding the item to home screen with the provided title.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaBottomSheetController.java b/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetController.java
similarity index 98%
rename from chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaBottomSheetController.java
rename to chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetController.java
index d3bdef0..5144b54d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaBottomSheetController.java
+++ b/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetController.java
@@ -2,7 +2,7 @@
 // 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.webapps.addtohomescreen;
+package org.chromium.chrome.browser.webapps;
 
 import android.app.Activity;
 import android.content.Context;
@@ -18,7 +18,6 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
-import org.chromium.chrome.R;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider;
 import org.chromium.content_public.browser.NavigationHandle;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaBottomSheetControllerFactory.java b/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerFactory.java
similarity index 92%
rename from chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaBottomSheetControllerFactory.java
rename to chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerFactory.java
index 2122a95..fd669d5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaBottomSheetControllerFactory.java
+++ b/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerFactory.java
@@ -2,7 +2,7 @@
 // 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.webapps.addtohomescreen;
+package org.chromium.chrome.browser.webapps;
 
 import android.app.Activity;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaBottomSheetControllerProvider.java b/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerProvider.java
similarity index 95%
rename from chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaBottomSheetControllerProvider.java
rename to chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerProvider.java
index ed947d22..7f3a3ea5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaBottomSheetControllerProvider.java
+++ b/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaBottomSheetControllerProvider.java
@@ -2,7 +2,7 @@
 // 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.webapps.addtohomescreen;
+package org.chromium.chrome.browser.webapps;
 
 import android.graphics.Bitmap;
 
@@ -26,7 +26,7 @@
      * @param windowAndroid The window to pull the controller from.
      * @return A shared instance of a {@link PwaBottomSheetController}.
      */
-    static PwaBottomSheetController from(WindowAndroid windowAndroid) {
+    public static PwaBottomSheetController from(WindowAndroid windowAndroid) {
         return KEY.retrieveDataFromHost(windowAndroid.getUnownedUserDataHost());
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaInstallBottomSheetContent.java b/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaInstallBottomSheetContent.java
similarity index 95%
rename from chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaInstallBottomSheetContent.java
rename to chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaInstallBottomSheetContent.java
index 3f0709a..4cd0860 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaInstallBottomSheetContent.java
+++ b/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaInstallBottomSheetContent.java
@@ -2,14 +2,13 @@
 // 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.webapps.addtohomescreen;
+package org.chromium.chrome.browser.webapps;
 
 import android.view.View;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.chrome.R;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
 
 /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaInstallBottomSheetView.java b/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaInstallBottomSheetView.java
similarity index 90%
rename from chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaInstallBottomSheetView.java
rename to chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaInstallBottomSheetView.java
index 691fd86..50f9c9c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/addtohomescreen/PwaInstallBottomSheetView.java
+++ b/chrome/browser/webapps/android/java/src/org/chromium/chrome/browser/webapps/PwaInstallBottomSheetView.java
@@ -2,7 +2,7 @@
 // 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.webapps.addtohomescreen;
+package org.chromium.chrome.browser.webapps;
 
 import android.annotation.TargetApi;
 import android.content.Context;
@@ -17,8 +17,6 @@
 
 import androidx.recyclerview.widget.RecyclerView;
 
-import org.chromium.chrome.R;
-
 /**
  * The view portion of the PWA Install bottom sheet.
  */
@@ -117,4 +115,19 @@
         mToolbarView.findViewById(R.id.button_install).setOnClickListener(listener);
         mToolbarView.findViewById(R.id.drag_handlebar).setOnClickListener(listener);
     }
+
+    // Testing functions:
+
+    public static int getAppNameViewIdForTesting() {
+        return R.id.app_name;
+    }
+    public static int getAppOriginViewIdForTesting() {
+        return R.id.app_origin;
+    }
+    public static int getDescViewIdForTesting() {
+        return R.id.description;
+    }
+    public static int getCategoriesViewIdForTesting() {
+        return R.id.categories;
+    }
 }
diff --git a/chrome/browser/android/webapps/pwa_bottom_sheet_controller.cc b/chrome/browser/webapps/android/pwa_bottom_sheet_controller.cc
similarity index 93%
rename from chrome/browser/android/webapps/pwa_bottom_sheet_controller.cc
rename to chrome/browser/webapps/android/pwa_bottom_sheet_controller.cc
index 04f013c..c442342b 100644
--- a/chrome/browser/android/webapps/pwa_bottom_sheet_controller.cc
+++ b/chrome/browser/webapps/android/pwa_bottom_sheet_controller.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/webapps/pwa_bottom_sheet_controller.h"
+#include "chrome/browser/webapps/android/pwa_bottom_sheet_controller.h"
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/android/chrome_jni_headers/PwaBottomSheetControllerProvider_jni.h"
-#include "chrome/android/chrome_jni_headers/PwaBottomSheetController_jni.h"
 #include "chrome/browser/banners/app_banner_manager_android.h"
-#include "chrome/browser/flags/android/chrome_feature_list.h"
+#include "chrome/browser/webapps/android/features.h"
+#include "chrome/browser/webapps/android/jni_headers/PwaBottomSheetControllerProvider_jni.h"
+#include "chrome/browser/webapps/android/jni_headers/PwaBottomSheetController_jni.h"
 #include "components/url_formatter/elide_url.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/gfx/android/java_bitmap.h"
@@ -27,7 +27,8 @@
                         const base::string16& description,
                         const std::vector<base::string16>& categories,
                         const std::map<GURL, SkBitmap>& screenshots) {
-  if (!base::FeatureList::IsEnabled(chrome::android::kPwaInstallUseBottomSheet))
+  if (!base::FeatureList::IsEnabled(
+          webapps::features::kPwaInstallUseBottomSheet))
     return false;
 
   if (description.size() == 0 || categories.size() == 0 ||
diff --git a/chrome/browser/android/webapps/pwa_bottom_sheet_controller.h b/chrome/browser/webapps/android/pwa_bottom_sheet_controller.h
similarity index 94%
rename from chrome/browser/android/webapps/pwa_bottom_sheet_controller.h
rename to chrome/browser/webapps/android/pwa_bottom_sheet_controller.h
index 3bdc62b..78b879f 100644
--- a/chrome/browser/android/webapps/pwa_bottom_sheet_controller.h
+++ b/chrome/browser/webapps/android/pwa_bottom_sheet_controller.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_ANDROID_WEBAPPS_PWA_BOTTOM_SHEET_CONTROLLER_H_
-#define CHROME_BROWSER_ANDROID_WEBAPPS_PWA_BOTTOM_SHEET_CONTROLLER_H_
+#ifndef CHROME_BROWSER_WEBAPPS_ANDROID_PWA_BOTTOM_SHEET_CONTROLLER_H_
+#define CHROME_BROWSER_WEBAPPS_ANDROID_PWA_BOTTOM_SHEET_CONTROLLER_H_
 
 #include <map>
 
@@ -85,4 +85,4 @@
 
 }  // namespace webapps
 
-#endif  // CHROME_BROWSER_ANDROID_WEBAPPS_PWA_BOTTOM_SHEET_CONTROLLER_H_
+#endif  // CHROME_BROWSER_WEBAPPS_ANDROID_PWA_BOTTOM_SHEET_CONTROLLER_H_
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 26db0de7..b19f976 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-master-1609890206-88ace00cc385e4ef682397c3629935c4bd822382.profdata
+chrome-linux-master-1609912549-c91a8fa5efe894cd1dbcbf24f242fd8e4fea7dac.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 91cea05..68d836d 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1609890206-97a23ce40eede0995d03d53b562706106b3aa301.profdata
+chrome-mac-master-1609912549-27b0371d28f026dcf49b02c005becd8eabbb3dbd.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 98856a0..3a3a997 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-master-1609880376-51963dc93137cbb2d9fa681b7bce54c93abd3038.profdata
+chrome-win32-master-1609923503-082d3636d9b7f0ebc97af69fa1fe05452441e219.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index fdd795d..ff77526a 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1609880376-433e631db9acaf4e4400335821e1ac4c51c26057.profdata
+chrome-win64-master-1609923503-9b9894a01ac9daf80ce951069eff07585fba216a.profdata
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index d2b1a2b..d23ab034 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -543,12 +543,14 @@
 js_type_check("closure_compile_local") {
   is_polymer3 = true
   closure_flags = default_closure_args + [
+                    "browser_resolver_prefix_replacements=\"chrome://interventions-internals/=../../chrome/browser/resources/interventions-internals/\"",
                     "js_module_root=../../chrome/test/data/webui/",
                     "js_module_root=./gen/chrome/test/data/webui/",
                   ]
   deps = [
     ":chai_assert",
     ":fake_chrome_event.m",
+    ":interventions_internals_test",
     ":mock_timer.m",
     ":test_browser_proxy.m",
     ":test_plural_string_proxy",
@@ -556,6 +558,17 @@
   ]
 }
 
+js_library("interventions_internals_test") {
+  deps = [
+    ":chai_assert",
+    ":test_browser_proxy.m",
+    "//chrome/browser/resources/interventions_internals:index",
+    "//ui/webui/resources/js:promise_resolver.m",
+    "//ui/webui/resources/js:util.m",
+  ]
+  externs_list = [ "$externs_path/mocha-2.5.js" ]
+}
+
 js_library("fake_chrome_event.m") {
   sources = [ "$root_gen_dir/chrome/test/data/webui/fake_chrome_event.m.js" ]
   deps = [ ":chai_assert" ]
diff --git a/chrome/test/data/webui/interventions_internals_test.js b/chrome/test/data/webui/interventions_internals_test.js
index 2537a2f..a490b7b6 100644
--- a/chrome/test/data/webui/interventions_internals_test.js
+++ b/chrome/test/data/webui/interventions_internals_test.js
@@ -3,31 +3,44 @@
 // found in the LICENSE file.
 
 import {getTimeFormat, InterventionsInternalPageImpl, URL_THRESHOLD} from 'chrome://interventions-internals/index.js';
+import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js';
 import {$} from 'chrome://resources/js/util.m.js';
 
+import {assertEquals, assertFalse, assertGT} from './chai_assert.js';
 import {TestBrowserProxy} from './test_browser_proxy.m.js';
 
+/** @return {!PromiseResolver} */
+function getSetupFnResolver() {
+  return /** @type {{setupFnResolver: !PromiseResolver}} */ (window)
+      .setupFnResolver;
+}
+
 suite('InterventionsInternalsUITest', function() {
   /**
    * A stub class for the Mojo PageHandler.
+   * @implements {mojom.InterventionsInternalsPageInterface}
+   * @implements {mojom.InterventionsInternalsPageHandlerInterface}
    */
   class TestPageHandler extends TestBrowserProxy {
     constructor() {
       super(['getPreviewsEnabled', 'getPreviewsFlagsDetails']);
 
-      /** @private {!Map} */
-      this.previewsModeStatuses_ = new Map();
-      this.previewsFlagsStatuses_ = new Map();
+      /** @private {!Array<!mojom.PreviewsStatus>} */
+      this.previewsModeStatuses_ = [];
+
+      /** @private {!Array<!mojom.PreviewsFlag>} */
+      this.previewsFlagsStatuses_ = [];
     }
 
     /**
      * Setup testing map for getPreviewsEnabled.
-     * @param {!Map} map The testing status map.
+     * @param {!Array<!mojom.PreviewsStatus>} map The testing status map.
      */
     setTestingPreviewsModeMap(map) {
       this.previewsModeStatuses_ = map;
     }
 
+    /** @param {!Array<!mojom.PreviewsFlag>} map */
     setTestingPreviewsFlagsMap(map) {
       this.previewsFlagsStatuses_ = map;
     }
@@ -47,12 +60,30 @@
         flags: this.previewsFlagsStatuses_,
       });
     }
+
+    /** @override **/
+    logNewMessage() {}
+    /** @override **/
+    onBlocklistCleared() {}
+    /** @override **/
+    onBlocklistedHost() {}
+    /** @override **/
+    onIgnoreBlocklistDecisionStatusChanged() {}
+    /** @override **/
+    onUserBlocklistedStatusChange() {}
+    /** @override **/
+    setClientPage() {}
+    /** @override **/
+    setIgnorePreviewsBlocklistDecision() {}
+    /** @override **/
+    updateEffectiveConnectionType() {}
   }
 
   function getBlocklistedStatus(blocklisted) {
     return (blocklisted ? 'Blocklisted' : 'Not blocklisted');
   }
 
+  /** @type {?TestPageHandler} */
   let testPageHandler = null;
 
   setup(function() {
@@ -81,9 +112,10 @@
     ];
 
     testPageHandler.setTestingPreviewsModeMap(testArray);
-    window.setupFnResolver.resolve();
+    getSetupFnResolver().resolve();
 
-    return window.setupFnResolver.promise
+    return getSetupFnResolver()
+        .promise
         .then(() => {
           return testPageHandler.whenCalled('getPreviewsEnabled');
         })
@@ -92,7 +124,7 @@
             let expected = value.description + ': ' +
                 (value.enabled ? 'Enabled' : 'Disabled');
             let actual = document.querySelector('#' + value.htmlId).textContent;
-            expectEquals(expected, actual);
+            assertEquals(expected, actual);
           });
         });
   });
@@ -121,9 +153,10 @@
     ];
 
     testPageHandler.setTestingPreviewsFlagsMap(testArray);
-    window.setupFnResolver.resolve();
+    getSetupFnResolver().resolve();
 
-    return window.setupFnResolver.promise
+    return getSetupFnResolver()
+        .promise
         .then(() => {
           return testPageHandler.whenCalled('getPreviewsFlagsDetails');
         })
@@ -133,15 +166,15 @@
             let actualDescription =
                 document.querySelector('#' + key + 'Description');
             let actualValue = document.querySelector('#' + key + 'Value');
-            expectEquals(value.description, actualDescription.textContent);
-            expectEquals(value.link, actualDescription.getAttribute('href'));
-            expectEquals(value.value, actualValue.textContent);
+            assertEquals(value.description, actualDescription.textContent);
+            assertEquals(value.link, actualDescription.getAttribute('href'));
+            assertEquals(value.value, actualValue.textContent);
           });
         });
   });
 
   test('LogNewMessage', () => {
-    let pageImpl = new InterventionsInternalPageImpl(null);
+    let pageImpl = new InterventionsInternalPageImpl();
     let logs = [
       {
         type: 'Type_a',
@@ -171,7 +204,7 @@
     });
 
     let rows = $('message-logs-table').querySelectorAll('.log-message');
-    expectEquals(logs.length, rows.length);
+    assertEquals(logs.length, rows.length);
 
     logs.forEach((log, index) => {
       let row = rows[logs.length - index - 1];  // Expecting reversed order.
@@ -179,25 +212,25 @@
                                                 // appended to the top of the
                                                 // log table).
 
-      expectEquals(
+      assertEquals(
           getTimeFormat(log.time), row.querySelector('.log-time').textContent);
-      expectEquals(log.type, row.querySelector('.log-type').textContent);
-      expectEquals(
+      assertEquals(log.type, row.querySelector('.log-type').textContent);
+      assertEquals(
           log.description, row.querySelector('.log-description').textContent);
-      expectEquals(
+      assertEquals(
           log.url.url, row.querySelector('.log-url-value').textContent);
     });
   });
 
   test('LogNewMessageWithLongUrl', () => {
-    let pageImpl = new InterventionsInternalPageImpl(null);
-    let log = {
+    let pageImpl = new InterventionsInternalPageImpl();
+    let log = /** @type {!mojom.MessageLog} */ ({
       type: 'Some type',
       url: {url: ''},
       description: 'Some description',
       time: 758675653000,  // Jan 15 1994 23:14:13 UTC
       pageId: 0,
-    };
+    });
     // Creating long url.
     for (let i = 0; i <= 2 * URL_THRESHOLD; i++) {
       log.url.url += 'a';
@@ -205,31 +238,31 @@
     let expectedUrl = log.url.url.substring(0, URL_THRESHOLD - 3) + '...';
 
     pageImpl.logNewMessage(log);
-    expectEquals(
+    assertEquals(
         expectedUrl, document.querySelector('div.log-url-value').textContent);
   });
 
 
   test('LogNewMessageWithNoUrl', () => {
-    let pageImpl = new InterventionsInternalPageImpl(null);
-    let log = {
+    let pageImpl = new InterventionsInternalPageImpl();
+    let log = /** @type {!mojom.MessageLog} */ ({
       type: 'Some type',
       url: {url: ''},
       description: 'Some description',
       time: 758675653000,  // Jan 15 1994 23:14:13 UTC
       pageId: 0,
-    };
+    });
     pageImpl.logNewMessage(log);
     let actual = $('message-logs-table').rows[1];
     let expectedNoColumns = 3;
-    expectEquals(expectedNoColumns, actual.querySelectorAll('td').length);
-    assert(
-        !actual.querySelector('.log-url'),
+    assertEquals(expectedNoColumns, actual.querySelectorAll('td').length);
+    assertFalse(
+        !!actual.querySelector('.log-url'),
         'There should not be a log-url column for empty URL');
   });
 
   test('LogNewMessagePageIdZero', () => {
-    let pageImpl = new InterventionsInternalPageImpl(null);
+    let pageImpl = new InterventionsInternalPageImpl();
     let logs = [
       {
         type: 'Type_a',
@@ -254,23 +287,23 @@
     // Expect 2 different rows in logs table.
     let rows = $('message-logs-table').querySelectorAll('.log-message');
     let expectedNumberOfRows = 2;
-    expectEquals(expectedNumberOfRows, rows.length);
+    assertEquals(expectedNumberOfRows, rows.length);
 
     logs.forEach((log, index) => {
       let expectedTime = getTimeFormat(log.time);
       let row = rows[logs.length - index - 1];
 
-      expectEquals(expectedTime, row.querySelector('.log-time').textContent);
-      expectEquals(log.type, row.querySelector('.log-type').textContent);
-      expectEquals(
+      assertEquals(expectedTime, row.querySelector('.log-time').textContent);
+      assertEquals(log.type, row.querySelector('.log-type').textContent);
+      assertEquals(
           log.description, row.querySelector('.log-description').textContent);
-      expectEquals(
+      assertEquals(
           log.url.url, row.querySelector('.log-url-value').textContent);
     });
   });
 
   test('LogNewMessageNewPageId', () => {
-    let pageImpl = new InterventionsInternalPageImpl(null);
+    let pageImpl = new InterventionsInternalPageImpl();
     let logs = [
       {
         type: 'Type_a',
@@ -294,23 +327,23 @@
 
     // Expect 2 different rows in logs table.
     let rows = $('message-logs-table').querySelectorAll('.log-message');
-    expectEquals(2, rows.length);
+    assertEquals(2, rows.length);
 
     logs.forEach((log, index) => {
       let expectedTime = getTimeFormat(log.time);
       let row = rows[logs.length - index - 1];
 
-      expectEquals(expectedTime, row.querySelector('.log-time').textContent);
-      expectEquals(log.type, row.querySelector('.log-type').textContent);
-      expectEquals(
+      assertEquals(expectedTime, row.querySelector('.log-time').textContent);
+      assertEquals(log.type, row.querySelector('.log-type').textContent);
+      assertEquals(
           log.description, row.querySelector('.log-description').textContent);
-      expectEquals(
+      assertEquals(
           log.url.url, row.querySelector('.log-url-value').textContent);
     });
   });
 
   test('LogNewMessageExistedPageId', () => {
-    let pageImpl = new InterventionsInternalPageImpl(null);
+    let pageImpl = new InterventionsInternalPageImpl();
     let logs = [
       {
         type: 'Type_a',
@@ -333,35 +366,35 @@
     });
 
     let logTableRows = $('message-logs-table').querySelectorAll('.log-message');
-    expectEquals(1, logTableRows.length);
-    expectEquals(
+    assertEquals(1, logTableRows.length);
+    assertEquals(
         1, document.querySelector('.expansion-logs-table').rows.length);
 
     // Log table row.
     let row = $('message-logs-table').querySelector('.log-message');
     let expectedRowTime = getTimeFormat(logs[1].time);
-    expectEquals(expectedRowTime, row.querySelector('.log-time').textContent);
-    expectEquals(logs[1].type, row.querySelector('.log-type').textContent);
-    expectEquals(
+    assertEquals(expectedRowTime, row.querySelector('.log-time').textContent);
+    assertEquals(logs[1].type, row.querySelector('.log-type').textContent);
+    assertEquals(
         logs[1].description, row.querySelector('.log-description').textContent);
-    expectEquals(
+    assertEquals(
         logs[1].url.url, row.querySelector('.log-url-value').textContent);
 
     // Sub log table row.
     let subRow = document.querySelector('.expansion-logs-table').rows[0];
     let expectedSubTime = getTimeFormat(logs[0].time);
-    expectEquals(
+    assertEquals(
         expectedSubTime, subRow.querySelector('.log-time').textContent);
-    expectEquals(logs[0].type, subRow.querySelector('.log-type').textContent);
-    expectEquals(
+    assertEquals(logs[0].type, subRow.querySelector('.log-type').textContent);
+    assertEquals(
         logs[0].description,
         subRow.querySelector('.log-description').textContent);
-    expectEquals(
+    assertEquals(
         logs[0].url.url, subRow.querySelector('.log-url-value').textContent);
   });
 
   test('LogNewMessageExistedPageIdGroupToTopOfTable', () => {
-    let pageImpl = new InterventionsInternalPageImpl(null);
+    let pageImpl = new InterventionsInternalPageImpl();
     let logs = [
       {
         type: 'Type_a',
@@ -389,130 +422,130 @@
     pageImpl.logNewMessage(logs[0]);
     pageImpl.logNewMessage(logs[1]);
     let rows = $('message-logs-table').querySelectorAll('.log-message');
-    expectEquals(2, rows.length);
-    expectEquals(logs[1].type, rows[0].querySelector('.log-type').textContent);
-    expectEquals(logs[0].type, rows[1].querySelector('.log-type').textContent);
+    assertEquals(2, rows.length);
+    assertEquals(logs[1].type, rows[0].querySelector('.log-type').textContent);
+    assertEquals(logs[0].type, rows[1].querySelector('.log-type').textContent);
 
     // Existing group pushed to the top of the log table.
     pageImpl.logNewMessage(logs[2]);
     rows = $('message-logs-table').querySelectorAll('.log-message');
-    expectEquals(2, rows.length);
-    expectEquals(logs[2].type, rows[0].querySelector('.log-type').textContent);
-    expectEquals(logs[1].type, rows[1].querySelector('.log-type').textContent);
+    assertEquals(2, rows.length);
+    assertEquals(logs[2].type, rows[0].querySelector('.log-type').textContent);
+    assertEquals(logs[1].type, rows[1].querySelector('.log-type').textContent);
   });
 
   test('AddNewBlocklistedHost', () => {
-    let pageImpl = new InterventionsInternalPageImpl(null);
+    let pageImpl = new InterventionsInternalPageImpl();
     let time = 758675653000;  // Jan 15 1994 23:14:13 UTC
     let expectedHost = 'example.com';
-    pageImpl.onBlocklistedHost(expectedHost, time);
+    pageImpl.onBlocklistedHost(expectedHost, BigInt(time));
 
     let blocklistedTable = $('blocklisted-hosts-table');
     let row = blocklistedTable.querySelector('.blocklisted-host-row');
 
     let expectedTime = getTimeFormat(time);
 
-    expectEquals(
+    assertEquals(
         expectedHost, row.querySelector('.host-blocklisted').textContent);
-    expectEquals(
+    assertEquals(
         expectedTime, row.querySelector('.host-blocklisted-time').textContent);
   });
 
 
   test('HostAlreadyBlocklisted', () => {
-    let pageImpl = new InterventionsInternalPageImpl(null);
+    let pageImpl = new InterventionsInternalPageImpl();
     let time0 = 758675653000;   // Jan 15 1994 23:14:13 UTC
     let time1 = 1507221689240;  // Oct 05 2017 16:41:29 UTC
     let expectedHost = 'example.com';
 
-    pageImpl.onBlocklistedHost(expectedHost, time0);
+    pageImpl.onBlocklistedHost(expectedHost, BigInt(time0));
 
     let blocklistedTable = $('blocklisted-hosts-table');
     let row = blocklistedTable.querySelector('.blocklisted-host-row');
     let expectedTime = getTimeFormat(time0);
-    expectEquals(
+    assertEquals(
         expectedHost, row.querySelector('.host-blocklisted').textContent);
-    expectEquals(
+    assertEquals(
         expectedTime, row.querySelector('.host-blocklisted-time').textContent);
 
-    pageImpl.onBlocklistedHost(expectedHost, time1);
+    pageImpl.onBlocklistedHost(expectedHost, BigInt(time1));
 
     // The row remains the same.
-    expectEquals(
+    assertEquals(
         expectedHost, row.querySelector('.host-blocklisted').textContent);
-    expectEquals(
+    assertEquals(
         expectedTime, row.querySelector('.host-blocklisted-time').textContent);
   });
 
   test('UpdateUserBlocklisted', () => {
-    let pageImpl = new InterventionsInternalPageImpl(null);
+    let pageImpl = new InterventionsInternalPageImpl();
     let state = $('user-blocklisted-status-value');
 
     pageImpl.onUserBlocklistedStatusChange(true /* blocklisted */);
-    expectEquals(
+    assertEquals(
         getBlocklistedStatus(true /* blocklisted */), state.textContent);
 
     pageImpl.onUserBlocklistedStatusChange(false /* blocklisted */);
-    expectEquals(
+    assertEquals(
         getBlocklistedStatus(false /* blocklisted */), state.textContent);
   });
 
   test('OnBlocklistCleared', () => {
-    let pageImpl = new InterventionsInternalPageImpl(null);
+    let pageImpl = new InterventionsInternalPageImpl();
     let state = $('user-blocklisted-status-value');
     let time = 758675653000;  // Jan 15 1994 23:14:13 UTC
 
-    pageImpl.onBlocklistCleared(time);
+    pageImpl.onBlocklistCleared(BigInt(time));
     let actualClearedTime = $('blocklist-last-cleared-time').textContent;
-    expectEquals(getTimeFormat(time), actualClearedTime);
+    assertEquals(getTimeFormat(time), actualClearedTime);
     let blocklistedTable = $('blocklisted-hosts-table');
     let rows = blocklistedTable.querySelectorAll('.blocklisted-host-row');
-    expectEquals(0, rows.length);
+    assertEquals(0, rows.length);
   });
 
   test('ClearLogMessageOnBlocklistCleared', () => {
-    let pageImpl = new InterventionsInternalPageImpl(null);
+    let pageImpl = new InterventionsInternalPageImpl();
     let time = 758675653000;  // Jan 15 1994 23:14:13 UTC
-    let log = {
+    let log = /** @type {!mojom.MessageLog} */ ({
       type: 'Some type',
       url: {url: ''},
       description: 'Some description',
       time: 758675653000,  // Jan 15 1994 23:14:13 UTC
       pageId: 0,
-    };
+    });
 
     pageImpl.logNewMessage(log);
-    expectGT($('message-logs-table').rows.length, 1 /* header row */);
-    pageImpl.onBlocklistCleared(time);
+    assertGT($('message-logs-table').rows.length, 1 /* header row */);
+    pageImpl.onBlocklistCleared(BigInt(time));
     let expectedNumberOfRows = 2;  // header row and clear blocklist log.
     let rows = $('message-logs-table').rows;
-    expectEquals(expectedNumberOfRows, rows.length);
-    expectEquals(
+    assertEquals(expectedNumberOfRows, rows.length);
+    assertEquals(
         'Blocklist Cleared',
         rows[1].querySelector('.log-description').textContent);
   });
 
 
   test('OnECTChanged', () => {
-    let pageImpl = new InterventionsInternalPageImpl(null);
+    let pageImpl = new InterventionsInternalPageImpl();
     let ectTypes = ['type1', 'type2', 'type3'];
     ectTypes.forEach((type) => {
       pageImpl.updateEffectiveConnectionType(type, 'max');
       let actual = $('nqe-type').textContent;
-      expectEquals(type, actual);
+      assertEquals(type, actual);
     });
   });
 
   test('OnBlocklistIgnoreChange', () => {
-    let pageImpl = new InterventionsInternalPageImpl(null);
+    let pageImpl = new InterventionsInternalPageImpl();
     pageImpl.onIgnoreBlocklistDecisionStatusChanged(true /* ignored */);
-    expectEquals('Enable Blocklist', $('ignore-blocklist-button').textContent);
-    expectEquals(
+    assertEquals('Enable Blocklist', $('ignore-blocklist-button').textContent);
+    assertEquals(
         'Blocklist decisions are ignored.',
         $('blocklist-ignored-status').textContent);
 
     pageImpl.onIgnoreBlocklistDecisionStatusChanged(false /* ignored */);
-    expectEquals('Ignore Blocklist', $('ignore-blocklist-button').textContent);
-    expectEquals('', $('blocklist-ignored-status').textContent);
+    assertEquals('Ignore Blocklist', $('ignore-blocklist-button').textContent);
+    assertEquals('', $('blocklist-ignored-status').textContent);
   });
 });
diff --git a/chrome/test/data/webui/settings/chromeos/switch_access_subpage_tests.js b/chrome/test/data/webui/settings/chromeos/switch_access_subpage_tests.js
index fb1fa04..0a1a73d 100644
--- a/chrome/test/data/webui/settings/chromeos/switch_access_subpage_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/switch_access_subpage_tests.js
@@ -96,15 +96,13 @@
   });
 
   /**
-   * @param {!Array<string>} keys New switch key assignments for select action.
+   * @param {!Array<string>} switches New switch assignments for select action.
    * @return {string} Sub-label text from the select link row.
    */
-  function getSublabelForSelectUpdates(keys) {
-    cr.webUIListenerCallback('switch-access-assignments-changed', {
-      select: keys.map(key => ({key, devices: ['internal']})),
-      next: [],
-      previous: []
-    });
+  function getSublabelForSelectUpdates(switches) {
+    cr.webUIListenerCallback(
+        'switch-access-assignments-changed',
+        {select: switches, next: [], previous: []});
 
     return page.$$('#selectLinkRow').$$('#subLabel').textContent.trim();
   }
@@ -120,7 +118,7 @@
     // Simulate a pref change for the select action.
     cr.webUIListenerCallback(
         'switch-access-assignments-changed',
-        {select: [{key: 'a', devices: ['internal']}], next: [], previous: []});
+        {select: ['a'], next: [], previous: []});
 
     assertEquals(1, page.selectAssignments_.length);
     assertEquals('a', page.selectAssignments_[0]);
diff --git a/chrome/tools/build/mac/run_verify_order.py b/chrome/tools/build/mac/run_verify_order.py
deleted file mode 100644
index 70802464..0000000
--- a/chrome/tools/build/mac/run_verify_order.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import argparse
-import os.path
-import sys
-import subprocess
-
-# Wraps chrome/tools/build/mac/verify_order for the GN build so that it can
-# write a stamp file, rather than operate as a postbuild.
-
-if __name__ == '__main__':
-  parser = argparse.ArgumentParser(
-      description='A wrapper around verify_order that writes a stamp file.')
-  parser.add_argument('--stamp', action='store', type=str,
-      help='Touch this stamp file on success.')
-
-  args, unknown_args = parser.parse_known_args()
-
-  this_script_dir = os.path.dirname(sys.argv[0])
-  rv = subprocess.check_call(
-      [ os.path.join(this_script_dir, 'verify_order') ] + unknown_args)
-
-  if rv == 0 and args.stamp:
-    if os.path.exists(args.stamp):
-      os.unlink(args.stamp)
-    open(args.stamp, 'w+').close()
-
-  sys.exit(rv)
diff --git a/chrome/tools/build/mac/verify_order b/chrome/tools/build/mac/verify_order
deleted file mode 100755
index d41e766d..0000000
--- a/chrome/tools/build/mac/verify_order
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/bin/bash
-
-# Copyright (c) 2009 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.
-
-# Verifies that no global text symbols are present in a Mach-O file
-# (MACH_O_FILE) at an address higher than the address of a specific symbol
-# (LAST_SYMBOL).  If LAST_SYMBOL is not found in MACH_O_FILE or if symbols
-# are present with addresses higher than LAST_SYMBOL's address, an error
-# message is printed to stderr, and the script will exit nonzero.
-#
-# This script can be used to verify that all of the global text symbols in
-# a Mach-O file are accounted for in an order file.
-
-if [ ${#} -ne 3 ] ; then
-  echo "usage: ${0} LAST_SYMBOL MACH_O_FILE BIN_SEARCH_PATH" >& 2
-  exit 1
-fi
-
-LAST_SYMBOL=${1}
-MACH_O_FILE=${2}
-BIN_SEARCH_PATH=${3}
-NM_PATH="${BIN_SEARCH_PATH}nm"
-OTOOL_PATH="${BIN_SEARCH_PATH}otool"
-
-SYMBOLS=$("${NM_PATH}" -gjn "${MACH_O_FILE}" -s __TEXT __text)
-if [ ${?} -ne 0 ] || [ -z "${SYMBOLS}" ] ; then
-  echo "${0}: no symbols in ${MACH_O_FILE}" >& 2
-  exit 1
-fi
-
-LAST_SYMBOLS=$(grep -A 100 -Fx "${LAST_SYMBOL}" <<< "${SYMBOLS}")
-if [ ${?} -ne 0 ] || [ -z "${LAST_SYMBOLS}" ] ; then
-  echo "${0}: symbol ${LAST_SYMBOL} not found in ${MACH_O_FILE}" >& 2
-  exit 1
-fi
-
-UNORDERED_SYMBOLS=$(grep -Fvx "${LAST_SYMBOL}" <<< "${LAST_SYMBOLS}")
-if [ ${?} -eq 0 ] || [ -n "${UNORDERED_SYMBOLS}" ] ; then
-  echo "${0}: unordered symbols in ${MACH_O_FILE}:" >& 2
-  echo "${UNORDERED_SYMBOLS}" >& 2
-  exit 1
-fi
-
-LIBS=$("${OTOOL_PATH}" -L "${MACH_O_FILE}")
-if [ ${?} -ne 0 ] ; then
-  echo "${0}: failed to get libraries in ${MACH_O_FILE}" >& 2
-  exit 1
-fi
-
-exit 0
diff --git a/chrome/tools/build/mac/verify_order.py b/chrome/tools/build/mac/verify_order.py
new file mode 100644
index 0000000..39031d9
--- /dev/null
+++ b/chrome/tools/build/mac/verify_order.py
@@ -0,0 +1,91 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Verifies that no global text symbols are present in a Mach-O file
+# that is not in a given allowlist. Also verifies the order of global symbols
+# matches the order in the allowlist.
+
+from __future__ import print_function
+
+import argparse
+import os.path
+import re
+import sys
+import subprocess
+
+
+def has_duplicates(x):
+  return len(x) != len(set(x))
+
+
+def parse_order_file(filename):
+  """Parses a file containing symbols like passed to ld64's -order_file.
+
+  Doesn't support arch or object file prefixes.
+  """
+  strip_comments = re.compile('#.*$')
+  symbols = [strip_comments.sub('', line).strip() for line in open(filename)]
+  symbols = filter(None, symbols)
+  if has_duplicates(symbols):
+    print('order file "%s" contains duplicate symbols' % filename,
+          file=sys.stderr)
+    sys.exit(1)
+  return symbols
+
+
+def check_symbol_table(binary, allowed_symbols, mac_bin_path, symbol_file):
+  nm = os.path.join(mac_bin_path, 'nm')
+  actual_symbols = subprocess.check_output([nm, '-jUng', binary])
+  actual_symbols = [s.rstrip() for s in actual_symbols.splitlines()]
+  def print_syms(syms):
+    print('\n'.join(['  ' + s for s in syms]), file=sys.stderr)
+  try:
+    # Check that actual_symbols is a sublist of allowed_symbols.
+    # Every exported symbol must be in allowed_symbols, and the order of the
+    # exported symbols must match the order in allowed_symbols. Not all
+    # symbols in allowed_symbols need to be present in the actual exports.
+    # The approach here is O(m*n), but allowed_symbols is very small so that's
+    # fine. Order matters, so can't use set().
+    symbol_indices = [allowed_symbols.index(s) for s in actual_symbols]
+    if symbol_indices != sorted(symbol_indices):
+      print('"%s" exports symbols in order different from order file %s' %
+            (binary, symbol_file),
+            file=sys.stderr)
+      print('actual order:', file=sys.stderr)
+      print_syms(actual_symbols)
+      print('expected order:', file=sys.stderr)
+      print_syms(allowed_symbols)
+      sys.exit(1)
+    # If we get here, every symbol in actual_symbols is in allowed_symbols, in
+    # the right order. nm's output doesn't contain duplicates, so we are done.
+    assert not has_duplicates(allowed_symbols)
+  except ValueError as e:
+    print('unexpected export: %s' % e, file=sys.stderr)
+    print('allowed exports from %s:' % symbol_file, file=sys.stderr)
+    print_syms(allowed_symbols)
+    sys.exit(1)
+
+
+def main():
+  parser = argparse.ArgumentParser(
+    description='Check order of exported symbols of a given binary.')
+  parser.add_argument('--stamp', required=True,
+    help='Touch this stamp file on success.')
+  parser.add_argument('--binary', required=True, help='Check this binary.')
+  parser.add_argument('--mac-bin-path', required=True,
+    help='Directory containing nm, otool, llvm-objdump')
+  parser.add_argument('--symbol-file', required=True,
+    help='Order file listing expected public symbols.')
+  args = parser.parse_args()
+
+  allowed_symbols = parse_order_file(args.symbol_file)
+  check_symbol_table(
+      args.binary, allowed_symbols, args.mac_bin_path, args.symbol_file)
+  # TODO(thakis): Also verify global symbols in the binary's export trie.
+
+  open(args.stamp, 'w').close()  # Update mtime on stamp file.
+
+
+if __name__ == '__main__':
+  main()
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 80257fd..c29da56 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-13706.0.0
\ No newline at end of file
+13707.0.0
\ No newline at end of file
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt
index 8d807537..e3edae08 100644
--- a/chromeos/profiles/atom.afdo.newest.txt
+++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-atom-89-4342.0-1607345364-benchmark-89.0.4357.3-r1-redacted.afdo.xz
+chromeos-chrome-amd64-atom-89-4367.0-1609757097-benchmark-89.0.4379.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index c714dc9..d279b12 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-89-4342.0-1607944823-benchmark-89.0.4357.3-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-89-4367.0-1609764762-benchmark-89.0.4379.0-r1-redacted.afdo.xz
diff --git a/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.cc b/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.cc
index d47a4d2..9066c264 100644
--- a/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.cc
+++ b/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.cc
@@ -27,6 +27,7 @@
 #include "ui/gfx/vector_icon_types.h"
 #include "ui/strings/grit/ui_strings.h"  // Accessibility names
 #include "ui/views/layout/box_layout.h"
+#include "ui/views/metadata/metadata_impl_macros.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
 #include "ui/views/window/frame_caption_button.h"
@@ -116,6 +117,9 @@
 class DefaultCaptionButtonModel : public CaptionButtonModel {
  public:
   explicit DefaultCaptionButtonModel(views::Widget* frame) : frame_(frame) {}
+  DefaultCaptionButtonModel(const DefaultCaptionButtonModel&) = delete;
+  DefaultCaptionButtonModel& operator=(const DefaultCaptionButtonModel&) =
+      delete;
   ~DefaultCaptionButtonModel() override {}
 
   // CaptionButtonModel:
@@ -151,15 +155,10 @@
 
  private:
   views::Widget* frame_;
-  DISALLOW_COPY_AND_ASSIGN(DefaultCaptionButtonModel);
 };
 
 }  // namespace
 
-// static
-const char FrameCaptionButtonContainerView::kViewClassName[] =
-    "FrameCaptionButtonContainerView";
-
 FrameCaptionButtonContainerView::FrameCaptionButtonContainerView(
     views::Widget* frame)
     : views::AnimationDelegateViews(frame->GetRootView()),
@@ -321,10 +320,6 @@
 #endif  // DCHECK_IS_ON()
 }
 
-const char* FrameCaptionButtonContainerView::GetClassName() const {
-  return kViewClassName;
-}
-
 void FrameCaptionButtonContainerView::ChildPreferredSizeChanged(View* child) {
   PreferredSizeChanged();
 }
@@ -540,4 +535,7 @@
   SnapController::Get()->CommitSnap(frame_->GetNativeWindow(), snap);
 }
 
+BEGIN_METADATA(FrameCaptionButtonContainerView, views::View)
+END_METADATA
+
 }  // namespace chromeos
diff --git a/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h b/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h
index 26d70111..588d18e 100644
--- a/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h
+++ b/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h
@@ -13,6 +13,7 @@
 #include "chromeos/ui/frame/caption_buttons/frame_size_button_delegate.h"
 #include "chromeos/ui/frame/caption_buttons/snap_controller.h"
 #include "ui/views/animation/animation_delegate_views.h"
+#include "ui/views/metadata/metadata_header_macros.h"
 #include "ui/views/view.h"
 #include "ui/views/window/frame_caption_button.h"
 
@@ -38,10 +39,14 @@
       public FrameSizeButtonDelegate,
       public views::AnimationDelegateViews {
  public:
-  static const char kViewClassName[];
+  METADATA_HEADER(FrameCaptionButtonContainerView);
 
   // |frame| is the views::Widget that the caption buttons act on.
   explicit FrameCaptionButtonContainerView(views::Widget* frame);
+  FrameCaptionButtonContainerView(const FrameCaptionButtonContainerView&) =
+      delete;
+  FrameCaptionButtonContainerView& operator=(
+      const FrameCaptionButtonContainerView&) = delete;
   ~FrameCaptionButtonContainerView() override;
 
   // For testing.
@@ -49,6 +54,8 @@
    public:
     explicit TestApi(FrameCaptionButtonContainerView* container_view)
         : container_view_(container_view) {}
+    TestApi(const TestApi&) = delete;
+    TestApi& operator=(const TestApi&) = delete;
 
     void EndAnimations();
 
@@ -70,8 +77,6 @@
 
    private:
     FrameCaptionButtonContainerView* container_view_;
-
-    DISALLOW_COPY_AND_ASSIGN(TestApi);
   };
 
   // Sets the id of the vector image to paint the button for |icon|. The
@@ -107,7 +112,6 @@
 
   // views::View:
   void Layout() override;
-  const char* GetClassName() const override;
   void ChildPreferredSizeChanged(View* child) override;
   void ChildVisibilityChanged(View* child) override;
 
@@ -166,8 +170,6 @@
   std::unique_ptr<gfx::SlideAnimation> tablet_mode_animation_;
 
   std::unique_ptr<CaptionButtonModel> model_;
-
-  DISALLOW_COPY_AND_ASSIGN(FrameCaptionButtonContainerView);
 };
 
 }  // namespace chromeos
diff --git a/components/autofill/core/browser/autofill_regex_constants.cc b/components/autofill/core/browser/autofill_regex_constants.cc
index a887eb6..3f4b0491 100644
--- a/components/autofill/core/browser/autofill_regex_constants.cc
+++ b/components/autofill/core/browser/autofill_regex_constants.cc
@@ -21,7 +21,8 @@
 const char kAddressNameIgnoredRe[] =
     "address.*nickname|address.*label"
     "|adres ([İi]sim|başlığı|adı)"  // tr
-    "|identificação do endereço";   // pt-BR, pt-PT
+    "|identificação do endereço"    // pt-BR, pt-PT
+    "|(label|judul|nama) alamat";   // id
 const char kCompanyRe[] =
     "company|business|organization|organisation"
     "|(?<!con)firma|firmenname"  // de-DE
@@ -32,7 +33,8 @@
     "|название.?компании"        // ru
     "|单位|公司"                 // zh-CN
     "|شرکت"                      // fa
-    "|회사|직장";                // ko-KR
+    "|회사|직장"                 // ko-KR
+    "|(nama.?)?perusahaan";      // id
 const char kStreetNameRe[] =
     "stra(ss|ß)e"              // de
     "|street"                  // en
@@ -65,7 +67,8 @@
     "|Адрес"                                  // ru
     "|地址"                                   // zh-CN
     "|(\\b|_)adres(?! tarifi)(\\b|_)"         // tr
-    "|^주소.?$|주소.?1";                      // ko-KR
+    "|^주소.?$|주소.?1"                       // ko-KR
+    "|^alamat";                               // id
 const char kAddressLine1LabelRe[] =
     "(^\\W*address)"
     "|(address\\W*$)"
@@ -78,6 +81,7 @@
     "|地址"                            // zh-CN
     "|(\\b|_)adres(?! tarifi)(\\b|_)"  // tr
     "|주소"                            // ko-KR
+    "|^alamat"                         // id
     // Should contain street and any other address component, in any order
     "|street.*(house|building|apartment|floor)"  // en
     "|(house|building|apartment|floor).*street"
@@ -115,7 +119,8 @@
     "|国家"                              // zh-CN
     "|국가|나라"                         // ko-KR
     "|(\\b|_)(ülke|ulce|ulke)(\\b|_)"    // tr
-    "|کشور";                             // fa
+    "|کشور"                              // fa
+    "|negara";                           // id
 const char kCountryLocationRe[] = "location";
 const char kZipCodeRe[] =
     "zip|postal|post.*code|pcode"
@@ -132,14 +137,16 @@
     "|邮政编码|邮编"                // zh-CN
     "|郵遞區號"                     // zh-TW
     "|(\\b|_)posta kodu(\\b|_)"     // tr
-    "|우편.?번호";                  // ko-KR
+    "|우편.?번호"                   // ko-KR
+    "|kode.?pos";                   // id
 const char kZip4Re[] =
     "zip|^-$|post2"
     "|codpos2";  // pt-BR, pt-PT
 const char kDependentLocalityRe[] =
     "neighbo(u)?rhood"  // en
     "|bairro"           // pt-BR, pt-PT
-    "|mahalle|köy";     // tr
+    "|mahalle|köy"      // tr
+    "|kecamatan";       // id
 const char kCityRe[] =
     "city|town"
     "|\\bort\\b|stadt"                                  // de-DE
@@ -157,7 +164,8 @@
     "|ग्राम|गाँव"                                         // hi for village
     "|നഗരം|ഗ്രാമം"                                       // ml for town|village
     "|((\\b|_|\\*)([İii̇]l[cç]e(miz|niz)?)(\\b|_|\\*))"  // tr
-    "|^시[^도·・]|시[·・]?군[·・]?구";                  // ko-KR
+    "|^시[^도·・]|시[·・]?군[·・]?구"                   // ko-KR
+    "|kota|kabupaten";                                  // id
 const char kStateRe[] =
     "(?<!(united|hist|history).?)state|county|region|province"
     "|county|principality"  // en-UK
@@ -170,7 +178,8 @@
     "|استان"                // fa
     "|राज्य"                 // hi
     "|((\\b|_|\\*)(eyalet|[şs]ehir|[İii̇]l(imiz)?|kent)(\\b|_|\\*))"  // tr
-    "|^시[·・]?도";                                                  // ko-KR
+    "|^시[·・]?도"                                                   // ko-KR
+    "|provinci";                                                     // id
 
 /////////////////////////////////////////////////////////////////////////////
 // search_field.cc
@@ -209,6 +218,7 @@
     "|nome.*cart"                      // it-IT
     "|名前"                            // ja-JP
     "|Имя.*карты"                      // ru
+    "|nama.*kartu"                     // id
     "|信用卡开户名|开户名|持卡人姓名"  // zh-CN
     "|持卡人姓名";                     // zh-TW
 const char kNameOnCardContextualRe[] = "name";
@@ -217,6 +227,7 @@
     "|(?<!telefon|haus|person|fødsels)nummer"  // de-DE, sv-SE, no
     "|カード番号"                              // ja-JP
     "|Номер.*карты"                            // ru
+    "|no.*kartu"                               // id
     "|信用卡号|信用卡号码"                     // zh-CN
     "|信用卡卡號"                              // zh-TW
     "|카드"                                    // ko-KR
@@ -244,14 +255,15 @@
 // Instead, we match only words beginning with "month".
 const char kExpirationMonthRe[] =
     "expir|exp.*mo|exp.*date|ccmonth|cardmonth|addmonth"
-    "|gueltig|gültig|monat"  // de-DE
-    "|fecha"                 // es
-    "|date.*exp"             // fr-FR
-    "|scadenza"              // it-IT
-    "|有効期限"              // ja-JP
-    "|validade"              // pt-BR, pt-PT
-    "|Срок действия карты"   // ru
-    "|月";                   // zh-CN
+    "|gueltig|gültig|monat"         // de-DE
+    "|fecha"                        // es
+    "|date.*exp"                    // fr-FR
+    "|scadenza"                     // it-IT
+    "|有効期限"                     // ja-JP
+    "|validade"                     // pt-BR, pt-PT
+    "|Срок действия карты"          // ru
+    "|masa berlaku|berlaku hingga"  // id
+    "|月";                          // zh-CN
 const char kExpirationYearRe[] =
     "exp|^/|(add)?year"
     "|ablaufdatum|gueltig|gültig|jahr"  // de-DE
@@ -260,6 +272,7 @@
     "|有効期限"                         // ja-JP
     "|validade"                         // pt-BR, pt-PT
     "|Срок действия карты"              // ru
+    "|masa berlaku|berlaku hingga"      // id
     "|年|有效期";                       // zh-CN
 
 // Used to match a expiration date field with a two digit year.
@@ -323,13 +336,14 @@
     "^name|full.?name|your.?name|customer.?name|bill.?name|ship.?name"
     "|name.*first.*last|firstandlastname"
     "|nombre.*y.*apellidos"                    // es
-    "|^nom(?!bre)"                             // fr-FR
+    "|^nom(?![a-zA-Z])"                        // fr-FR
     "|お名前|氏名"                             // ja-JP
     "|^nome"                                   // pt-BR, pt-PT
     "|نام.*نام.*خانوادگی"                      // fa
     "|姓名"                                    // zh-CN
     "|(\\b|_|\\*)ad[ı]? soyad[ı]?(\\b|_|\\*)"  // tr
-    "|성명";                                   // ko-KR
+    "|성명"                                    // ko-KR
+    "|nama.?(lengkap|penerima|kamu)";          // id
 const char kNameSpecificRe[] =
     "^name"
     "|^nom"    // fr-FR
@@ -346,14 +360,15 @@
     "|이름"                                                // ko-KR
     "|പേര്"                                                 // ml
     "|(\\b|_|\\*)(isim|ad|ad(i|ı|iniz|ınız)?)(\\b|_|\\*)"  // tr
-    "|नाम";                                                // hi
+    "|नाम"                                                 // hi
+    "|nama depan";                                         // id
 const char kMiddleInitialRe[] = "middle.*initial|m\\.i\\.|mi$|\\bmi\\b";
 const char kMiddleNameRe[] = "middle.*name|mname|middle$";
 const char kLastNameRe[] =
     "last.*name|lname|surname(?!\\d)|last$|secondname|family.*name"
     "|nachname"                                               // de-DE
     "|apellidos?"                                             // es
-    "|famille|^nom(?!bre)"                                    // fr-FR
+    "|famille|^nom(?![a-zA-Z])"                               // fr-FR
     "|cognome"                                                // it-IT
     "|姓"                                                     // ja-JP
     "|apelidos|surename|sobrenome"                            // pt-BR, pt-PT
@@ -362,7 +377,8 @@
     "|उपनाम"                                                  // hi
     "|മറുപേര്"                                                  // ml
     "|(\\b|_|\\*)(soyisim|soyad(i|ı|iniz|ınız)?)(\\b|_|\\*)"  // tr
-    "|\\b성(?:[^명]|\\b)";                                    // ko-KR
+    "|\\b성(?:[^명]|\\b)"                                     // ko-KR
+    "|nama belakang";                                         // id
 const char kNameLastFirstRe[] =
     "(primer.*apellido)"                 // es
     "|(apellido1)"                       // es
@@ -388,17 +404,18 @@
 /////////////////////////////////////////////////////////////////////////////
 const char kPhoneRe[] =
     "phone|mobile|contact.?number"
-    "|telefonnummer"                                // de-DE
-    "|telefono|teléfono"                            // es
-    "|telfixe"                                      // fr-FR
-    "|電話"                                         // ja-JP
-    "|telefone|telemovel"                           // pt-BR, pt-PT
-    "|телефон"                                      // ru
-    "|मोबाइल"                                       // hi for mobile
-    "|(\\b|_|\\*)telefon(\\b|_|\\*)"                // tr
-    "|电话"                                         // zh-CN
-    "|മൊബൈല്‍"                        // ml for mobile
-    "|(?:전화|핸드폰|휴대폰|휴대전화)(?:.?번호)?";  // ko-KR
+    "|telefonnummer"                                   // de-DE
+    "|telefono|teléfono"                               // es
+    "|telfixe"                                         // fr-FR
+    "|電話"                                            // ja-JP
+    "|telefone|telemovel"                              // pt-BR, pt-PT
+    "|телефон"                                         // ru
+    "|मोबाइल"                                          // hi for mobile
+    "|(\\b|_|\\*)telefon(\\b|_|\\*)"                   // tr
+    "|电话"                                            // zh-CN
+    "|മൊബൈല്‍"                           // ml for mobile
+    "|(?:전화|핸드폰|휴대폰|휴대전화)(?:.?번호)?"      // ko-KR
+    "|telepon|ponsel|(nomor|no\\.?).?(hp|handphone)";  // id
 const char kAugmentedPhoneCountryCodeRe[] =
     "^[^0-9+]*(?:\\+|00)\\s*([1-9]\\d{0,3})\\D*$";
 const char kCountryCodeRe[] =
diff --git a/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json b/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json
index 6f0e710c..95b1c0a 100644
--- a/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json
+++ b/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json
@@ -239,6 +239,16 @@
         "match_field_attributes": 3,
         "match_field_input_types": 1
       }
+    ],
+    "id": [
+      {
+        "pattern_identifier": "id_address_name_ignored_preserving",
+        "positive_pattern": "(label|judul|nama) alamat",
+        "positive_score": 1.1,
+        "negative_pattern": null,
+        "match_field_attributes": 3,
+        "match_field_input_types": 1
+      }
     ]
   },
   "COMPANY": {
@@ -341,6 +351,16 @@
         "match_field_attributes": 3,
         "match_field_input_types": 1
       }
+    ],
+    "id": [
+      {
+        "pattern_identifier": "id_company_preserving",
+        "positive_pattern": "(nama.?)?perusahaan",
+        "positive_score": 1.1,
+        "negative_pattern": null,
+        "match_field_attributes": 3,
+        "match_field_input_types": 1
+      }
     ]
   },
   "ADDRESS_LINE_1": {
@@ -510,6 +530,25 @@
         "match_field_attributes": 1,
         "match_field_input_types": 1
       }
+    ],
+    "id": [
+      {
+        "pattern_identifier": "id_address_line_1_preserving",
+        "positive_pattern": "^alamat",
+        "positive_score": 1.1,
+        "negative_pattern": null,
+        "match_field_attributes": 3,
+        "match_field_input_types": 1
+      }
+    ,
+      {
+        "pattern_identifier": "id_address_line_1_label_preserving",
+        "positive_pattern": "^alamat",
+        "positive_score": 1.1,
+        "negative_pattern": null,
+        "match_field_attributes": 1,
+        "match_field_input_types": 1
+      }
     ]
   },
   "ADDRESS_LINE_2": {
@@ -788,6 +827,16 @@
         "match_field_attributes": 3,
         "match_field_input_types": 137
       }
+    ],
+    "id": [
+      {
+        "pattern_identifier": "id_country_preserving",
+        "positive_pattern": "negara",
+        "positive_score": 1.1,
+        "negative_pattern": null,
+        "match_field_attributes": 3,
+        "match_field_input_types": 137
+      }
     ]
   },
   "COUNTRY_LOCATION": {
@@ -942,6 +991,16 @@
         "match_field_attributes": 3,
         "match_field_input_types": 69
       }
+    ],
+    "id": [
+      {
+        "pattern_identifier": "id_zip_code_preserving",
+        "positive_pattern": "kode.?pos",
+        "positive_score": 1.1,
+        "negative_pattern": null,
+        "match_field_attributes": 3,
+        "match_field_input_types": 69
+      }
     ]
   },
   "ZIP_4": {
@@ -996,6 +1055,16 @@
         "match_field_attributes": 3,
         "match_field_input_types": 137
       }
+    ],
+    "id": [
+      {
+        "pattern_identifier": "id_dependent_locality_preserving",
+        "positive_pattern": "kecamatan",
+        "positive_score": 1.1,
+        "negative_pattern": null,
+        "match_field_attributes": 3,
+        "match_field_input_types": 137
+      }
     ]
   },
   "CITY": {
@@ -1138,6 +1207,16 @@
         "match_field_attributes": 3,
         "match_field_input_types": 137
       }
+    ],
+    "id": [
+      {
+        "pattern_identifier": "id_city_preserving",
+        "positive_pattern": "kota|kabupaten",
+        "positive_score": 1.1,
+        "negative_pattern": null,
+        "match_field_attributes": 3,
+        "match_field_input_types": 137
+      }
     ]
   },
   "STATE": {
@@ -1240,6 +1319,16 @@
         "match_field_attributes": 3,
         "match_field_input_types": 137
       }
+    ],
+    "id": [
+      {
+        "pattern_identifier": "id_state_preserving",
+        "positive_pattern": "provinci",
+        "positive_score": 1.1,
+        "negative_pattern": null,
+        "match_field_attributes": 3,
+        "match_field_input_types": 137
+      }
     ]
   },
   "SEARCH_TERM": {
@@ -1446,6 +1535,16 @@
         "match_field_attributes": 3,
         "match_field_input_types": 1
       }
+    ],
+    "id": [
+      {
+        "pattern_identifier": "id_name_on_card_preserving",
+        "positive_pattern": "nama.*kartu",
+        "positive_score": 1.0,
+        "negative_pattern": null,
+        "match_field_attributes": 3,
+        "match_field_input_types": 1
+      }
     ]
   },
   "NAME_ON_CARD_CONTEXTUAL": {
@@ -1560,6 +1659,16 @@
         "match_field_attributes": 3,
         "match_field_input_types": 101
       }
+    ],
+    "id": [
+      {
+        "pattern_identifier": "id_card_number_preserving",
+        "positive_pattern": "no.*kartu",
+        "positive_score": 1.0,
+        "negative_pattern": null,
+        "match_field_attributes": 3,
+        "match_field_input_types": 101
+      }
     ]
   },
   "CREDIT_CARD_VERIFICATION_CODE": {
@@ -1664,6 +1773,16 @@
         "match_field_attributes": 3,
         "match_field_input_types": 205
       }
+    ],
+    "id": [
+      {
+        "pattern_identifier": "id_card_exp_month_preserving",
+        "positive_pattern": "masa berlaku|berlaku hingga",
+        "positive_score": 1.0,
+        "negative_pattern": null,
+        "match_field_attributes": 3,
+        "match_field_input_types": 205
+      }
     ]
   },
   "CREDIT_CARD_EXP_YEAR": {
@@ -1852,6 +1971,16 @@
         "match_field_attributes": 3,
         "match_field_input_types": 205
       }
+    ],
+    "id": [
+      {
+        "pattern_identifier": "id_card_exp_date_preserving",
+        "positive_pattern": "masa berlaku|berlaku hingga",
+        "positive_score": 1.0,
+        "negative_pattern": null,
+        "match_field_attributes": 3,
+        "match_field_input_types": 205
+      }
     ]
   },
   "CREDIT_CARD_EXP_MONTH_BEFORE_YEAR": {
@@ -2114,7 +2243,7 @@
     "fr": [
       {
         "pattern_identifier": "fr_full_name_preserving",
-        "positive_pattern": "^nom(?!bre)",
+        "positive_pattern": "^nom(?![a-zA-Z])",
         "positive_score": 0.9,
         "negative_pattern": null,
         "match_field_attributes": 3,
@@ -2180,6 +2309,16 @@
         "match_field_attributes": 3,
         "match_field_input_types": 1
       }
+    ],
+    "id": [
+      {
+        "pattern_identifier": "id_full_name_preserving",
+        "positive_pattern": "nama.?(lengkap|penerima|kamu)",
+        "positive_score": 0.9,
+        "negative_pattern": null,
+        "match_field_attributes": 3,
+        "match_field_input_types": 1
+      }
     ]
   },
   "NAME_SPECIFIC": {
@@ -2334,6 +2473,16 @@
         "match_field_attributes": 3,
         "match_field_input_types": 1
       }
+    ],
+    "id": [
+      {
+        "pattern_identifier": "id_first_name_preserving",
+        "positive_pattern": "nama depan",
+        "positive_score": 0.9,
+        "negative_pattern": null,
+        "match_field_attributes": 3,
+        "match_field_input_types": 1
+      }
     ]
   },
   "MIDDLE_INITIAL": {
@@ -2394,7 +2543,7 @@
     "fr": [
       {
         "pattern_identifier": "fr_last_name_preserving",
-        "positive_pattern": "famille|^nom(?!bre)",
+        "positive_pattern": "famille|^nom(?![a-zA-Z])",
         "positive_score": 0.9,
         "negative_pattern": null,
         "match_field_attributes": 3,
@@ -2490,6 +2639,16 @@
         "match_field_attributes": 3,
         "match_field_input_types": 1
       }
+    ],
+    "id": [
+      {
+        "pattern_identifier": "id_last_name_preserving",
+        "positive_pattern": "nama belakang",
+        "positive_score": 0.9,
+        "negative_pattern": null,
+        "match_field_attributes": 3,
+        "match_field_input_types": 1
+      }
     ]
   },
   "LAST_NAME_FIRST": {
@@ -2718,6 +2877,16 @@
         "match_field_attributes": 3,
         "match_field_input_types": 69
       }
+    ],
+    "id": [
+      {
+        "pattern_identifier": "id_phone_preserving",
+        "positive_pattern": "telepon|ponsel|(nomor|no\\.?).?(hp|handphone)",
+        "positive_score": 1.2,
+        "negative_pattern": null,
+        "match_field_attributes": 3,
+        "match_field_input_types": 69
+      }
     ]
   },
   "AUGMENTED_PHONE_COUNTRY_CODE": {
diff --git a/components/browser_ui/styles/android/BUILD.gn b/components/browser_ui/styles/android/BUILD.gn
index 8ede54e..80eb76d 100644
--- a/components/browser_ui/styles/android/BUILD.gn
+++ b/components/browser_ui/styles/android/BUILD.gn
@@ -174,7 +174,6 @@
     "java/res/values-night/drawables.xml",
     "java/res/values-night/values.xml",
     "java/res/values-sw600dp-v27/styles.xml",
-    "java/res/values-sw600dp/dimens.xml",
     "java/res/values-v27/styles.xml",
     "java/res/values/colors.xml",
     "java/res/values/dimens.xml",
diff --git a/components/browser_ui/styles/android/java/res/values/dimens.xml b/components/browser_ui/styles/android/java/res/values/dimens.xml
index bebc0e1..263d8e5 100644
--- a/components/browser_ui/styles/android/java/res/values/dimens.xml
+++ b/components/browser_ui/styles/android/java/res/values/dimens.xml
@@ -16,7 +16,4 @@
 
     <!-- Toolbar dimensions -->
     <dimen name="toolbar_shadow_height">8dp</dimen>
-
-    <!-- Tab Strip Dimensions -->
-    <dimen name="tab_strip_height">0dp</dimen>
 </resources>
diff --git a/components/image_fetcher/ios/webp_decoder.h b/components/image_fetcher/ios/webp_decoder.h
index 8135b30..76cf2cb3 100644
--- a/components/image_fetcher/ios/webp_decoder.h
+++ b/components/image_fetcher/ios/webp_decoder.h
@@ -21,9 +21,7 @@
 class WebpDecoder : public base::RefCountedThreadSafe<WebpDecoder> {
  public:
   // Format of the decoded image.
-  // This enum is used for UMA reporting, keep it in sync with the histogram
-  // definition.
-  enum DecodedImageFormat { JPEG = 1, PNG, TIFF, DECODED_FORMAT_COUNT };
+  enum DecodedImageFormat { JPEG = 1, PNG, TIFF };
 
   class Delegate : public base::RefCountedThreadSafe<WebpDecoder::Delegate> {
    public:
diff --git a/components/image_fetcher/ios/webp_decoder.mm b/components/image_fetcher/ios/webp_decoder.mm
index 294bbc83..7ca4bbb3 100644
--- a/components/image_fetcher/ios/webp_decoder.mm
+++ b/components/image_fetcher/ios/webp_decoder.mm
@@ -10,7 +10,6 @@
 #include <stdint.h>
 
 #include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -298,8 +297,6 @@
   } else {
     result_data = output_buffer_;
   }
-  UMA_HISTOGRAM_ENUMERATION("WebP.DecodedImageFormat", format,
-                            DECODED_FORMAT_COUNT);
   delegate_->SetImageFeatures([result_data length], format);
   delegate_->OnDataDecoded(result_data);
   output_buffer_ = nil;
diff --git a/components/image_fetcher/ios/webp_decoder_unittest.mm b/components/image_fetcher/ios/webp_decoder_unittest.mm
index 478679ed..5c1d798 100644
--- a/components/image_fetcher/ios/webp_decoder_unittest.mm
+++ b/components/image_fetcher/ios/webp_decoder_unittest.mm
@@ -81,9 +81,6 @@
       case WebpDecoder::TIFF:
         ADD_FAILURE() << "Data already decompressed";
         return nil;
-      case WebpDecoder::DECODED_FORMAT_COUNT:
-        ADD_FAILURE() << "Unknown format";
-        return nil;
     }
     size_t width = CGImageGetWidth(image);
     size_t height = CGImageGetHeight(image);
diff --git a/components/media_router/browser/route_message_util.cc b/components/media_router/browser/route_message_util.cc
index 123210e..a240d736 100644
--- a/components/media_router/browser/route_message_util.cc
+++ b/components/media_router/browser/route_message_util.cc
@@ -4,7 +4,9 @@
 
 #include "components/media_router/browser/route_message_util.h"
 
+#include "base/json/json_writer.h"
 #include "base/macros.h"
+#include "base/values.h"
 
 using media_router::mojom::RouteMessage;
 using media_router::mojom::RouteMessagePtr;
@@ -12,6 +14,13 @@
 namespace media_router {
 namespace message_util {
 
+media_router::mojom::RouteMessagePtr RouteMessageFromValue(
+    base::Value message) {
+  std::string str;
+  CHECK(base::JSONWriter::Write(message, &str));
+  return RouteMessageFromString(std::move(str));
+}
+
 RouteMessagePtr RouteMessageFromString(std::string message) {
   auto route_message = RouteMessage::New();
   route_message->type = RouteMessage::Type::TEXT;
diff --git a/components/media_router/browser/route_message_util.h b/components/media_router/browser/route_message_util.h
index 5f789af..9e2a5914 100644
--- a/components/media_router/browser/route_message_util.h
+++ b/components/media_router/browser/route_message_util.h
@@ -12,9 +12,15 @@
 #include "components/media_router/common/mojom/media_router.mojom.h"
 #include "third_party/blink/public/mojom/presentation/presentation.mojom.h"
 
+namespace base {
+class Value;
+}  // namespace base
+
 namespace media_router {
 namespace message_util {
 
+media_router::mojom::RouteMessagePtr RouteMessageFromValue(base::Value value);
+
 media_router::mojom::RouteMessagePtr RouteMessageFromString(
     std::string message);
 
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacadeProvider.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacadeProvider.java
index 7c6c768..45e30f1c9 100644
--- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacadeProvider.java
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacadeProvider.java
@@ -77,7 +77,9 @@
     @CalledByNative
     public static AccountManagerFacade getInstance() {
         AccountManagerFacade instance = sAtomicInstance.get();
-        assert instance != null : "AccountManagerFacade is not initialized!";
+        if (instance == null) {
+            throw new IllegalStateException("AccountManagerFacade is not yet initialized!");
+        }
         return instance;
     }
 }
diff --git a/components/signin/core/browser/android/junit/src/org/chromium/components/signin/test/AccountManagerFacadeRobolectricTest.java b/components/signin/core/browser/android/junit/src/org/chromium/components/signin/test/AccountManagerFacadeRobolectricTest.java
index 6e5c80a..82b30eb2 100644
--- a/components/signin/core/browser/android/junit/src/org/chromium/components/signin/test/AccountManagerFacadeRobolectricTest.java
+++ b/components/signin/core/browser/android/junit/src/org/chromium/components/signin/test/AccountManagerFacadeRobolectricTest.java
@@ -31,6 +31,7 @@
 import org.chromium.components.signin.AccountManagerDelegateException;
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.AccountManagerFacadeImpl;
+import org.chromium.components.signin.AccountManagerFacadeProvider;
 import org.chromium.components.signin.AccountUtils;
 import org.chromium.components.signin.ChildAccountStatus;
 import org.chromium.components.signin.test.util.AccountHolder;
@@ -223,6 +224,12 @@
         assertChildAccountStatus(bothAccount, ChildAccountStatus.REGULAR_CHILD);
     }
 
+    @Test(expected = IllegalStateException.class)
+    @SmallTest
+    public void testAccountManagerFacadeProviderGetNullInstance() {
+        AccountManagerFacadeProvider.getInstance();
+    }
+
     private Account addTestAccount(String accountEmail, String... features) {
         AccountHolder holder = AccountHolder.builder(accountEmail)
                                        .alwaysAccept(true)
diff --git a/components/test/data/autofill/heuristics/input/174_i18n_id.html b/components/test/data/autofill/heuristics/input/174_i18n_id.html
new file mode 100644
index 0000000..3d9c2d49e
--- /dev/null
+++ b/components/test/data/autofill/heuristics/input/174_i18n_id.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+    <title></title>
+  </head>
+  <body>
+    <form action="http://www.google.com/" method="post">
+      <label for="fn">Nama Depan:</label> <input type="text" id="fn"><br>
+      <label for="ln">Nama Belakang:</label> <input type="text" id="ln"><br>
+      <label for="cm">Nama Perusahaan:</label> <input type="text" id="cm"><br>
+      <label for="a1">Alamat:</label> <input type="text" id="a1"><br>
+      <label for="st">Provinci:</label> <input type="text" id="st"><br>
+      <label for="ct">Kota/Kabupaten:</label> <input type="text" id="ct"><br>
+      <label for="dl">Kecamatan:</label> <input type="text" id="dl"><br>
+      <label for="zc">Kode Pos:</label> <input type="text" id="zc"><br>
+      <label for="em">Email:</label> <input type="text" id="em"><br>
+      <label for="ph">Nomor Telepon:</label> <input type="text" id="ph"><br>
+      <label for="c1">Nama di kartu:</label> <input type="text" id="c1"><br>
+      <label for="c2">Nomor Kartu:</label> <input type="text" id="c2"><br>
+      <label for="c3">Masa Berlaku:</label> <input type="text" id="c3"><br>
+      <label for="c4">Masa Berlaku:</label> <input type="text" id="c4"><br>
+    </form>
+  </body>
+</html>
\ No newline at end of file
diff --git a/components/test/data/autofill/heuristics/input/175_id_address_alfacart.com.html b/components/test/data/autofill/heuristics/input/175_id_address_alfacart.com.html
new file mode 100644
index 0000000..278b3f95
--- /dev/null
+++ b/components/test/data/autofill/heuristics/input/175_id_address_alfacart.com.html
@@ -0,0 +1,118 @@
+<form id="tambah-alamat" class="form-horizontal" novalidate="novalidate">
+  <div class="form-group">
+    <div class="col-xs-12">
+      <label for="alamat" class="control-label">Nama Alamat <span class="asterisk-alert">*</span></label>
+      <input type="text" class="form-control" id="txtAddAddressNewAddress" name="txtAddAddressNewAddress" placeholder=""
+        maxlength="30" autocomplete="off" aria-required="true">
+    </div>
+  </div>
+  <div class="form-group">
+    <div class="col-xs-6">
+      <label for="nama" class="control-label">Nama Penerima <span class="asterisk-alert">*</span></label>
+      <input type="text" class="form-control" id="txtNameNewAddress" name="txtNameNewAddress" placeholder=""
+        maxlength="30" autocomplete="off" aria-required="true">
+    </div>
+    <div class="col-xs-6">
+      <label for="telephone" class="control-label">Telepon <span class="asterisk-alert">*</span></label>
+      <input type="tel" class="form-control" id="txtHandphoneNewAddress" name="txtHandphoneNewAddress" placeholder=""
+        maxlength="16" autocomplete="off" aria-required="true">
+    </div>
+  </div>
+  <div class="form-group">
+    <div class="col-xs-6">
+      <label for="provinsi" class="control-label">Provinsi <span class="asterisk-alert">*</span></label>
+      <select class="form-control" id="listProvince" name="listProvince" aria-required="true">
+        <option value="">Pilih Provinsi</option>
+        <option value="51">BALI</option>
+        <option value="19">BANGKA BELITUNG</option>
+        <option value="36">BANTEN</option>
+        <option value="17">BENGKULU</option>
+        <option value="34">DI YOGYAKARTA</option>
+        <option value="31">DKI JAKARTA</option>
+        <option value="75">GORONTALO</option>
+        <option value="15">JAMBI</option>
+        <option value="32">JAWA BARAT</option>
+        <option value="33">JAWA TENGAH</option>
+        <option value="35">JAWA TIMUR</option>
+        <option value="61">KALIMANTAN BARAT</option>
+        <option value="63">KALIMANTAN SELATAN</option>
+        <option value="62">KALIMANTAN TENGAH</option>
+        <option value="64">KALIMANTAN TIMUR</option>
+        <option value="65">KALIMANTAN UTARA</option>
+        <option value="82">KEPULAUAN MALUKU</option>
+        <option value="21">KEPULAUAN RIAU</option>
+        <option value="18">LAMPUNG</option>
+        <option value="81">MALUKU</option>
+        <option value="11">NANGGROE ACEH DARUSSALAM (NAD)</option>
+        <option value="52">NUSA TENGGARA BARAT (NTB)</option>
+        <option value="53">NUSA TENGGARA TIMUR (NTT)</option>
+        <option value="94">PAPUA</option>
+        <option value="91">PAPUA BARAT</option>
+        <option value="14">RIAU</option>
+        <option value="76">SULAWESI BARAT</option>
+        <option value="73">SULAWESI SELATAN</option>
+        <option value="72">SULAWESI TENGAH</option>
+        <option value="74">SULAWESI TENGGARA</option>
+        <option value="71">SULAWESI UTARA</option>
+        <option value="13">SUMATERA BARAT</option>
+        <option value="16">SUMATERA SELATAN</option>
+        <option value="12">SUMATERA UTARA</option>
+      </select>
+    </div>
+    <div class="col-xs-6">
+      <label for="KotaKabupaten" class="control-label">Kota/kabupaten <span class="asterisk-alert">*</span></label>
+      <select class="form-control" id="listCity" name="listCity" aria-required="true">
+        <option value="">Pilih Kabupaten</option>
+      </select>
+    </div>
+  </div>
+  <div class="form-group">
+    <div class="col-xs-6">
+      <label for="kecamatan" class="control-label">Kecamatan <span class="asterisk-alert">*</span></label>
+      <select class="form-control" id="listDistrict" name="listDistrict" aria-required="true">
+        <option value="">Pilih Kecamatan</option>
+      </select>
+    </div>
+    <div class="col-xs-6">
+      <label for="kelurahan" class="control-label">Kelurahan <span class="asterisk-alert">*</span></label>
+      <select class="form-control" id="listVillage" name="listVillage" aria-required="true">
+        <option value="">Pilih Kelurahan</option>
+      </select>
+    </div>
+  </div>
+  <div class="form-group">
+    <div class="col-xs-12">
+      <label for="alamatlengkap" class="control-label">Alamat <span class="asterisk-alert">*</span></label>
+      <textarea class="form-control" id="txtAddressNewAddress" name="txtAddressNewAddress" placeholder=""
+        aria-required="true"></textarea>
+      <p class="error_validate" style="color:#999; font-style:italic;">Mohon masukkan alamat dengan lengkap (Nama Jalan,
+        Nama Perumahan, Blok Rumah, Nomor Rumah, RT/RW).</p>
+    </div>
+  </div>
+  <div class="form-group">
+    <div class="col-xs-6">
+      <label for="kodepos" class="control-label">Kode pos <span class="asterisk-alert">*</span></label>
+      <input type="text" class="form-control" id="txtPostalCodeNewAddress" name="txtPostalCodeNewAddress" placeholder=""
+        maxlength="5" autocomplete="off" aria-required="true">
+    </div>
+  </div>
+  <div class="form-group">
+    <div class="col-xs-12">
+      <div id="address-map" class="pin-alamat" data-attr="addAddress" data-mapid="map" data-inputid="pac-input"></div>
+    </div>
+  </div>
+  <input type="hidden" id="addLat" name="addressLat" value="">
+  <input type="hidden" id="addLng" name="addressLng" value="">
+  <div class="form-group">
+    <div class="col-xs-offset-4 col-xs-8 alamat-checkbox">
+      <input type="checkbox" id="isDelivery" name="isDelivery"> Atur Sebagai Default Pengiriman
+    </div>
+  </div>
+  <div class="form-group">
+    <div class="col-xs-8"></div>
+    <div class="col-xs-4">
+      <button type="button" id="btnAddNewAddress"
+        class="btn btn-default btn-simpan btn-simpan-small2 mb-10">SIMPAN</button>
+    </div>
+  </div>
+</form>
\ No newline at end of file
diff --git a/components/test/data/autofill/heuristics/input/176_id_payment_shopee.co.id.html b/components/test/data/autofill/heuristics/input/176_id_payment_shopee.co.id.html
new file mode 100644
index 0000000..48a3b89
--- /dev/null
+++ b/components/test/data/autofill/heuristics/input/176_id_payment_shopee.co.id.html
@@ -0,0 +1,71 @@
+<div class="shopee-popup-form shopee-popup-form--credit-card">
+  <div class="shopee-popup-form__header">
+    <div class="shopee-popup-form__title">Tambah Kartu Kredit Baru</div>
+  </div>
+  <div class="shopee-popup-form__main">
+    <div class="shopee-popup-form__main-container">
+      <div class="shopee-popup-form__server-error"></div>
+      <div class="_2FTWh8">
+        <div class="_2syZgE"><input class="_3FAIsa" type="text" placeholder="Nama Tertera di Kartu" value=""></div>
+        <div></div>
+      </div>
+      <div class="input-credit-card">
+        <div class="input-credit-card__input">
+          <div class="_2FTWh8">
+            <div class="_2syZgE lLictc"><input class="_3FAIsa" type="text" placeholder="No. Kartu Kredit" maxlength="19"
+                value=""></div>
+            <div><span class="_3o6Z5s shopee-modal__transition-enter-done">Mohon isi di kolom berikut</span></div>
+          </div>
+        </div>
+        <div class="input-credit-card__logo-wrapper"><span
+            class="input-credit-card__logo input-credit-card__logo--visa input-credit-card__logo--grey"></span></div>
+        <div class="input-credit-card__logo-wrapper"><span
+            class="input-credit-card__logo input-credit-card__logo--mastercard input-credit-card__logo--grey"></span>
+        </div>
+        <div class="input-credit-card__logo-wrapper"><span
+            class="input-credit-card__logo input-credit-card__logo--jcb input-credit-card__logo--grey"></span></div>
+        <div class="input-credit-card__logo-wrapper"><span
+            class="input-credit-card__logo input-credit-card__logo--amex input-credit-card__logo--grey"></span></div>
+      </div>
+      <div class="row">
+        <div class="col-xs-6">
+          <div class="shopee-popup-form__subheader">
+            <div class="shopee-popup-form__subheader-text">Kadaluarsa pada</div>
+          </div>
+        </div>
+        <div class="col-xs-6">
+          <div class="shopee-popup-form__subheader">
+            <div class="shopee-popup-form__subheader-text">CVV</div>
+          </div>
+        </div>
+      </div>
+      <div class="row">
+        <div class="col-xs-6">
+          <div class="_2FTWh8">
+            <div class="_2syZgE lLictc"><input class="_3FAIsa" type="text" placeholder="MM/YY" maxlength="5" value=""></div>
+            <div><span class="_3o6Z5s shopee-modal__transition-enter-done">Tanggal Kedaluwarsa Tidak Sah</span></div>
+          </div>
+        </div>
+        <div class="col-xs-6">
+          <div class="_2FTWh8">
+            <div class="_2syZgE"><input class="_3FAIsa" type="text" placeholder="000" maxlength="4" value=""></div>
+            <div></div>
+          </div>
+        </div>
+      </div>
+      <div class="_2FTWh8">
+        <div class="_2syZgE"><input class="_3FAIsa" type="text" placeholder="Alamat Tagihan" maxlength="1000" value="">
+        </div>
+        <div></div>
+      </div>
+      <div class="_2FTWh8">
+        <div class="_2syZgE"><input class="_3FAIsa" type="text" placeholder="Kode Pos" maxlength="100" value=""></div>
+        <div></div>
+      </div>
+      <div class="shopee-popup-form__message">Kami bekerja sama dengan NicePay untuk memastikan bahwa informasi kartu
+        kredit Anda tetap terlindungi. Shopee tidak akan mengakses info kartu kredit Anda.</div>
+    </div>
+  </div>
+  <div class="shopee-popup-form__footer"><button class="cancel-btn">Nanti Saja</button><button type="button"
+      class="btn btn-solid-primary btn--s btn--inline khi9AY" aria-disabled="false">OK</button></div>
+</div>
\ No newline at end of file
diff --git a/components/test/data/autofill/heuristics/output/174_i18n_id.out b/components/test/data/autofill/heuristics/output/174_i18n_id.out
new file mode 100644
index 0000000..ec643405
--- /dev/null
+++ b/components/test/data/autofill/heuristics/output/174_i18n_id.out
@@ -0,0 +1,14 @@
+NAME_FIRST | fn | Nama Depan: |  | fn_1-default
+NAME_LAST | ln | Nama Belakang: |  | fn_1-default
+COMPANY_NAME | cm | Nama Perusahaan: |  | fn_1-default
+ADDRESS_HOME_LINE1 | a1 | Alamat: |  | fn_1-default
+ADDRESS_HOME_STATE | st | Provinci: |  | fn_1-default
+ADDRESS_HOME_CITY | ct | Kota/Kabupaten: |  | fn_1-default
+ADDRESS_HOME_DEPENDENT_LOCALITY | dl | Kecamatan: |  | fn_1-default
+ADDRESS_HOME_ZIP | zc | Kode Pos: |  | fn_1-default
+EMAIL_ADDRESS | em | Email: |  | fn_1-default
+PHONE_HOME_WHOLE_NUMBER | ph | Nomor Telepon: |  | fn_1-default
+CREDIT_CARD_NAME_FULL | c1 | Nama di kartu: |  | credit-card-cc
+CREDIT_CARD_NUMBER | c2 | Nomor Kartu: |  | credit-card-cc
+CREDIT_CARD_EXP_MONTH | c3 | Masa Berlaku: |  | credit-card-cc
+CREDIT_CARD_EXP_4_DIGIT_YEAR | c4 | Masa Berlaku: |  | credit-card-cc
diff --git a/components/test/data/autofill/heuristics/output/175_id_address_alfacart.com.out b/components/test/data/autofill/heuristics/output/175_id_address_alfacart.com.out
new file mode 100644
index 0000000..07034a8
--- /dev/null
+++ b/components/test/data/autofill/heuristics/output/175_id_address_alfacart.com.out
@@ -0,0 +1,10 @@
+UNKNOWN_TYPE | txtAddAddressNewAddress | Nama Alamat * |  | txtAddAddressNewAddress_1-default
+NAME_FULL | txtNameNewAddress | Nama Penerima * |  | txtAddAddressNewAddress_1-default
+PHONE_HOME_WHOLE_NUMBER | txtHandphoneNewAddress | Telepon * |  | txtAddAddressNewAddress_1-default
+ADDRESS_HOME_STATE | listProvince | Provinsi * |  | txtAddAddressNewAddress_1-default
+ADDRESS_HOME_CITY | listCity | Kota/kabupaten * |  | txtAddAddressNewAddress_1-default
+ADDRESS_HOME_DEPENDENT_LOCALITY | listDistrict | Kecamatan * |  | txtAddAddressNewAddress_1-default
+UNKNOWN_TYPE | listVillage | Kelurahan * |  | txtAddAddressNewAddress_1-default
+ADDRESS_HOME_STREET_ADDRESS | txtAddressNewAddress | Alamat * |  | txtAddAddressNewAddress_1-default
+ADDRESS_HOME_ZIP | txtPostalCodeNewAddress | Kode pos * |  | txtAddAddressNewAddress_1-default
+UNKNOWN_TYPE | isDelivery | Atur Sebagai Default Pengiriman | on | txtAddAddressNewAddress_1-default
diff --git a/components/test/data/autofill/heuristics/output/176_id_payment_shopee.co.id.out b/components/test/data/autofill/heuristics/output/176_id_payment_shopee.co.id.out
new file mode 100644
index 0000000..8749fd46
--- /dev/null
+++ b/components/test/data/autofill/heuristics/output/176_id_payment_shopee.co.id.out
@@ -0,0 +1,6 @@
+CREDIT_CARD_NAME_FULL |  | Nama Tertera di Kartu |  | credit-card-cc
+CREDIT_CARD_NUMBER |  | No. Kartu Kredit |  | credit-card-cc
+CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR |  | MM/YY |  | credit-card-cc
+UNKNOWN_TYPE |  | 000 |  | _2-default
+ADDRESS_HOME_LINE1 |  | Alamat Tagihan |  | _2-default
+ADDRESS_HOME_ZIP |  | Kode Pos |  | _2-default
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index b9159fa8..1703a41 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -1011,11 +1011,10 @@
   // Enable PCScan once we are certain that FeatureList was initialized.
   EnablePCScanForMallocPartitionsIfNeeded();
 
-  // This is only relevant for PartitionAlloc-Everywhere builds.
-  // Temporarily disabled for non-DCHECK() builds on Windows, due to possibly
-  // related crashes (crbug.com/1155905).
-#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \
-    !(defined(OS_WIN) && !DCHECK_IS_ON())
+  // This is only relevant for PartitionAlloc-Everywhere builds. Temporarily
+  // disabled for non-DCHECK() builds, due to possibly related crashes
+  // (crbug.com/1155905).
+#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && DCHECK_IS_ON()
   base::internal::ThreadCacheRegistry::Instance().StartPeriodicPurge();
 #endif
 
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index c42496ec..fe956cf3 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -58,6 +58,7 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/url_constants.h"
+#include "device/gamepad/gamepad_haptics_manager.h"
 #include "device/gamepad/gamepad_monitor.h"
 #include "device/gamepad/public/mojom/gamepad.mojom.h"
 #include "device/vr/buildflags/buildflags.h"
@@ -588,6 +589,9 @@
   map->Add<blink::mojom::FileSystemManager>(base::BindRepeating(
       &RenderFrameHostImpl::GetFileSystemManager, base::Unretained(host)));
 
+  map->Add<device::mojom::GamepadHapticsManager>(
+      base::BindRepeating(&device::GamepadHapticsManager::Create));
+
   map->Add<blink::mojom::GeolocationService>(base::BindRepeating(
       &RenderFrameHostImpl::GetGeolocationService, base::Unretained(host)));
 
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index b5d6575b..c0daa618 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -8842,7 +8842,12 @@
   // renderer one. The browser will just "push" the correct value.
   if (navigation_request->state() >=
       NavigationRequest::NavigationState::WILL_PROCESS_RESPONSE) {
-    DCHECK_EQ(params.sandbox_flags, navigation_request->SandboxFlagsToCommit());
+    // TODO(https://crbug.com/1163108):
+    // - params.sandbox_flags and
+    // - navigation_request->SandboxFlagsToCommit()
+    // must match here. They don't, because of CSP embedded enforcement.
+    //
+    // This should be fixed and the DCHECK restored.
   }
 
   coep_reporter_ = navigation_request->TakeCoepReporter();
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index a8f3d08..b5e34e7 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -173,7 +173,6 @@
 #include "content/public/common/sandboxed_process_launcher_delegate.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/common/zygote/zygote_buildflags.h"
-#include "device/gamepad/gamepad_haptics_manager.h"
 #include "google_apis/gaia/gaia_switches.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/gpu_switches.h"
@@ -2293,9 +2292,6 @@
           {base::TaskPriority::USER_BLOCKING, base::MayBlock()}));
 #endif
 
-  registry->AddInterface(
-      base::BindRepeating(&device::GamepadHapticsManager::Create));
-
   AddUIThreadInterface(
       registry.get(),
       base::BindRepeating(&RenderProcessHostImpl::BindPushMessagingManager,
diff --git a/content/child/child_process_sandbox_support_impl_mac.cc b/content/child/child_process_sandbox_support_impl_mac.cc
index 20fa9f5..55ece81f 100644
--- a/content/child/child_process_sandbox_support_impl_mac.cc
+++ b/content/child/child_process_sandbox_support_impl_mac.cc
@@ -59,9 +59,8 @@
       out_descriptor);
 }
 
-SkColor WebSandboxSupportMac::GetSystemColor(
-    blink::MacSystemColorID color_id,
-    blink::mojom::ColorScheme color_scheme) {
+SkColor WebSandboxSupportMac::GetSystemColor(blink::MacSystemColorID color_id,
+                                             blink::ColorScheme color_scheme) {
   if (!color_map_.IsValid()) {
     DLOG(ERROR) << "GetSystemColor does not have a valid color_map_";
     return SK_ColorMAGENTA;
@@ -70,11 +69,10 @@
                 "Light and dark color scheme system colors loaded.");
   base::span<const SkColor> color_map = color_map_.GetMemoryAsSpan<SkColor>(
       blink::kMacSystemColorIDCount * blink::kMacSystemColorSchemeCount);
-  base::span<const SkColor> color_map_for_scheme =
-      color_map.subspan(color_scheme == blink::mojom::ColorScheme::kDark
-                            ? blink::kMacSystemColorIDCount
-                            : 0,
-                        blink::kMacSystemColorIDCount);
+  base::span<const SkColor> color_map_for_scheme = color_map.subspan(
+      color_scheme == blink::ColorScheme::kDark ? blink::kMacSystemColorIDCount
+                                                : 0,
+      blink::kMacSystemColorIDCount);
   return color_map_for_scheme[static_cast<size_t>(color_id)];
 }
 
diff --git a/content/child/child_process_sandbox_support_impl_mac.h b/content/child/child_process_sandbox_support_impl_mac.h
index 96c9cbc..1456f46 100644
--- a/content/child/child_process_sandbox_support_impl_mac.h
+++ b/content/child/child_process_sandbox_support_impl_mac.h
@@ -29,7 +29,7 @@
                 base::ScopedCFTypeRef<CTFontDescriptorRef>* out_descriptor,
                 uint32_t* font_id) override;
   SkColor GetSystemColor(blink::MacSystemColorID color_id,
-                         blink::mojom::ColorScheme color_scheme) override;
+                         blink::ColorScheme color_scheme) override;
 
  private:
   void OnGotSystemColors(base::ReadOnlySharedMemoryRegion region);
diff --git a/content/child/webthemeengine_impl_android.cc b/content/child/webthemeengine_impl_android.cc
index a6be4c16..0696ab7 100644
--- a/content/child/webthemeengine_impl_android.cc
+++ b/content/child/webthemeengine_impl_android.cc
@@ -10,6 +10,7 @@
 #include "skia/ext/platform_canvas.h"
 #include "ui/native_theme/native_theme.h"
 
+using blink::ColorScheme;
 using blink::WebThemeEngine;
 
 namespace content {
@@ -155,7 +156,7 @@
     WebThemeEngine::State state,
     const gfx::Rect& rect,
     const WebThemeEngine::ExtraParams* extra_params,
-    blink::mojom::ColorScheme color_scheme) {
+    blink::ColorScheme color_scheme) {
   ui::NativeTheme::ExtraParams native_theme_extra_params;
   GetNativeThemeExtraParams(
       part, state, extra_params, &native_theme_extra_params);
diff --git a/content/child/webthemeengine_impl_android.h b/content/child/webthemeengine_impl_android.h
index aff6b7c..06cc7b81 100644
--- a/content/child/webthemeengine_impl_android.h
+++ b/content/child/webthemeengine_impl_android.h
@@ -21,7 +21,7 @@
              blink::WebThemeEngine::State state,
              const gfx::Rect& rect,
              const blink::WebThemeEngine::ExtraParams* extra_params,
-             blink::mojom::ColorScheme color_scheme) override;
+             blink::ColorScheme color_scheme) override;
   blink::ForcedColors GetForcedColors() const override;
   void SetForcedColors(const blink::ForcedColors forced_colors) override;
 };
diff --git a/content/child/webthemeengine_impl_conversions.cc b/content/child/webthemeengine_impl_conversions.cc
index fa3747b5..84509d4 100644
--- a/content/child/webthemeengine_impl_conversions.cc
+++ b/content/child/webthemeengine_impl_conversions.cc
@@ -84,11 +84,11 @@
 }
 
 ui::NativeTheme::ColorScheme NativeColorScheme(
-    blink::mojom::ColorScheme color_scheme) {
+    blink::ColorScheme color_scheme) {
   switch (color_scheme) {
-    case blink::mojom::ColorScheme::kLight:
+    case blink::ColorScheme::kLight:
       return ui::NativeTheme::ColorScheme::kLight;
-    case blink::mojom::ColorScheme::kDark:
+    case blink::ColorScheme::kDark:
       return ui::NativeTheme::ColorScheme::kDark;
   }
 }
diff --git a/content/child/webthemeengine_impl_conversions.h b/content/child/webthemeengine_impl_conversions.h
index 92f7826f..88858bc 100644
--- a/content/child/webthemeengine_impl_conversions.h
+++ b/content/child/webthemeengine_impl_conversions.h
@@ -22,7 +22,7 @@
     blink::WebThemeEngine::State state);
 
 CONTENT_EXPORT ui::NativeTheme::ColorScheme NativeColorScheme(
-    blink::mojom::ColorScheme color_scheme);
+    blink::ColorScheme color_scheme);
 
 CONTENT_EXPORT ui::NativeTheme::SystemThemeColor NativeSystemThemeColor(
     blink::WebThemeEngine::SystemThemeColor theme_color);
diff --git a/content/child/webthemeengine_impl_default.cc b/content/child/webthemeengine_impl_default.cc
index 312bc84..836fa111 100644
--- a/content/child/webthemeengine_impl_default.cc
+++ b/content/child/webthemeengine_impl_default.cc
@@ -10,9 +10,9 @@
 #include "ui/native_theme/native_theme.h"
 #include "ui/native_theme/overlay_scrollbar_constants_aura.h"
 
+using blink::ColorScheme;
 using blink::WebScrollbarOverlayColorTheme;
 using blink::WebThemeEngine;
-using blink::mojom::ColorScheme;
 
 namespace content {
 namespace {
@@ -185,7 +185,7 @@
     WebThemeEngine::State state,
     const gfx::Rect& rect,
     const WebThemeEngine::ExtraParams* extra_params,
-    blink::mojom::ColorScheme color_scheme) {
+    blink::ColorScheme color_scheme) {
   ui::NativeTheme::ExtraParams native_theme_extra_params;
   GetNativeThemeExtraParams(
       part, state, extra_params, &native_theme_extra_params);
diff --git a/content/child/webthemeengine_impl_default.h b/content/child/webthemeengine_impl_default.h
index 9da412ed..91715b8c 100644
--- a/content/child/webthemeengine_impl_default.h
+++ b/content/child/webthemeengine_impl_default.h
@@ -22,7 +22,7 @@
              blink::WebThemeEngine::State state,
              const gfx::Rect& rect,
              const blink::WebThemeEngine::ExtraParams* extra_params,
-             blink::mojom::ColorScheme color_scheme) override;
+             blink::ColorScheme color_scheme) override;
   void GetOverlayScrollbarStyle(
       blink::WebThemeEngine::ScrollbarStyle*) override;
   bool SupportsNinePatch(Part part) const override;
diff --git a/content/child/webthemeengine_impl_mac.cc b/content/child/webthemeengine_impl_mac.cc
index 009f761..d442351 100644
--- a/content/child/webthemeengine_impl_mac.cc
+++ b/content/child/webthemeengine_impl_mac.cc
@@ -14,7 +14,7 @@
                               WebThemeEngine::State state,
                               const gfx::Rect& rect,
                               const WebThemeEngine::ExtraParams* extra_params,
-                              blink::mojom::ColorScheme color_scheme) {
+                              blink::ColorScheme color_scheme) {
   if (IsScrollbarPart(part)) {
     PaintMacScrollBarParts(canvas, part, state, rect, extra_params,
                            color_scheme);
@@ -44,7 +44,7 @@
     WebThemeEngine::State state,
     const gfx::Rect& rect,
     const WebThemeEngine::ExtraParams* extra_params,
-    blink::mojom::ColorScheme color_scheme) {
+    blink::ColorScheme color_scheme) {
   ui::NativeTheme::ExtraParams native_theme_extra_params;
   native_theme_extra_params.scrollbar_extra.is_hovering =
       extra_params->scrollbar_extra.is_hovering;
diff --git a/content/child/webthemeengine_impl_mac.h b/content/child/webthemeengine_impl_mac.h
index 64b17c7..6a3aac0 100644
--- a/content/child/webthemeengine_impl_mac.h
+++ b/content/child/webthemeengine_impl_mac.h
@@ -18,7 +18,7 @@
              blink::WebThemeEngine::State state,
              const gfx::Rect& rect,
              const blink::WebThemeEngine::ExtraParams* extra_params,
-             blink::mojom::ColorScheme color_scheme) override;
+             blink::ColorScheme color_scheme) override;
 
   static bool IsScrollbarPart(WebThemeEngine::Part part);
   static void PaintMacScrollBarParts(
@@ -27,7 +27,7 @@
       WebThemeEngine::State state,
       const gfx::Rect& rect,
       const WebThemeEngine::ExtraParams* extra_params,
-      blink::mojom::ColorScheme color_scheme);
+      blink::ColorScheme color_scheme);
 };
 
 }  // namespace content
diff --git a/content/child/webthemeengine_impl_unittest.cc b/content/child/webthemeengine_impl_unittest.cc
index 45bf16a6..45c2598d 100644
--- a/content/child/webthemeengine_impl_unittest.cc
+++ b/content/child/webthemeengine_impl_unittest.cc
@@ -97,8 +97,8 @@
 }
 
 TEST(WebThemeEngineTest, NativeColorScheme) {
-  std::vector<blink::mojom::ColorScheme> blink_inputs = {
-      blink::mojom::ColorScheme::kLight, blink::mojom::ColorScheme::kDark};
+  std::vector<blink::ColorScheme> blink_inputs = {blink::ColorScheme::kLight,
+                                                  blink::ColorScheme::kDark};
 
   std::vector<ui::NativeTheme::ColorScheme> native_theme_outputs = {
       ui::NativeTheme::ColorScheme::kLight,
diff --git a/gin/BUILD.gn b/gin/BUILD.gn
index dfc59c1..4fa8514 100644
--- a/gin/BUILD.gn
+++ b/gin/BUILD.gn
@@ -75,6 +75,10 @@
 
   defines = [ "GIN_IMPLEMENTATION" ]
 
+  if (use_perfetto_client_library) {
+    defines += [ "V8_USE_PERFETTO" ]
+  }
+
   public_deps = [
     "//base",
     "//v8",
diff --git a/gin/v8_platform.cc b/gin/v8_platform.cc
index 27c300ff..af8c64e 100644
--- a/gin/v8_platform.cc
+++ b/gin/v8_platform.cc
@@ -22,6 +22,7 @@
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
 #include "base/trace_event/trace_event.h"
+#include "base/tracing_buildflags.h"
 #include "build/build_config.h"
 #include "gin/per_isolate_data.h"
 
@@ -371,6 +372,7 @@
   ~TracingControllerImpl() override = default;
 
   // TracingController implementation.
+#if !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
   const uint8_t* GetCategoryGroupEnabled(const char* name) override {
     return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(name);
   }
@@ -438,6 +440,7 @@
     TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_enabled_flag, name,
                                                 traceEventHandle);
   }
+#endif  // !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
   void AddTraceStateObserver(TraceStateObserver* observer) override {
     g_trace_state_dispatcher.Get().AddObserver(observer);
   }
diff --git a/ios/chrome/browser/autofill/BUILD.gn b/ios/chrome/browser/autofill/BUILD.gn
index 0b2debc2..e09fd5b 100644
--- a/ios/chrome/browser/autofill/BUILD.gn
+++ b/ios/chrome/browser/autofill/BUILD.gn
@@ -364,6 +364,9 @@
     "//components/test/data/autofill/heuristics/input/171_i18n_ru_structured_address_2.html",
     "//components/test/data/autofill/heuristics/input/172_i18n_pt_structured_address_1.html",
     "//components/test/data/autofill/heuristics/input/173_i18n_pt_structured_address_2.html",
+    "//components/test/data/autofill/heuristics/input/174_i18n_id.html",
+    "//components/test/data/autofill/heuristics/input/175_id_address_alfacart.com.html",
+    "//components/test/data/autofill/heuristics/input/176_id_payment_shopee.co.id.html",
     "//components/test/data/autofill/heuristics/output/000_i18n_de.out",
     "//components/test/data/autofill/heuristics/output/001_i18n_de2.out",
     "//components/test/data/autofill/heuristics/output/002_i18n_en.out",
@@ -537,6 +540,9 @@
     "//components/test/data/autofill/heuristics/output/171_i18n_ru_structured_address_2.out",
     "//components/test/data/autofill/heuristics/output/172_i18n_pt_structured_address_1.out",
     "//components/test/data/autofill/heuristics/output/173_i18n_pt_structured_address_2.out",
+    "//components/test/data/autofill/heuristics/output/174_i18n_id.out",
+    "//components/test/data/autofill/heuristics/output/175_id_address_alfacart.com.out",
+    "//components/test/data/autofill/heuristics/output/176_id_payment_shopee.co.id.out",
   ]
   outputs = [ "{{bundle_resources_dir}}/" +
               "{{source_root_relative_dir}}/{{source_file_part}}" ]
diff --git a/ios/chrome/browser/autofill/form_structure_browsertest.mm b/ios/chrome/browser/autofill/form_structure_browsertest.mm
index c20605b..cc8a9ac 100644
--- a/ios/chrome/browser/autofill/form_structure_browsertest.mm
+++ b/ios/chrome/browser/autofill/form_structure_browsertest.mm
@@ -142,6 +142,8 @@
           autofill::features::kAutofillUseNewSectioningMethod,
           // TODO(crbug.com/1150890) Remove once launched
           autofill::features::kAutofillEnableAugmentedPhoneCountryCode,
+          // TODO(crbug.com/1157405) Remove once launched.
+          autofill::features::kAutofillEnableDependentLocalityParsing,
       },
       // Disabled
       {autofill::features::kAutofillRestrictUnownedFieldsToFormlessCheckout});
diff --git a/ios/chrome/browser/ui/authentication/signin/BUILD.gn b/ios/chrome/browser/ui/authentication/signin/BUILD.gn
index 1c49878..2948e8d 100644
--- a/ios/chrome/browser/ui/authentication/signin/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/signin/BUILD.gn
@@ -115,6 +115,7 @@
     "//components/signin/public/base",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/ui/authentication:eg_test_support+eg2",
+    "//ios/chrome/browser/ui/authentication/unified_consent:constants",
     "//ios/chrome/browser/ui/content_suggestions:feature_flags",
     "//ios/chrome/browser/ui/recent_tabs:recent_tabs_ui_constants",
     "//ios/chrome/browser/ui/settings:constants",
diff --git a/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm b/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm
index ef16531..a1a8562 100644
--- a/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm
+++ b/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm
@@ -8,6 +8,7 @@
 #import "base/test/ios/wait_util.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h"
+#import "ios/chrome/browser/ui/authentication/unified_consent/unified_consent_constants.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h"
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_constants.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -335,6 +336,29 @@
 
 // Tests to dismiss sign-in by opening an URL from another app.
 // Sign-in opened from: recent tabs.
+// Interrupted at: identity selection in user consent.
+- (void)testDismissIdentityPickerSigninFromRecentTabs {
+  FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeIdentity1];
+  [SigninEarlGrey addFakeIdentity:fakeIdentity];
+  [self openSigninFromView:OpenSigninMethodFromRecentTabs tapSettingsLink:NO];
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kIdentityPickerViewIdentifier)]
+      performAction:grey_tap()];
+
+  // Open the URL as if it was opened from another app.
+  [ChromeEarlGrey simulateExternalAppURLOpening];
+
+  // Check if the URL was opened.
+  const GURL expectedURL("http://www.example.com/");
+  GREYAssertEqual(expectedURL, [ChromeEarlGrey webStateVisibleURL],
+                  @"Didn't open new tab with example.com.");
+
+  // Should be not signed in.
+  [SigninEarlGrey verifySignedOut];
+}
+
+// Tests to dismiss sign-in by opening an URL from another app.
+// Sign-in opened from: recent tabs.
 // Interrupted at: advanced sign-in.
 - (void)testDismissSigninFromRecentTabsFromAdvancedSigninSettings {
   [self assertOpenURLWhenSigninFromView:OpenSigninMethodFromRecentTabs
diff --git a/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_coordinator.mm b/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_coordinator.mm
index 5bd1c58..939088e 100644
--- a/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/signin/user_signin/user_signin_coordinator.mm
@@ -505,10 +505,10 @@
   __weak UserSigninCoordinator* weakSelf = self;
   ProceduralBlock runCompletionCallback = ^{
     [weakSelf
-        runCompletionCallbackWithSigninResult:SigninCoordinatorResultInterrupted
-                                     identity:self.unifiedConsentCoordinator
-                                                  .selectedIdentity
-                   showAdvancedSettingsSignin:NO];
+        viewControllerDismissedWithResult:SigninCoordinatorResultInterrupted
+                                 identity:weakSelf.unifiedConsentCoordinator
+                                              .selectedIdentity
+                    settingsLinkWasTapped:NO];
     if (completion) {
       completion();
     }
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm
index 5804e0a..358a6b9 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm
@@ -52,6 +52,11 @@
   [self.unifiedConsentMediator start];
 }
 
+- (void)stop {
+  [self.unifiedConsentViewController dismissViewControllerAnimated:YES
+                                                        completion:nil];
+}
+
 - (void)scrollToBottom {
   [self.unifiedConsentViewController scrollToBottom];
 }
diff --git a/ios/chrome/browser/ui/content_suggestions/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
index 86b12d1e..ebd44a4 100644
--- a/ios/chrome/browser/ui/content_suggestions/BUILD.gn
+++ b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
@@ -78,6 +78,7 @@
     "//ios/chrome/browser/ui/content_suggestions/identifier",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/favicon",
+    "//ios/chrome/browser/ui/main:scene_state_header",
     "//ios/chrome/browser/ui/menu",
     "//ios/chrome/browser/ui/ntp",
     "//ios/chrome/browser/ui/ntp:ntp_internal",
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
index f11ea41..ffbd136 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
@@ -61,6 +61,8 @@
 #import "ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.h"
 #import "ios/chrome/browser/ui/content_suggestions/ntp_home_metrics.h"
 #import "ios/chrome/browser/ui/content_suggestions/theme_change_delegate.h"
+#import "ios/chrome/browser/ui/main/scene_state.h"
+#import "ios/chrome/browser/ui/main/scene_state_browser_agent.h"
 #import "ios/chrome/browser/ui/menu/action_factory.h"
 #import "ios/chrome/browser/ui/menu/menu_histograms.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_feature.h"
@@ -546,6 +548,12 @@
   [self.alertCoordinator stop];
 }
 
+- (UIEdgeInsets)safeAreaInsetsForDiscoverFeed {
+  return [SceneStateBrowserAgent::FromBrowser(self.browser)
+              ->GetSceneState()
+              .window.rootViewController.view safeAreaInsets];
+}
+
 #pragma mark - ContentSuggestionsActionHandler
 
 - (void)loadMoreFeedArticles {
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_provider.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_provider.h
index 926ab44..1952fc6e 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_provider.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_provider.h
@@ -8,7 +8,8 @@
 // Object providing a header view for the content suggestions.
 @protocol ContentSuggestionsHeaderProvider
 
-- (nullable UIView*)headerForWidth:(CGFloat)width;
+- (nullable UIView*)headerForWidth:(CGFloat)width
+                    safeAreaInsets:(UIEdgeInsets)safeAreaInsets;
 
 @end
 
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
index db23bf1..c0c3f33 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
@@ -240,7 +240,8 @@
 
 #pragma mark - ContentSuggestionsHeaderProvider
 
-- (UIView*)headerForWidth:(CGFloat)width {
+- (UIView*)headerForWidth:(CGFloat)width
+           safeAreaInsets:(UIEdgeInsets)safeAreaInsets {
   if (!self.headerView) {
     self.headerView =
         base::mac::ObjCCastStrict<ContentSuggestionsHeaderView>(self.view);
@@ -265,12 +266,10 @@
     // screen new tab animation, it's safe to check the rootViewController's
     // view instead.
     // TODO(crbug.com/791784) : Remove use of rootViewController.
-    UIView* insetsView = self.headerView;
-    if (!self.headerView.window) {
-      insetsView =
-          [[UIApplication sharedApplication] keyWindow].rootViewController.view;
+    if (self.headerView.window) {
+      safeAreaInsets =
+          self.headerView.window.rootViewController.view.safeAreaInsets;
     }
-    UIEdgeInsets safeAreaInsets = insetsView.safeAreaInsets;
     width = std::max<CGFloat>(
         0, width - safeAreaInsets.left - safeAreaInsets.right);
 
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
index 2f867003..41fd202 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
@@ -426,7 +426,9 @@
 }
 
 - (UIView*)headerViewForWidth:(CGFloat)width {
-  return [self.headerProvider headerForWidth:width];
+  return [self.headerProvider
+      headerForWidth:width
+      safeAreaInsets:[self.discoverFeedDelegate safeAreaInsetsForDiscoverFeed]];
 }
 
 - (void)toggleArticlesVisibility {
diff --git a/ios/chrome/browser/ui/content_suggestions/discover_feed_delegate.h b/ios/chrome/browser/ui/content_suggestions/discover_feed_delegate.h
index 68775c3..95d4769 100644
--- a/ios/chrome/browser/ui/content_suggestions/discover_feed_delegate.h
+++ b/ios/chrome/browser/ui/content_suggestions/discover_feed_delegate.h
@@ -12,6 +12,9 @@
 // re-created.
 - (void)recreateDiscoverFeedViewController;
 
+// Returns current safe area insets for the window owning this discover feed.
+- (UIEdgeInsets)safeAreaInsetsForDiscoverFeed;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_DISCOVER_FEED_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm
index 10b25db2..66613ae5f 100644
--- a/ios/chrome/browser/ui/main/scene_controller.mm
+++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -807,10 +807,10 @@
   }
 
   // The UI should be stopped before the models they observe are stopped.
+  // |self.signinCoordinator| will be released on completion.
   [self.signinCoordinator
       interruptWithAction:SigninCoordinatorInterruptActionNoDismiss
                completion:nil];
-  self.signinCoordinator = nil;
 
   [self.historyCoordinator stop];
   self.historyCoordinator = nil;
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
index 10c55d1..52896ed 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-783fdce9361239c67ef90da92b63002f8a8a16bb
\ No newline at end of file
+ec62d4e787448453dd9f92aeb3ec18167107cad2
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
index 702eb46d..96d603f 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-88448df52a73ed2e5b6365fe5ca033ed7ee12965
\ No newline at end of file
+df15e92a2eddd979d030a45cef9aac717018459d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
index 597106f..64c581c 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-c21209e3f14d5f49551481b8a7cdcea317a2f78a
\ No newline at end of file
+ed0294aacd9ea39bbecb983550ab679afff60e50
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
index c57bc18..45a05c9 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-de42fae3da12db766861111cf754385671552273
\ No newline at end of file
+2e485b6c09ed55cc4820c6898ed9dd267057ee6c
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
index b3b48157..7472d13c 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-34ae96712865c59413fa82eced04d7e920fc7099
\ No newline at end of file
+c35aa6b405ee2876ad6b9bcfece04494bada136b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
index b338de9..64c3038 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-0dab37afa9a1369d17b5068d41e8cc506253af5f
\ No newline at end of file
+22005b98edbaa5dc66f41ac8c4c260e494ecf611
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
index 61c4a4b..951d5095 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-d5f1a5422dda86218a2cab42294093707dd993a6
\ No newline at end of file
+bf886e6104ce9c31c07aeb5b7f06ab8b4c1f487b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
index 172adcbf..bf172849 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-2b255503b156208d0d5b605adbbc56018a50721f
\ No newline at end of file
+1f6fbdf4c1fa1011a0ff5dfbb3353aef2e33f047
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
index d01f6c2..201cca25 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-102a6a7b33ff13b2aefc9e4ca4f8fa36b9f04a82
\ No newline at end of file
+a6266083e78d196b873c89541366a74f569e96f9
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
index a4d1f51..45aa623 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-9b0f42737c92b083515ad729cf51af0143322dbf
\ No newline at end of file
+8fa7b110021b04f254eb4671ac318a41caf22856
\ No newline at end of file
diff --git a/ios/third_party/material_components_ios/BUILD.gn b/ios/third_party/material_components_ios/BUILD.gn
index 530b02d..69d2ee5 100644
--- a/ios/third_party/material_components_ios/BUILD.gn
+++ b/ios/third_party/material_components_ios/BUILD.gn
@@ -235,6 +235,7 @@
   "src/components/List/src/MDCBaseCell.h",
   "src/components/List/src/MDCSelfSizingLayoutAttributes.h",
   "src/components/List/src/MDCSelfSizingStereoCell.h",
+  "src/components/List/src/MDCSelfSizingStereoCellImageViewVerticalPosition.h",
   "src/components/List/src/MaterialList.h",
   "src/components/List/src/Theming/MDCBaseCell+MaterialTheming.h",
   "src/components/List/src/Theming/MDCSelfSizingStereoCell+MaterialTheming.h",
@@ -1045,6 +1046,7 @@
   "src/components/List/src/MDCSelfSizingLayoutAttributes.h",
   "src/components/List/src/MDCSelfSizingStereoCell.h",
   "src/components/List/src/MDCSelfSizingStereoCell.m",
+  "src/components/List/src/MDCSelfSizingStereoCellImageViewVerticalPosition.h",
   "src/components/List/src/MaterialList.h",
   "src/components/List/src/Theming/MDCBaseCell+MaterialTheming.h",
   "src/components/List/src/Theming/MDCBaseCell+MaterialTheming.m",
diff --git a/media/fuchsia/audio/fuchsia_audio_renderer.cc b/media/fuchsia/audio/fuchsia_audio_renderer.cc
index 053d299c..2ad559a 100644
--- a/media/fuchsia/audio/fuchsia_audio_renderer.cc
+++ b/media/fuchsia/audio/fuchsia_audio_renderer.cc
@@ -524,7 +524,7 @@
     }
     stream_sink_->EndOfStream();
 
-    // No more data is going to be biffered. Update buffering state to ensure
+    // No more data is going to be buffered. Update buffering state to ensure
     // RendererImpl starts playback in case it was waiting for buffering to
     // finish.
     SetBufferState(BUFFERING_HAVE_ENOUGH);
diff --git a/services/network/public/cpp/content_security_policy/content_security_policy.cc b/services/network/public/cpp/content_security_policy/content_security_policy.cc
index 4efaee6..1bf2311 100644
--- a/services/network/public/cpp/content_security_policy/content_security_policy.cc
+++ b/services/network/public/cpp/content_security_policy/content_security_policy.cc
@@ -971,13 +971,15 @@
             directive_name, directive.second, out->parsing_errors);
         break;
       case CSPDirectiveName::Sandbox:
-        // Note: |ParseSandboxPolicy(...).error_message| is ignored here.
-        // Blink's CSP parser is already in charge of displaying it.
+        // Note: Outside of CSP embedded enforcement,
+        // |ParseSandboxPolicy(...).error_message| isn't displayed to the user.
+        // Blink's CSP parser is already in charge of it.
         {
           auto sandbox = ParseWebSandboxPolicy(directive.second,
                                                mojom::WebSandboxFlags::kNone);
           out->sandbox = sandbox.flags;
-          out->parsing_errors.emplace_back(std::move(sandbox.error_message));
+          if (!sandbox.error_message.empty())
+            out->parsing_errors.emplace_back(std::move(sandbox.error_message));
         }
         break;
       case CSPDirectiveName::UpgradeInsecureRequests:
diff --git a/storage/browser/file_system/copy_or_move_file_validator_unittest.cc b/storage/browser/file_system/copy_or_move_file_validator_unittest.cc
index f8918394..d0dbaf0 100644
--- a/storage/browser/file_system/copy_or_move_file_validator_unittest.cc
+++ b/storage/browser/file_system/copy_or_move_file_validator_unittest.cc
@@ -269,8 +269,7 @@
   CopyOrMoveFileValidatorTestHelper helper("http://foo", kNoValidatorType,
                                            kWithValidatorType);
   helper.SetUp();
-  std::unique_ptr<CopyOrMoveFileValidatorFactory> factory(
-      new TestCopyOrMoveFileValidatorFactory(VALID));
+  auto factory = std::make_unique<TestCopyOrMoveFileValidatorFactory>(VALID);
   helper.SetMediaCopyOrMoveFileValidatorFactory(std::move(factory));
 
   helper.CopyTest(base::File::FILE_OK);
@@ -281,8 +280,8 @@
   CopyOrMoveFileValidatorTestHelper helper("http://foo", kNoValidatorType,
                                            kWithValidatorType);
   helper.SetUp();
-  std::unique_ptr<CopyOrMoveFileValidatorFactory> factory(
-      new TestCopyOrMoveFileValidatorFactory(PRE_WRITE_INVALID));
+  auto factory =
+      std::make_unique<TestCopyOrMoveFileValidatorFactory>(PRE_WRITE_INVALID);
   helper.SetMediaCopyOrMoveFileValidatorFactory(std::move(factory));
 
   helper.CopyTest(base::File::FILE_ERROR_SECURITY);
@@ -294,12 +293,12 @@
   CopyOrMoveFileValidatorTestHelper helper("http://foo", kNoValidatorType,
                                            kWithValidatorType);
   helper.SetUp();
-  std::unique_ptr<CopyOrMoveFileValidatorFactory> reject_factory(
-      new TestCopyOrMoveFileValidatorFactory(PRE_WRITE_INVALID));
+  auto reject_factory =
+      std::make_unique<TestCopyOrMoveFileValidatorFactory>(PRE_WRITE_INVALID);
   helper.SetMediaCopyOrMoveFileValidatorFactory(std::move(reject_factory));
 
-  std::unique_ptr<CopyOrMoveFileValidatorFactory> accept_factory(
-      new TestCopyOrMoveFileValidatorFactory(VALID));
+  auto accept_factory =
+      std::make_unique<TestCopyOrMoveFileValidatorFactory>(VALID);
   helper.SetMediaCopyOrMoveFileValidatorFactory(std::move(accept_factory));
 
   helper.CopyTest(base::File::FILE_ERROR_SECURITY);
@@ -310,8 +309,8 @@
   CopyOrMoveFileValidatorTestHelper helper("http://foo", kNoValidatorType,
                                            kWithValidatorType);
   helper.SetUp();
-  std::unique_ptr<CopyOrMoveFileValidatorFactory> factory(
-      new TestCopyOrMoveFileValidatorFactory(POST_WRITE_INVALID));
+  auto factory =
+      std::make_unique<TestCopyOrMoveFileValidatorFactory>(POST_WRITE_INVALID);
   helper.SetMediaCopyOrMoveFileValidatorFactory(std::move(factory));
 
   helper.CopyTest(base::File::FILE_ERROR_SECURITY);
diff --git a/storage/browser/file_system/copy_or_move_operation_delegate.cc b/storage/browser/file_system/copy_or_move_operation_delegate.cc
index 91e146d..86cbd03 100644
--- a/storage/browser/file_system/copy_or_move_operation_delegate.cc
+++ b/storage/browser/file_system/copy_or_move_operation_delegate.cc
@@ -499,12 +499,13 @@
 
     NotifyOnStartUpdate(dest_url_);
     DCHECK(!copy_helper_);
-    copy_helper_.reset(new CopyOrMoveOperationDelegate::StreamCopyHelper(
-        std::move(reader_), std::move(writer_),
-        dest_url_.mount_option().flush_policy(), kReadBufferSize,
-        file_progress_callback_,
-        base::TimeDelta::FromMilliseconds(
-            kMinProgressCallbackInvocationSpanInMilliseconds)));
+    copy_helper_ =
+        std::make_unique<CopyOrMoveOperationDelegate::StreamCopyHelper>(
+            std::move(reader_), std::move(writer_),
+            dest_url_.mount_option().flush_policy(), kReadBufferSize,
+            file_progress_callback_,
+            base::TimeDelta::FromMilliseconds(
+                kMinProgressCallbackInvocationSpanInMilliseconds));
     copy_helper_->Run(base::BindOnce(&StreamCopyOrMoveImpl::RunAfterStreamCopy,
                                      weak_factory_.GetWeakPtr(),
                                      std::move(callback), last_modified));
diff --git a/storage/browser/file_system/copy_or_move_operation_delegate_unittest.cc b/storage/browser/file_system/copy_or_move_operation_delegate_unittest.cc
index 6bd2fcf..ed56a1ab 100644
--- a/storage/browser/file_system/copy_or_move_operation_delegate_unittest.cc
+++ b/storage/browser/file_system/copy_or_move_operation_delegate_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/location.h"
 #include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/test/task_environment.h"
@@ -191,11 +192,11 @@
              bool init_copy_or_move_validator) {
     ASSERT_TRUE(base_.CreateUniqueTempDir());
     base::FilePath base_dir = base_.GetPath();
-    quota_manager_ =
-        new MockQuotaManager(false /* is_incognito */, base_dir,
-                             base::ThreadTaskRunnerHandle::Get().get(),
-                             nullptr /* special storage policy */);
-    quota_manager_proxy_ = new MockQuotaManagerProxy(
+    quota_manager_ = base::MakeRefCounted<MockQuotaManager>(
+        false /* is_incognito */, base_dir,
+        base::ThreadTaskRunnerHandle::Get().get(),
+        nullptr /* special storage policy */);
+    quota_manager_proxy_ = base::MakeRefCounted<MockQuotaManagerProxy>(
         quota_manager_.get(), base::ThreadTaskRunnerHandle::Get().get());
     file_system_context_ =
         CreateFileSystemContextForTesting(quota_manager_proxy_.get(), base_dir);
@@ -210,8 +211,7 @@
     if (dest_type_ == kFileSystemTypeTest) {
       TestFileSystemBackend* test_backend =
           static_cast<TestFileSystemBackend*>(backend);
-      std::unique_ptr<CopyOrMoveFileValidatorFactory> factory(
-          new TestValidatorFactory);
+      auto factory = std::make_unique<TestValidatorFactory>();
       test_backend->set_require_copy_or_move_validator(
           require_copy_or_move_validator);
       if (init_copy_or_move_validator)
diff --git a/storage/browser/file_system/file_system_context.cc b/storage/browser/file_system/file_system_context.cc
index 10db27f..dcc92eb 100644
--- a/storage/browser/file_system/file_system_context.cc
+++ b/storage/browser/file_system/file_system_context.cc
@@ -150,28 +150,29 @@
       io_task_runner_(io_task_runner),
       default_file_task_runner_(file_task_runner),
       quota_manager_proxy_(quota_manager_proxy),
-      sandbox_delegate_(
-          new SandboxFileSystemBackendDelegate(quota_manager_proxy,
-                                               file_task_runner,
-                                               partition_path,
-                                               special_storage_policy,
-                                               options,
-                                               env_override_.get())),
-      sandbox_backend_(new SandboxFileSystemBackend(sandbox_delegate_.get())),
-      plugin_private_backend_(
-          new PluginPrivateFileSystemBackend(file_task_runner,
-                                             partition_path,
-                                             special_storage_policy,
-                                             options,
-                                             env_override_.get())),
+      sandbox_delegate_(std::make_unique<SandboxFileSystemBackendDelegate>(
+          quota_manager_proxy,
+          file_task_runner,
+          partition_path,
+          special_storage_policy,
+          options,
+          env_override_.get())),
+      sandbox_backend_(
+          std::make_unique<SandboxFileSystemBackend>(sandbox_delegate_.get())),
+      plugin_private_backend_(std::make_unique<PluginPrivateFileSystemBackend>(
+          file_task_runner,
+          partition_path,
+          special_storage_policy,
+          options,
+          env_override_.get())),
       additional_backends_(std::move(additional_backends)),
       auto_mount_handlers_(auto_mount_handlers),
       external_mount_points_(external_mount_points),
       partition_path_(partition_path),
       is_incognito_(options.is_incognito()),
-      operation_runner_(
-          new FileSystemOperationRunner(base::PassKey<FileSystemContext>(),
-                                        this)) {
+      operation_runner_(std::make_unique<FileSystemOperationRunner>(
+          base::PassKey<FileSystemContext>(),
+          this)) {
   RegisterBackend(sandbox_backend_.get());
   RegisterBackend(plugin_private_backend_.get());
 
@@ -183,9 +184,9 @@
   // IsolatedFileSystemBackend does not need to handle them. For example, on
   // Chrome OS the additional backend chromeos::FileSystemBackend handles these
   // types.
-  isolated_backend_.reset(new IsolatedFileSystemBackend(
+  isolated_backend_ = std::make_unique<IsolatedFileSystemBackend>(
       !base::Contains(backend_map_, kFileSystemTypeNativeLocal),
-      !base::Contains(backend_map_, kFileSystemTypeNativeForPlatformApp)));
+      !base::Contains(backend_map_, kFileSystemTypeNativeForPlatformApp));
   RegisterBackend(isolated_backend_.get());
 
   if (quota_manager_proxy) {
diff --git a/storage/browser/file_system/file_system_context_unittest.cc b/storage/browser/file_system/file_system_context_unittest.cc
index 2cc657c..0f2199e 100644
--- a/storage/browser/file_system/file_system_context_unittest.cc
+++ b/storage/browser/file_system/file_system_context_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/task_environment.h"
@@ -51,9 +52,9 @@
   void SetUp() override {
     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
 
-    storage_policy_ = new MockSpecialStoragePolicy();
+    storage_policy_ = base::MakeRefCounted<MockSpecialStoragePolicy>();
 
-    mock_quota_manager_ = new MockQuotaManager(
+    mock_quota_manager_ = base::MakeRefCounted<MockQuotaManager>(
         false /* is_incognito */, data_dir_.GetPath(),
         base::ThreadTaskRunnerHandle::Get().get(), storage_policy_.get());
   }
diff --git a/storage/browser/file_system/file_system_operation_impl.cc b/storage/browser/file_system/file_system_operation_impl.cc
index 1c00df8..f7e0cfcf 100644
--- a/storage/browser/file_system/file_system_operation_impl.cc
+++ b/storage/browser/file_system/file_system_operation_impl.cc
@@ -104,12 +104,12 @@
   DCHECK(SetPendingOperationType(kOperationCopy));
   DCHECK(!recursive_operation_delegate_);
 
-  recursive_operation_delegate_.reset(new CopyOrMoveOperationDelegate(
+  recursive_operation_delegate_ = std::make_unique<CopyOrMoveOperationDelegate>(
       file_system_context(), src_url, dest_url,
       CopyOrMoveOperationDelegate::OPERATION_COPY, option, error_behavior,
       progress_callback,
       base::BindOnce(&FileSystemOperationImpl::DidFinishOperation,
-                     weak_factory_.GetWeakPtr(), std::move(callback))));
+                     weak_factory_.GetWeakPtr(), std::move(callback)));
   recursive_operation_delegate_->RunRecursively();
 }
 
@@ -119,12 +119,12 @@
                                    StatusCallback callback) {
   DCHECK(SetPendingOperationType(kOperationMove));
   DCHECK(!recursive_operation_delegate_);
-  recursive_operation_delegate_.reset(new CopyOrMoveOperationDelegate(
+  recursive_operation_delegate_ = std::make_unique<CopyOrMoveOperationDelegate>(
       file_system_context(), src_url, dest_url,
       CopyOrMoveOperationDelegate::OPERATION_MOVE, option, ERROR_BEHAVIOR_ABORT,
       FileSystemOperation::CopyProgressCallback(),
       base::BindOnce(&FileSystemOperationImpl::DidFinishOperation,
-                     weak_factory_.GetWeakPtr(), std::move(callback))));
+                     weak_factory_.GetWeakPtr(), std::move(callback)));
   recursive_operation_delegate_->RunRecursively();
 }
 
@@ -178,10 +178,10 @@
     return;
   }
 
-  recursive_operation_delegate_.reset(new RemoveOperationDelegate(
+  recursive_operation_delegate_ = std::make_unique<RemoveOperationDelegate>(
       file_system_context(), url,
       base::BindOnce(&FileSystemOperationImpl::DidFinishOperation,
-                     weak_factory_.GetWeakPtr(), std::move(callback))));
+                     weak_factory_.GetWeakPtr(), std::move(callback)));
   recursive_operation_delegate_->Run();
 }
 
@@ -567,10 +567,10 @@
   if (rv == base::File::FILE_ERROR_INVALID_OPERATION) {
     // Recursive removal is not supported on this platform.
     DCHECK(!recursive_operation_delegate_);
-    recursive_operation_delegate_.reset(new RemoveOperationDelegate(
+    recursive_operation_delegate_ = std::make_unique<RemoveOperationDelegate>(
         file_system_context(), url,
         base::BindOnce(&FileSystemOperationImpl::DidFinishOperation, weak_ptr_,
-                       std::move(callback))));
+                       std::move(callback)));
     recursive_operation_delegate_->RunRecursively();
     return;
   }
diff --git a/storage/browser/file_system/file_system_operation_impl_unittest.cc b/storage/browser/file_system/file_system_operation_impl_unittest.cc
index d1eb56c..7da145b 100644
--- a/storage/browser/file_system/file_system_operation_impl_unittest.cc
+++ b/storage/browser/file_system/file_system_operation_impl_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
@@ -56,11 +57,11 @@
     update_observers_ = MockFileUpdateObserver::CreateList(&update_observer_);
 
     base::FilePath base_dir = base_.GetPath().AppendASCII("filesystem");
-    quota_manager_ =
-        new MockQuotaManager(false /* is_incognito */, base_dir,
-                             base::ThreadTaskRunnerHandle::Get().get(),
-                             nullptr /* special storage policy */);
-    quota_manager_proxy_ = new MockQuotaManagerProxy(
+    quota_manager_ = base::MakeRefCounted<MockQuotaManager>(
+        /* is_incognito= */ false, base_dir,
+        base::ThreadTaskRunnerHandle::Get().get(),
+        /* special storage policy= */ nullptr);
+    quota_manager_proxy_ = base::MakeRefCounted<MockQuotaManagerProxy>(
         quota_manager(), base::ThreadTaskRunnerHandle::Get().get());
     sandbox_file_system_.SetUp(base_dir, quota_manager_proxy_.get());
     sandbox_file_system_.AddFileChangeObserver(&change_observer_);
diff --git a/storage/browser/file_system/file_system_operation_impl_write_unittest.cc b/storage/browser/file_system/file_system_operation_impl_write_unittest.cc
index f8a3c404..987ff4f 100644
--- a/storage/browser/file_system/file_system_operation_impl_write_unittest.cc
+++ b/storage/browser/file_system/file_system_operation_impl_write_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/bind.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
@@ -59,15 +60,15 @@
   void SetUp() override {
     ASSERT_TRUE(dir_.CreateUniqueTempDir());
 
-    quota_manager_ =
-        new MockQuotaManager(false /* is_incognito */, dir_.GetPath(),
-                             base::ThreadTaskRunnerHandle::Get().get(),
-                             nullptr /* special storage policy */);
+    quota_manager_ = base::MakeRefCounted<MockQuotaManager>(
+        /* is_incognito= */ false, dir_.GetPath(),
+        base::ThreadTaskRunnerHandle::Get().get(),
+        /* special storage policy= */ nullptr);
     virtual_path_ = base::FilePath(FILE_PATH_LITERAL("temporary file"));
 
     file_system_context_ = CreateFileSystemContextForTesting(
         quota_manager_->proxy(), dir_.GetPath());
-    blob_storage_context_.reset(new BlobStorageContext);
+    blob_storage_context_ = std::make_unique<BlobStorageContext>();
 
     file_system_context_->operation_runner()->CreateFile(
         URLForPath(virtual_path_), true /* exclusive */,
diff --git a/storage/browser/file_system/file_system_operation_runner.cc b/storage/browser/file_system/file_system_operation_runner.cc
index 228a4e8..7c186bd 100644
--- a/storage/browser/file_system/file_system_operation_runner.cc
+++ b/storage/browser/file_system/file_system_operation_runner.cc
@@ -267,8 +267,8 @@
     return id;
   }
 
-  std::unique_ptr<FileWriterDelegate> writer_delegate(new FileWriterDelegate(
-      std::move(writer), url.mount_option().flush_policy()));
+  auto writer_delegate = std::make_unique<FileWriterDelegate>(
+      std::move(writer), url.mount_option().flush_policy());
 
   std::unique_ptr<BlobReader> blob_reader;
   if (blob)
@@ -306,8 +306,8 @@
     return id;
   }
 
-  std::unique_ptr<FileWriterDelegate> writer_delegate(new FileWriterDelegate(
-      std::move(writer), url.mount_option().flush_policy()));
+  auto writer_delegate = std::make_unique<FileWriterDelegate>(
+      std::move(writer), url.mount_option().flush_policy());
 
   PrepareForWrite(id, url);
   operation_raw->Write(url, std::move(writer_delegate), std::move(data_pipe),
diff --git a/storage/browser/file_system/file_system_quota_client.cc b/storage/browser/file_system/file_system_quota_client.cc
index e9f3f9bf..ee87ffb 100644
--- a/storage/browser/file_system/file_system_quota_client.cc
+++ b/storage/browser/file_system/file_system_quota_client.cc
@@ -29,35 +29,29 @@
 
 namespace {
 
-void GetOriginsForTypeOnFileTaskRunner(FileSystemContext* context,
-                                       StorageType storage_type,
-                                       std::vector<url::Origin>* origins_ptr) {
+std::vector<url::Origin> GetOriginsForTypeOnFileTaskRunner(
+    FileSystemContext* context,
+    StorageType storage_type) {
   FileSystemType type = QuotaStorageTypeToFileSystemType(storage_type);
   DCHECK(type != kFileSystemTypeUnknown);
 
   FileSystemQuotaUtil* quota_util = context->GetQuotaUtil(type);
   if (!quota_util)
-    return;
-  *origins_ptr = quota_util->GetOriginsForTypeOnFileTaskRunner(type);
+    return {};
+  return quota_util->GetOriginsForTypeOnFileTaskRunner(type);
 }
 
-void GetOriginsForHostOnFileTaskRunner(FileSystemContext* context,
-                                       StorageType storage_type,
-                                       const std::string& host,
-                                       std::vector<url::Origin>* origins_ptr) {
+std::vector<url::Origin> GetOriginsForHostOnFileTaskRunner(
+    FileSystemContext* context,
+    StorageType storage_type,
+    const std::string& host) {
   FileSystemType type = QuotaStorageTypeToFileSystemType(storage_type);
   DCHECK(type != kFileSystemTypeUnknown);
 
   FileSystemQuotaUtil* quota_util = context->GetQuotaUtil(type);
   if (!quota_util)
-    return;
-  *origins_ptr = quota_util->GetOriginsForHostOnFileTaskRunner(type, host);
-}
-
-void DidGetFileSystemQuotaClientOrigins(
-    QuotaClient::GetOriginsForTypeCallback callback,
-    std::vector<url::Origin>* origins_ptr) {
-  std::move(callback).Run(*origins_ptr);
+    return {};
+  return quota_util->GetOriginsForHostOnFileTaskRunner(type, host);
 }
 
 blink::mojom::QuotaStatusCode DeleteOriginOnFileTaskRunner(
@@ -120,14 +114,11 @@
     GetOriginsForTypeCallback callback) {
   DCHECK(!callback.is_null());
 
-  auto* origins_ptr = new std::vector<url::Origin>();
-  file_task_runner()->PostTaskAndReply(
+  file_task_runner()->PostTaskAndReplyWithResult(
       FROM_HERE,
       base::BindOnce(&GetOriginsForTypeOnFileTaskRunner,
-                     base::RetainedRef(file_system_context_), storage_type,
-                     base::Unretained(origins_ptr)),
-      base::BindOnce(&DidGetFileSystemQuotaClientOrigins, std::move(callback),
-                     base::Owned(origins_ptr)));
+                     base::RetainedRef(file_system_context_), storage_type),
+      std::move(callback));
 }
 
 void FileSystemQuotaClient::GetOriginsForHost(
@@ -136,14 +127,12 @@
     GetOriginsForHostCallback callback) {
   DCHECK(!callback.is_null());
 
-  auto* origins_ptr = new std::vector<url::Origin>();
-  file_task_runner()->PostTaskAndReply(
+  file_task_runner()->PostTaskAndReplyWithResult(
       FROM_HERE,
       base::BindOnce(&GetOriginsForHostOnFileTaskRunner,
                      base::RetainedRef(file_system_context_), storage_type,
-                     host, base::Unretained(origins_ptr)),
-      base::BindOnce(&DidGetFileSystemQuotaClientOrigins, std::move(callback),
-                     base::Owned(origins_ptr)));
+                     host),
+      std::move(callback));
 }
 
 void FileSystemQuotaClient::DeleteOriginData(
diff --git a/storage/browser/file_system/isolated_file_system_backend.cc b/storage/browser/file_system/isolated_file_system_backend.cc
index ef345ee..643e769c 100644
--- a/storage/browser/file_system/isolated_file_system_backend.cc
+++ b/storage/browser/file_system/isolated_file_system_backend.cc
@@ -38,9 +38,12 @@
     bool use_for_type_platform_app)
     : use_for_type_native_local_(use_for_type_native_local),
       use_for_type_platform_app_(use_for_type_platform_app),
-      isolated_file_util_(new AsyncFileUtilAdapter(new LocalFileUtil())),
-      dragged_file_util_(new AsyncFileUtilAdapter(new DraggedFileUtil())),
-      transient_file_util_(new AsyncFileUtilAdapter(new TransientFileUtil())) {}
+      isolated_file_util_(
+          std::make_unique<AsyncFileUtilAdapter>(new LocalFileUtil())),
+      dragged_file_util_(
+          std::make_unique<AsyncFileUtilAdapter>(new DraggedFileUtil())),
+      transient_file_util_(
+          std::make_unique<AsyncFileUtilAdapter>(new TransientFileUtil())) {}
 
 IsolatedFileSystemBackend::~IsolatedFileSystemBackend() = default;
 
diff --git a/storage/browser/file_system/local_file_stream_reader.cc b/storage/browser/file_system/local_file_stream_reader.cc
index efd95885..89db58c 100644
--- a/storage/browser/file_system/local_file_stream_reader.cc
+++ b/storage/browser/file_system/local_file_stream_reader.cc
@@ -6,6 +6,7 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
@@ -107,7 +108,7 @@
     return;
   }
 
-  stream_impl_.reset(new net::FileStream(task_runner_));
+  stream_impl_ = std::make_unique<net::FileStream>(task_runner_);
   callback_ = std::move(callback);
   const int result = stream_impl_->Open(
       file_path_, kOpenFlagsForRead,
diff --git a/storage/browser/file_system/local_file_stream_writer.cc b/storage/browser/file_system/local_file_stream_writer.cc
index 5ef1c70..2439de24 100644
--- a/storage/browser/file_system/local_file_stream_writer.cc
+++ b/storage/browser/file_system/local_file_stream_writer.cc
@@ -6,6 +6,8 @@
 
 #include <stdint.h>
 
+#include <memory>
+
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "net/base/file_stream.h"
@@ -103,7 +105,7 @@
   DCHECK(has_pending_operation_);
   DCHECK(!stream_impl_.get());
 
-  stream_impl_.reset(new net::FileStream(task_runner_));
+  stream_impl_ = std::make_unique<net::FileStream>(task_runner_);
 
   int open_flags = 0;
   switch (open_or_create_) {
diff --git a/storage/browser/file_system/local_file_util.cc b/storage/browser/file_system/local_file_util.cc
index 807079a..827e3e01 100644
--- a/storage/browser/file_system/local_file_util.cc
+++ b/storage/browser/file_system/local_file_util.cc
@@ -136,7 +136,7 @@
                                     bool recursive) {
   base::FilePath file_path;
   if (GetLocalFilePath(context, root_url, &file_path) != base::File::FILE_OK) {
-    return base::WrapUnique(new EmptyFileEnumerator);
+    return std::make_unique<EmptyFileEnumerator>();
   }
   return std::make_unique<LocalFileEnumerator>(
       this, file_path, root_url.path(), recursive,
diff --git a/storage/browser/file_system/obfuscated_file_util.cc b/storage/browser/file_system/obfuscated_file_util.cc
index 78b74678..87728ff 100644
--- a/storage/browser/file_system/obfuscated_file_util.cc
+++ b/storage/browser/file_system/obfuscated_file_util.cc
@@ -819,7 +819,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   SandboxDirectoryDatabase* db = GetDirectoryDatabase(root_url, false);
   if (!db) {
-    return base::WrapUnique(new EmptyFileEnumerator);
+    return std::make_unique<EmptyFileEnumerator>();
   }
   return std::make_unique<ObfuscatedFileEnumerator>(
       db, context, this, root_url, recursive);
diff --git a/storage/browser/file_system/obfuscated_file_util_unittest.cc b/storage/browser/file_system/obfuscated_file_util_unittest.cc
index 112a574..30039344 100644
--- a/storage/browser/file_system/obfuscated_file_util_unittest.cc
+++ b/storage/browser/file_system/obfuscated_file_util_unittest.cc
@@ -464,17 +464,17 @@
   std::unique_ptr<UsageVerifyHelper> AllowUsageIncrease(
       int64_t requested_growth) {
     int64_t usage = sandbox_file_system_.GetCachedOriginUsage();
-    return std::unique_ptr<UsageVerifyHelper>(new UsageVerifyHelper(
-        LimitedContext(requested_growth), &sandbox_file_system_,
-        usage + requested_growth, this));
+    return std::make_unique<UsageVerifyHelper>(LimitedContext(requested_growth),
+                                               &sandbox_file_system_,
+                                               usage + requested_growth, this);
   }
 
   std::unique_ptr<UsageVerifyHelper> DisallowUsageIncrease(
       int64_t requested_growth) {
     int64_t usage = sandbox_file_system_.GetCachedOriginUsage();
-    return std::unique_ptr<UsageVerifyHelper>(
-        new UsageVerifyHelper(LimitedContext(requested_growth - 1),
-                              &sandbox_file_system_, usage, this));
+    return std::make_unique<UsageVerifyHelper>(
+        LimitedContext(requested_growth - 1), &sandbox_file_system_, usage,
+        this);
   }
 
   void FillTestDirectory(const FileSystemURL& root_url,
diff --git a/storage/browser/file_system/quota/quota_backend_impl_unittest.cc b/storage/browser/file_system/quota/quota_backend_impl_unittest.cc
index e7e8c49..45010a5e 100644
--- a/storage/browser/file_system/quota/quota_backend_impl_unittest.cc
+++ b/storage/browser/file_system/quota/quota_backend_impl_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/bind.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -93,7 +94,7 @@
  public:
   QuotaBackendImplTest()
       : file_system_usage_cache_(is_incognito()),
-        quota_manager_proxy_(new MockQuotaManagerProxy) {}
+        quota_manager_proxy_(base::MakeRefCounted<MockQuotaManagerProxy>()) {}
 
   void SetUp() override {
     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
diff --git a/storage/browser/file_system/quota/quota_reservation_manager_unittest.cc b/storage/browser/file_system/quota/quota_reservation_manager_unittest.cc
index 3e5f74d..f588e18 100644
--- a/storage/browser/file_system/quota/quota_reservation_manager_unittest.cc
+++ b/storage/browser/file_system/quota/quota_reservation_manager_unittest.cc
@@ -188,9 +188,9 @@
     file_path_ = work_dir_.GetPath().Append(FILE_PATH_LITERAL("hoge"));
     SetFileSize(file_path_, kInitialFileSize);
 
-    std::unique_ptr<QuotaReservationManager::QuotaBackend> backend(
-        new FakeBackend);
-    reservation_manager_.reset(new QuotaReservationManager(std::move(backend)));
+    auto backend = std::make_unique<FakeBackend>();
+    reservation_manager_ =
+        std::make_unique<QuotaReservationManager>(std::move(backend));
   }
 
   void TearDown() override { reservation_manager_.reset(); }
diff --git a/storage/browser/file_system/sandbox_directory_database_unittest.cc b/storage/browser/file_system/sandbox_directory_database_unittest.cc
index 2f84433..e24f825 100644
--- a/storage/browser/file_system/sandbox_directory_database_unittest.cc
+++ b/storage/browser/file_system/sandbox_directory_database_unittest.cc
@@ -46,7 +46,7 @@
     // Call CloseDatabase() to avoid having multiple database instances for
     // single directory at once.
     CloseDatabase();
-    db_.reset(new SandboxDirectoryDatabase(path(), nullptr));
+    db_ = std::make_unique<SandboxDirectoryDatabase>(path(), nullptr);
   }
 
   void CloseDatabase() { db_.reset(); }
@@ -98,7 +98,7 @@
     db_.reset();
     ASSERT_TRUE(base::DeletePathRecursively(path()));
     ASSERT_TRUE(base::CreateDirectory(path()));
-    db_.reset(new SandboxDirectoryDatabase(path(), nullptr));
+    db_ = std::make_unique<SandboxDirectoryDatabase>(path(), nullptr);
   }
 
   bool RepairDatabase() {
diff --git a/storage/browser/file_system/sandbox_file_system_backend_delegate.cc b/storage/browser/file_system/sandbox_file_system_backend_delegate.cc
index 65083f3..9ef9119 100644
--- a/storage/browser/file_system/sandbox_file_system_backend_delegate.cc
+++ b/storage/browser/file_system/sandbox_file_system_backend_delegate.cc
@@ -113,17 +113,17 @@
   std::unique_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator> enum_;
 };
 
-void OpenSandboxFileSystemOnFileTaskRunner(ObfuscatedFileUtil* file_util,
-                                           const GURL& origin_url,
-                                           FileSystemType type,
-                                           OpenFileSystemMode mode,
-                                           base::File::Error* error_ptr) {
-  DCHECK(error_ptr);
+base::File::Error OpenSandboxFileSystemOnFileTaskRunner(
+    ObfuscatedFileUtil* file_util,
+    const GURL& origin_url,
+    FileSystemType type,
+    OpenFileSystemMode mode) {
   const bool create = (mode == OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT);
+  base::File::Error error;
   file_util->GetDirectoryForOriginAndType(
       url::Origin::Create(origin_url),
-      SandboxFileSystemBackendDelegate::GetTypeString(type), create, error_ptr);
-  if (*error_ptr != base::File::FILE_OK) {
+      SandboxFileSystemBackendDelegate::GetTypeString(type), create, &error);
+  if (error != base::File::FILE_OK) {
     UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel, kCreateDirectoryError,
                               kFileSystemErrorMax);
   } else {
@@ -132,18 +132,20 @@
   // The reference of file_util will be derefed on the FILE thread
   // when the storage of this callback gets deleted regardless of whether
   // this method is called or not.
+
+  return error;
 }
 
 void DidOpenFileSystem(
     base::WeakPtr<SandboxFileSystemBackendDelegate> delegate,
     base::OnceClosure quota_callback,
     base::OnceCallback<void(base::File::Error error)> callback,
-    base::File::Error* error) {
+    base::File::Error error) {
   if (delegate)
-    delegate->CollectOpenFileSystemMetrics(*error);
-  if (*error == base::File::FILE_OK)
+    delegate->CollectOpenFileSystemMetrics(error);
+  if (error == base::File::FILE_OK)
     std::move(quota_callback).Run();
-  std::move(callback).Run(*error);
+  std::move(callback).Run(error);
 }
 
 template <typename T>
@@ -195,11 +197,12 @@
                                  file_system_options.is_incognito()))),
       file_system_usage_cache_(std::make_unique<FileSystemUsageCache>(
           file_system_options.is_incognito())),
-      quota_observer_(new SandboxQuotaObserver(quota_manager_proxy,
-                                               file_task_runner,
-                                               obfuscated_file_util(),
-                                               usage_cache())),
-      quota_reservation_manager_(new QuotaReservationManager(
+      quota_observer_(
+          std::make_unique<SandboxQuotaObserver>(quota_manager_proxy,
+                                                 file_task_runner,
+                                                 obfuscated_file_util(),
+                                                 usage_cache())),
+      quota_reservation_manager_(std::make_unique<QuotaReservationManager>(
           std::make_unique<QuotaBackendImpl>(file_task_runner_.get(),
                                              obfuscated_file_util(),
                                              usage_cache(),
@@ -273,16 +276,13 @@
                            FileSystemTypeToQuotaStorageType(type))
           : base::DoNothing();
 
-  base::File::Error* error_ptr = new base::File::Error;
-  file_task_runner_->PostTaskAndReply(
+  file_task_runner_->PostTaskAndReplyWithResult(
       FROM_HERE,
       base::BindOnce(&OpenSandboxFileSystemOnFileTaskRunner,
-                     obfuscated_file_util(), origin.GetURL(), type, mode,
-                     base::Unretained(error_ptr)),
+                     obfuscated_file_util(), origin.GetURL(), type, mode),
       base::BindOnce(&DidOpenFileSystem, weak_factory_.GetWeakPtr(),
                      std::move(quota_callback),
-                     base::BindOnce(std::move(callback), root_url, name),
-                     base::Owned(error_ptr)));
+                     base::BindOnce(std::move(callback), root_url, name)));
 
   DETACH_FROM_THREAD(io_thread_checker_);
   is_filesystem_opened_ = true;
@@ -302,8 +302,8 @@
   const ChangeObserverList* change_observers = GetChangeObservers(url.type());
   DCHECK(update_observers);
 
-  std::unique_ptr<FileSystemOperationContext> operation_context(
-      new FileSystemOperationContext(context));
+  auto operation_context =
+      std::make_unique<FileSystemOperationContext>(context);
   operation_context->set_update_observers(*update_observers);
   operation_context->set_change_observers(
       change_observers ? *change_observers : ChangeObserverList());
diff --git a/storage/browser/file_system/sandbox_file_system_backend_unittest.cc b/storage/browser/file_system/sandbox_file_system_backend_unittest.cc
index 7e029cb8..52d6d9f 100644
--- a/storage/browser/file_system/sandbox_file_system_backend_unittest.cc
+++ b/storage/browser/file_system/sandbox_file_system_backend_unittest.cc
@@ -91,16 +91,16 @@
 
   void SetUpNewDelegate(const FileSystemOptions& options) {
     incognito_env_override_ = leveldb_chrome::NewMemEnv("FileSystem");
-    delegate_.reset(new SandboxFileSystemBackendDelegate(
+    delegate_ = std::make_unique<SandboxFileSystemBackendDelegate>(
         nullptr /* quota_manager_proxy */,
         base::ThreadTaskRunnerHandle::Get().get(), data_dir_.GetPath(),
         nullptr /* special_storage_policy */, options,
-        options.is_in_memory() ? incognito_env_override_.get() : nullptr));
+        options.is_in_memory() ? incognito_env_override_.get() : nullptr);
   }
 
   void SetUpNewBackend(const FileSystemOptions& options) {
     SetUpNewDelegate(options);
-    backend_.reset(new SandboxFileSystemBackend(delegate_.get()));
+    backend_ = std::make_unique<SandboxFileSystemBackend>(delegate_.get());
   }
 
   SandboxFileSystemBackendDelegate::OriginEnumerator* CreateOriginEnumerator()
diff --git a/storage/browser/file_system/sandbox_origin_database_unittest.cc b/storage/browser/file_system/sandbox_origin_database_unittest.cc
index a52ab31..f9b1aa4e 100644
--- a/storage/browser/file_system/sandbox_origin_database_unittest.cc
+++ b/storage/browser/file_system/sandbox_origin_database_unittest.cc
@@ -208,8 +208,7 @@
       "hoge.example.com", "fuga.example.com",
   };
 
-  std::unique_ptr<SandboxOriginDatabase> database(
-      new SandboxOriginDatabase(kFSDir, nullptr));
+  auto database = std::make_unique<SandboxOriginDatabase>(kFSDir, nullptr);
   for (size_t i = 0; i < base::size(kOrigins); ++i) {
     base::FilePath path;
     EXPECT_FALSE(database->HasOriginPath(kOrigins[i]));
@@ -238,7 +237,7 @@
   CorruptDatabase(kDBDir, leveldb::kLogFile, -1, 1);
 
   base::FilePath path;
-  database.reset(new SandboxOriginDatabase(kFSDir, nullptr));
+  database = std::make_unique<SandboxOriginDatabase>(kFSDir, nullptr);
   std::vector<SandboxOriginDatabase::OriginRecord> origins_in_db;
   EXPECT_TRUE(database->ListAllOrigins(&origins_in_db));
 
@@ -274,8 +273,7 @@
     const std::string kOrigin = "foo.example.com";
     base::FilePath path;
 
-    std::unique_ptr<SandboxOriginDatabase> database(
-        new SandboxOriginDatabase(kFSDir, nullptr));
+    auto database = std::make_unique<SandboxOriginDatabase>(kFSDir, nullptr);
     EXPECT_FALSE(database->HasOriginPath(kOrigin));
     EXPECT_TRUE(database->GetPathForOrigin(kOrigin, &path));
     EXPECT_FALSE(path.empty());
@@ -285,7 +283,7 @@
 
     DeleteDatabaseFile(kDBDir, file_type);
 
-    database.reset(new SandboxOriginDatabase(kFSDir, nullptr));
+    database = std::make_unique<SandboxOriginDatabase>(kFSDir, nullptr);
     std::vector<SandboxOriginDatabase::OriginRecord> origins_in_db;
     EXPECT_TRUE(database->ListAllOrigins(&origins_in_db));
 
diff --git a/storage/browser/file_system/sandbox_prioritized_origin_database.cc b/storage/browser/file_system/sandbox_prioritized_origin_database.cc
index 5c46bff..d364b54 100644
--- a/storage/browser/file_system/sandbox_prioritized_origin_database.cc
+++ b/storage/browser/file_system/sandbox_prioritized_origin_database.cc
@@ -4,6 +4,8 @@
 
 #include "storage/browser/file_system/sandbox_prioritized_origin_database.h"
 
+#include <memory>
+
 #include "base/check.h"
 #include "base/files/file.h"
 #include "base/files/file_util.h"
@@ -65,8 +67,10 @@
   if (!primary_origin_database_ && !is_in_memory) {
     if (!MaybeLoadPrimaryOrigin() && ResetPrimaryOrigin(origin)) {
       MaybeMigrateDatabase(origin);
-      primary_origin_database_.reset(new SandboxIsolatedOriginDatabase(
-          origin, file_system_directory_, base::FilePath(kPrimaryDirectory)));
+      primary_origin_database_ =
+          std::make_unique<SandboxIsolatedOriginDatabase>(
+              origin, file_system_directory_,
+              base::FilePath(kPrimaryDirectory));
       return true;
     }
   }
@@ -151,8 +155,8 @@
   std::string saved_origin;
   if (!ReadPrimaryOriginFile(primary_origin_file_, &saved_origin))
     return false;
-  primary_origin_database_.reset(new SandboxIsolatedOriginDatabase(
-      saved_origin, file_system_directory_, base::FilePath(kPrimaryDirectory)));
+  primary_origin_database_ = std::make_unique<SandboxIsolatedOriginDatabase>(
+      saved_origin, file_system_directory_, base::FilePath(kPrimaryDirectory));
   return true;
 }
 
@@ -207,8 +211,8 @@
   if (origin_database_)
     return;
 
-  origin_database_.reset(
-      new SandboxOriginDatabase(file_system_directory_, env_override_));
+  origin_database_ = std::make_unique<SandboxOriginDatabase>(
+      file_system_directory_, env_override_);
   if (!create && !base::DirectoryExists(origin_database_->GetDatabasePath())) {
     origin_database_.reset();
     return;
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index e0624a1..194f99a 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -317,11 +317,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.75"
+            "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.76"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.75",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.76",
         "resultdb": {
           "enable": true
         },
@@ -331,7 +331,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M88",
-              "revision": "version:88.0.4324.75"
+              "revision": "version:88.0.4324.76"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -471,11 +471,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.75"
+            "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.76"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.75",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.76",
         "resultdb": {
           "enable": true
         },
@@ -485,7 +485,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M88",
-              "revision": "version:88.0.4324.75"
+              "revision": "version:88.0.4324.76"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -846,11 +846,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.75"
+            "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.76"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.75",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.76",
         "resultdb": {
           "enable": true
         },
@@ -860,7 +860,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M88",
-              "revision": "version:88.0.4324.75"
+              "revision": "version:88.0.4324.76"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -1000,11 +1000,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.75"
+            "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.76"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.75",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.76",
         "resultdb": {
           "enable": true
         },
@@ -1014,7 +1014,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M88",
-              "revision": "version:88.0.4324.75"
+              "revision": "version:88.0.4324.76"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -1375,11 +1375,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.75"
+            "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.76"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.75",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.76",
         "resultdb": {
           "enable": true
         },
@@ -1389,7 +1389,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M88",
-              "revision": "version:88.0.4324.75"
+              "revision": "version:88.0.4324.76"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -1529,11 +1529,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.75"
+            "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.76"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.75",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.76",
         "resultdb": {
           "enable": true
         },
@@ -1543,7 +1543,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M88",
-              "revision": "version:88.0.4324.75"
+              "revision": "version:88.0.4324.76"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -1904,11 +1904,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.75"
+            "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.76"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.75",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Tests For 88.0.4324.76",
         "resultdb": {
           "enable": true
         },
@@ -1918,7 +1918,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M88",
-              "revision": "version:88.0.4324.75"
+              "revision": "version:88.0.4324.76"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -2058,11 +2058,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.75"
+            "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.76"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.75",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Tests For 88.0.4324.76",
         "resultdb": {
           "enable": true
         },
@@ -2072,7 +2072,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M88",
-              "revision": "version:88.0.4324.75"
+              "revision": "version:88.0.4324.76"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 21cbad5..4abce2d 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -319,13 +319,13 @@
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
       '--impl-version=88',
     ],
-    'identifier': 'Implementation Tests For 88.0.4324.75',
+    'identifier': 'Implementation Tests For 88.0.4324.76',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M88',
-          'revision': 'version:88.0.4324.75',
+          'revision': 'version:88.0.4324.76',
         }
       ],
     },
@@ -388,13 +388,13 @@
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
       '--client-version=88',
     ],
-    'identifier': 'Client Tests For 88.0.4324.75',
+    'identifier': 'Client Tests For 88.0.4324.76',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M88',
-          'revision': 'version:88.0.4324.75',
+          'revision': 'version:88.0.4324.76',
         }
       ],
     },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index f5755d4..374a798 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2911,6 +2911,21 @@
             ]
         }
     ],
+    "DriveFsBidirectionalNativeMessaging": [
+        {
+            "platforms": [
+                "chromeos"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "DriveFsBidirectionalNativeMessaging"
+                    ]
+                }
+            ]
+        }
+    ],
     "DynamicTcmallocThreadCache": [
         {
             "platforms": [
@@ -3737,6 +3752,21 @@
             ]
         }
     ],
+    "IOSErrorPageRefactoring": [
+        {
+            "platforms": [
+                "ios"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "UseJSForErrorPage"
+                    ]
+                }
+            ]
+        }
+    ],
     "IOSFullPageScreenshot": [
         {
             "platforms": [
diff --git a/third_party/blink/public/common/BUILD.gn b/third_party/blink/public/common/BUILD.gn
index 1b409bc..9edade2 100644
--- a/third_party/blink/public/common/BUILD.gn
+++ b/third_party/blink/public/common/BUILD.gn
@@ -69,6 +69,7 @@
     "client_hints/client_hints.h",
     "context_menu_data/edit_flags.h",
     "context_menu_data/input_field_type.h",
+    "css/color_scheme.h",
     "css/forced_colors.h",
     "css/navigation_controls.h",
     "css/page_orientation.h",
diff --git a/third_party/blink/public/common/css/color_scheme.h b/third_party/blink/public/common/css/color_scheme.h
new file mode 100644
index 0000000..3ea04a9f
--- /dev/null
+++ b/third_party/blink/public/common/css/color_scheme.h
@@ -0,0 +1,21 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_CSS_COLOR_SCHEME_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_CSS_COLOR_SCHEME_H_
+
+namespace blink {
+
+// This is the color scheme for rendering web content. The color scheme affects
+// the UA style sheet (setting the text color to white instead of black on the
+// root element for kDark), the frame backdrop color (black instead of white for
+// kDark), theming form controls and scrollbars, etc.
+enum ColorScheme {
+  kLight = 1,
+  kDark = 2,
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_CSS_COLOR_SCHEME_H_
diff --git a/third_party/blink/public/common/frame/frame_owner_properties_mojom_traits.h b/third_party/blink/public/common/frame/frame_owner_properties_mojom_traits.h
new file mode 100644
index 0000000..76907d7
--- /dev/null
+++ b/third_party/blink/public/common/frame/frame_owner_properties_mojom_traits.h
@@ -0,0 +1,44 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_FRAME_FRAME_OWNER_PROPERTIES_MOJOM_TRAITS_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_FRAME_FRAME_OWNER_PROPERTIES_MOJOM_TRAITS_H_
+
+#include "mojo/public/cpp/bindings/enum_traits.h"
+#include "third_party/blink/public/common/common_export.h"
+#include "third_party/blink/public/common/css/color_scheme.h"
+#include "third_party/blink/public/mojom/frame/frame_owner_properties.mojom-shared.h"
+
+namespace mojo {
+
+template <>
+struct BLINK_COMMON_EXPORT
+    EnumTraits<blink::mojom::ColorScheme, ::blink::ColorScheme> {
+  static blink::mojom::ColorScheme ToMojom(::blink::ColorScheme color_scheme) {
+    switch (color_scheme) {
+      case ::blink::ColorScheme::kLight:
+        return blink::mojom::ColorScheme::kLight;
+      case ::blink::ColorScheme::kDark:
+        return blink::mojom::ColorScheme::kDark;
+    }
+    NOTREACHED();
+    return blink::mojom::ColorScheme::kLight;
+  }
+  static bool FromMojom(blink::mojom::ColorScheme input,
+                        ::blink::ColorScheme* out) {
+    switch (input) {
+      case blink::mojom::ColorScheme::kLight:
+        *out = ::blink::ColorScheme::kLight;
+        return true;
+      case blink::mojom::ColorScheme::kDark:
+        *out = ::blink::ColorScheme::kDark;
+        return true;
+    }
+    return false;
+  }
+};
+
+}  // namespace mojo
+
+#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_FRAME_FRAME_OWNER_PROPERTIES_MOJOM_TRAITS_H_
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index b421478..e8343d8 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -7143,6 +7143,51 @@
       # Timestamp title.
       string title
 
+# Reporting of performance timeline events, as specified in
+# https://w3c.github.io/performance-timeline/#dom-performanceobserver.
+experimental domain PerformanceTimeline
+  depends on DOM
+  depends on Network
+
+  # See https://github.com/WICG/LargestContentfulPaint and largest_contentful_paint.idl
+  type LargestContentfulPaint extends object
+    properties
+      number renderTime
+      number loadTime
+      # The number of pixels being painted.
+      number size
+      # The id attribute of the element, if available.
+      optional string elementId
+      # The URL of the image (may be trimmed).
+      optional string url
+      optional DOM.BackendNodeId nodeId
+
+  type TimelineEvent extends object
+    properties
+      # Identifies the frame that this event is related to. Empty for non-frame targets.
+      Page.FrameId frameId
+      string type
+      string name
+      # Time in seconds since Epoch, monotonically increasing within document lifetime.
+      Network.TimeSinceEpoch time
+      # Event duration, if applicable.
+      optional number duration
+      optional LargestContentfulPaint lcpDetails
+
+  # Previously buffered events would be reported before method returns.
+  # The specified filter overrides any previous filters, passing empty
+  # filter disables recording.
+  # Note that not all types exposed to the web platform are currently supported.
+  # See also: timelineEventAdded
+  command enable
+    parameters
+      array of string eventTypes
+
+  # Sent when a performance timeline event is added. See reportPerformanceTimeline method.
+  event timelineEventAdded
+    parameters
+      TimelineEvent event
+
 # Security
 domain Security
 
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn
index 7ea2a72..cfdb8c492 100644
--- a/third_party/blink/public/mojom/BUILD.gn
+++ b/third_party/blink/public/mojom/BUILD.gn
@@ -212,7 +212,6 @@
   public_deps = [
     ":android_mojo_bindings",
     ":authenticator_test_mojo_bindings",
-    ":color_scheme_mojo_bindings",
     ":mojom_mhtml_load_result",
     ":script_type_mojo_bindings",
     ":web_feature_mojo_bindings",
@@ -416,6 +415,17 @@
     {
       types = [
         {
+          mojom = "blink.mojom.ColorScheme"
+          cpp = "::blink::ColorScheme"
+          copyable_pass_by_value = true
+        },
+      ]
+      traits_headers = [ "//third_party/blink/public/common/frame/frame_owner_properties_mojom_traits.h" ]
+      traits_public_deps = [ "//third_party/blink/public/common:headers" ]
+    },
+    {
+      types = [
+        {
           mojom = "blink.mojom.WebPreferences"
           cpp = "::blink::web_pref::WebPreferences"
         },
@@ -828,7 +838,6 @@
 
   public_deps = [
     ":android_mojo_bindings",
-    ":color_scheme_mojo_bindings",
     ":mojom_platform",
     ":script_type_mojo_bindings",
     ":web_feature_mojo_bindings",
@@ -1300,23 +1309,6 @@
   export_header_blink = "third_party/blink/renderer/platform/platform_export.h"
 }
 
-mojom("color_scheme_mojo_bindings") {
-  generate_java = true
-  visibility_blink = [
-    "//third_party/blink/public/mojom:mojom_core_blink",
-    "//third_party/blink/public/mojom:mojom_platform_blink",
-    "//third_party/blink/renderer/core:prerequisites",
-    "//third_party/blink/renderer/modules",
-    "//third_party/blink/renderer/platform",
-  ]
-
-  sources = [ "frame/color_scheme.mojom" ]
-
-  export_class_attribute = "BLINK_COMMON_EXPORT"
-  export_define = "BLINK_COMMON_IMPLEMENTATION=1"
-  export_header = "third_party/blink/public/common/common_export.h"
-}
-
 mojom("mobile_metrics") {
   sources = [ "mobile_metrics/mobile_friendliness.mojom" ]
   cpp_typemaps = [
diff --git a/third_party/blink/public/mojom/frame/color_scheme.mojom b/third_party/blink/public/mojom/frame/color_scheme.mojom
deleted file mode 100644
index d4f3f3c..0000000
--- a/third_party/blink/public/mojom/frame/color_scheme.mojom
+++ /dev/null
@@ -1,10 +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.
-
-module blink.mojom;
-
-enum ColorScheme {
-  kLight,
-  kDark,
-};
diff --git a/third_party/blink/public/mojom/frame/frame_owner_properties.mojom b/third_party/blink/public/mojom/frame/frame_owner_properties.mojom
index c6f9ef1d..aeb9f5ce 100644
--- a/third_party/blink/public/mojom/frame/frame_owner_properties.mojom
+++ b/third_party/blink/public/mojom/frame/frame_owner_properties.mojom
@@ -5,7 +5,11 @@
 module blink.mojom;
 
 import "third_party/blink/public/mojom/scroll/scrollbar_mode.mojom";
-import "third_party/blink/public/mojom/frame/color_scheme.mojom";
+
+enum ColorScheme {
+  kLight,
+  kDark,
+};
 
 struct FrameOwnerProperties {
   // Browsing context container's name
diff --git a/third_party/blink/public/platform/mac/web_sandbox_support.h b/third_party/blink/public/platform/mac/web_sandbox_support.h
index 0dbe483..a91384b7 100644
--- a/third_party/blink/public/platform/mac/web_sandbox_support.h
+++ b/third_party/blink/public/platform/mac/web_sandbox_support.h
@@ -32,8 +32,8 @@
 #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MAC_WEB_SANDBOX_SUPPORT_H_
 
 #include "base/mac/scoped_cftyperef.h"
+#include "third_party/blink/public/common/css/color_scheme.h"
 #include "third_party/blink/public/common/sandbox_support/sandbox_support_mac.h"
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-shared.h"
 #include "third_party/skia/include/core/SkColor.h"
 
 typedef struct CGFont* CGFontRef;
@@ -57,7 +57,7 @@
       uint32_t* font_id) = 0;
 
   // Returns the system's preferred value for a named color.
-  virtual SkColor GetSystemColor(MacSystemColorID, mojom::ColorScheme) = 0;
+  virtual SkColor GetSystemColor(MacSystemColorID, ColorScheme) = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/public/platform/web_theme_engine.h b/third_party/blink/public/platform/web_theme_engine.h
index 8873bdf..97a07fd 100644
--- a/third_party/blink/public/platform/web_theme_engine.h
+++ b/third_party/blink/public/platform/web_theme_engine.h
@@ -34,8 +34,8 @@
 #include "base/optional.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "third_party/blink/public/common/css/color_scheme.h"
 #include "third_party/blink/public/common/css/forced_colors.h"
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-shared.h"
 #include "third_party/blink/public/platform/web_scrollbar_overlay_color_theme.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/rect.h"
@@ -189,7 +189,7 @@
   struct ScrollbarExtraParams {
     bool is_hovering;
     bool is_overlay;
-    mojom::ColorScheme scrollbar_theme;
+    ColorScheme scrollbar_theme;
     ScrollbarOrientation orientation;
   };
 #endif
@@ -246,7 +246,7 @@
                      State,
                      const gfx::Rect&,
                      const ExtraParams*,
-                     blink::mojom::ColorScheme) {}
+                     blink::ColorScheme) {}
 
   virtual base::Optional<SkColor> GetSystemColor(
       SystemThemeColor system_theme) const {
diff --git a/third_party/blink/public/web/web_frame_owner_properties.h b/third_party/blink/public/web/web_frame_owner_properties.h
index bc8a70072..150fdd6 100644
--- a/third_party/blink/public/web/web_frame_owner_properties.h
+++ b/third_party/blink/public/web/web_frame_owner_properties.h
@@ -5,7 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_FRAME_OWNER_PROPERTIES_H_
 #define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_FRAME_OWNER_PROPERTIES_H_
 
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-shared.h"
+#include "third_party/blink/public/common/css/color_scheme.h"
 #include "third_party/blink/public/mojom/scroll/scrollbar_mode.mojom-shared.h"
 #include "third_party/blink/public/platform/web_string.h"
 
@@ -19,7 +19,7 @@
   bool allow_fullscreen{false};
   bool allow_payment_request{false};
   bool is_display_none{false};
-  mojom::ColorScheme color_scheme{mojom::ColorScheme::kLight};
+  ColorScheme color_scheme{ColorScheme::kLight};
   WebString required_csp;
 
  public:
@@ -33,7 +33,7 @@
                           bool allow_fullscreen,
                           bool allow_payment_request,
                           bool is_display_none,
-                          mojom::ColorScheme color_scheme,
+                          ColorScheme color_scheme,
                           const WebString& required_csp)
       : name(name),
         scrollbar_mode(scrollbar_mode),
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index b9e8f4e2d73..4310ee3 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -125,7 +125,6 @@
     "//services/service_manager/public/cpp",
     "//skia",
     "//third_party/angle:translator",
-    "//third_party/blink/public/mojom:color_scheme_mojo_bindings",
     "//third_party/blink/public/mojom:mojom_broadcastchannel_bindings_blink",
     "//third_party/blink/renderer/bindings/core/v8:bindings_core_v8_generated",
     "//third_party/blink/renderer/bindings/core/v8:generated",
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index f57b9b0..1e4dca11 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -1898,7 +1898,7 @@
       property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal", "InitialValue"],
       style_builder_custom_functions: ["initial", "inherit", "value"],
       inherited: true,
-      include_paths: ["third_party/blink/public/mojom/frame/color_scheme.mojom-blink.h"],
+      include_paths: ["third_party/blink/public/common/css/color_scheme.h"],
       type_name: "Vector<AtomicString>",
       default_value: "Vector<AtomicString, 0>()",
       field_template: "external",
diff --git a/third_party/blink/renderer/core/css/parser/css_parser.cc b/third_party/blink/renderer/core/css/parser/css_parser.cc
index 24e43759..8ac3af1 100644
--- a/third_party/blink/renderer/core/css/parser/css_parser.cc
+++ b/third_party/blink/renderer/core/css/parser/css_parser.cc
@@ -280,7 +280,7 @@
 
 bool CSSParser::ParseSystemColor(Color& color,
                                  const String& color_string,
-                                 mojom::blink::ColorScheme color_scheme) {
+                                 ColorScheme color_scheme) {
   CSSValueID id = CssValueKeywordID(color_string);
   if (!StyleColor::IsSystemColor(id))
     return false;
diff --git a/third_party/blink/renderer/core/css/parser/css_parser.h b/third_party/blink/renderer/core/css/parser/css_parser.h
index 9277f458..99a926f 100644
--- a/third_party/blink/renderer/core/css/parser/css_parser.h
+++ b/third_party/blink/renderer/core/css/parser/css_parser.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PARSER_CSS_PARSER_H_
 
 #include <memory>
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink-forward.h"
+#include "third_party/blink/public/common/css/color_scheme.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css/css_property_names.h"
 #include "third_party/blink/renderer/core/css/css_property_value_set.h"
@@ -103,9 +103,7 @@
   // The color will only be changed when string contains a valid CSS color, so
   // callers can set it to a default color and ignore the boolean result.
   static bool ParseColor(Color&, const String&, bool strict = false);
-  static bool ParseSystemColor(Color&,
-                               const String&,
-                               mojom::blink::ColorScheme color_scheme);
+  static bool ParseSystemColor(Color&, const String&, ColorScheme color_scheme);
 
   static void ParseSheetForInspector(const CSSParserContext*,
                                      StyleSheetContents*,
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 6e41b3b..8aa2d4db 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
@@ -1928,9 +1928,8 @@
     if (value_id == CSSValueID::kCurrentcolor)
       return value;
     if (StyleColor::IsColorKeyword(value_id)) {
-      mojom::blink::ColorScheme scheme =
-          state ? state->Style()->UsedColorScheme()
-                : mojom::blink::ColorScheme::kLight;
+      ColorScheme scheme =
+          state ? state->Style()->UsedColorScheme() : ColorScheme::kLight;
       Color color = document.GetTextLinkColors().ColorFromCSSValue(
           value, Color(), scheme, false);
       return *cssvalue::CSSColorValue::Create(color.Rgb());
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc b/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
index 6be1002..4023f26 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
@@ -215,7 +215,7 @@
   if (const auto* pair = DynamicTo<CSSLightDarkValuePair>(value)) {
     if (!property.IsInherited())
       Style()->SetHasNonInheritedLightDarkValue();
-    if (Style()->UsedColorScheme() == mojom::blink::ColorScheme::kLight)
+    if (Style()->UsedColorScheme() == ColorScheme::kLight)
       return pair->First();
     return pair->Second();
   }
diff --git a/third_party/blink/renderer/core/css/style_color.cc b/third_party/blink/renderer/core/css/style_color.cc
index 0a9dab2..b62e67c 100644
--- a/third_party/blink/renderer/core/css/style_color.cc
+++ b/third_party/blink/renderer/core/css/style_color.cc
@@ -10,7 +10,7 @@
 namespace blink {
 
 Color StyleColor::Resolve(Color current_color,
-                          mojom::blink::ColorScheme color_scheme,
+                          ColorScheme color_scheme,
                           bool is_forced_color) const {
   if (IsCurrentColor())
     return current_color;
@@ -21,7 +21,7 @@
 }
 
 Color StyleColor::ResolveWithAlpha(Color current_color,
-                                   mojom::blink::ColorScheme color_scheme,
+                                   ColorScheme color_scheme,
                                    int alpha,
                                    bool is_forced_color) const {
   Color color = Resolve(current_color, color_scheme, is_forced_color);
@@ -29,7 +29,7 @@
 }
 
 Color StyleColor::ColorFromKeyword(CSSValueID keyword,
-                                   mojom::blink::ColorScheme color_scheme) {
+                                   ColorScheme color_scheme) {
   if (const char* value_name = getValueName(keyword)) {
     if (const NamedColor* named_color =
             FindColor(value_name, static_cast<wtf_size_t>(strlen(value_name))))
diff --git a/third_party/blink/renderer/core/css/style_color.h b/third_party/blink/renderer/core/css/style_color.h
index 4cab8f2..8a0b6ca 100644
--- a/third_party/blink/renderer/core/css/style_color.h
+++ b/third_party/blink/renderer/core/css/style_color.h
@@ -31,7 +31,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_STYLE_COLOR_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_STYLE_COLOR_H_
 
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink-forward.h"
+#include "third_party/blink/public/common/css/color_scheme.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css_value_keywords.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
@@ -74,7 +74,7 @@
   // TODO(1081945):  Once CSSSystemColorComputeToSelf is enabled, we can remove
   // |is_forced_color|.
   Color Resolve(Color current_color,
-                mojom::blink::ColorScheme color_scheme,
+                ColorScheme color_scheme,
                 bool is_forced_color = false) const;
 
   // Resolve and override the resolved color's alpha channel as specified by
@@ -82,7 +82,7 @@
   // TODO(1081945):  Once CSSSystemColorComputeToSelf is enabled, we can remove
   // |is_forced_color|.
   Color ResolveWithAlpha(Color current_color,
-                         mojom::blink::ColorScheme color_scheme,
+                         ColorScheme color_scheme,
                          int alpha,
                          bool is_forced_color = false) const;
 
@@ -90,8 +90,7 @@
     return EffectiveColorKeyword() == CSSValueID::kInvalid;
   }
 
-  static Color ColorFromKeyword(CSSValueID,
-                                mojom::blink::ColorScheme color_scheme);
+  static Color ColorFromKeyword(CSSValueID, ColorScheme color_scheme);
   static bool IsColorKeyword(CSSValueID);
   static bool IsSystemColor(CSSValueID);
 
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc
index 8d07634..24b1488 100644
--- a/third_party/blink/renderer/core/css/style_engine.cc
+++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -29,7 +29,6 @@
 
 #include "third_party/blink/renderer/core/css/style_engine.h"
 
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_theme_engine.h"
 #include "third_party/blink/renderer/core/css/counter_style_map.h"
@@ -112,8 +111,7 @@
     : document_(&document),
       is_html_import_(document.IsHTMLImport()),
       document_style_sheet_collection_(
-          MakeGarbageCollected<DocumentStyleSheetCollection>(document)),
-      owner_color_scheme_(mojom::blink::ColorScheme::kLight) {
+          MakeGarbageCollected<DocumentStyleSheetCollection>(document)) {
   if (document.GetFrame()) {
     // We don't need to create CSSFontSelector for imported document or
     // HTMLTemplateElement's document, because those documents have no frame.
@@ -2284,20 +2282,18 @@
     // view's base background color in order to match the root element color-
     // scheme. See spec:
     // https://drafts.csswg.org/css-color-adjust/#color-scheme-effect
-    mojom::blink::ColorScheme root_color_scheme =
-        mojom::blink::ColorScheme::kLight;
+    ColorScheme root_color_scheme = ColorScheme::kLight;
     if (auto* root_element = GetDocument().documentElement()) {
       if (const ComputedStyle* style = root_element->GetComputedStyle())
         root_color_scheme = style->UsedColorSchemeForInitialColors();
       else if (SupportsDarkColorScheme())
-        root_color_scheme = mojom::blink::ColorScheme::kDark;
+        root_color_scheme = ColorScheme::kDark;
     }
-    color_scheme_background_ =
-        root_color_scheme == mojom::blink::ColorScheme::kLight
-            ? Color::kWhite
-            : Color(0x12, 0x12, 0x12);
+    color_scheme_background_ = root_color_scheme == ColorScheme::kLight
+                                   ? Color::kWhite
+                                   : Color(0x12, 0x12, 0x12);
     if (GetDocument().IsInMainFrame()) {
-      if (root_color_scheme == mojom::blink::ColorScheme::kDark) {
+      if (root_color_scheme == ColorScheme::kDark) {
         use_color_adjust_background =
             LocalFrameView::UseColorAdjustBackground::kIfBaseNotTransparent;
       }
@@ -2314,7 +2310,7 @@
                                     color_scheme_changed);
 }
 
-void StyleEngine::SetOwnerColorScheme(mojom::blink::ColorScheme color_scheme) {
+void StyleEngine::SetOwnerColorScheme(ColorScheme color_scheme) {
   DCHECK(!GetDocument().IsInMainFrame());
   if (owner_color_scheme_ == color_scheme)
     return;
@@ -2324,7 +2320,7 @@
 
 void StyleEngine::UpdateForcedBackgroundColor() {
   forced_background_color_ = LayoutTheme::GetTheme().SystemColor(
-      CSSValueID::kCanvas, mojom::blink::ColorScheme::kLight);
+      CSSValueID::kCanvas, ColorScheme::kLight);
 }
 
 Color StyleEngine::ColorAdjustBackgroundColor() const {
diff --git a/third_party/blink/renderer/core/css/style_engine.h b/third_party/blink/renderer/core/css/style_engine.h
index 9e05a79..b788afc0 100644
--- a/third_party/blink/renderer/core/css/style_engine.h
+++ b/third_party/blink/renderer/core/css/style_engine.h
@@ -159,10 +159,8 @@
   void WatchedSelectorsChanged();
   void InitialStyleChanged();
   void ColorSchemeChanged();
-  void SetOwnerColorScheme(mojom::blink::ColorScheme);
-  mojom::blink::ColorScheme GetOwnerColorScheme() const {
-    return owner_color_scheme_;
-  }
+  void SetOwnerColorScheme(ColorScheme);
+  ColorScheme GetOwnerColorScheme() const { return owner_color_scheme_; }
   void InitialViewportChanged();
   void ViewportRulesChanged();
   void HtmlImportAddedOrRemoved();
@@ -669,7 +667,7 @@
   // embedding document. If the color-scheme of the owner element and the root
   // element in the embedded document differ, use a solid backdrop color instead
   // of the default transparency of an iframe.
-  mojom::blink::ColorScheme owner_color_scheme_;
+  ColorScheme owner_color_scheme_{ColorScheme::kLight};
 
   // The color of the canvas backdrop for the used color-scheme.
   Color color_scheme_background_;
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc
index 896b68a2..aac42901 100644
--- a/third_party/blink/renderer/core/css/style_engine_test.cc
+++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -2402,7 +2402,7 @@
   color_scheme_helper.SetForcedColors(GetDocument(), ForcedColors::kActive);
   UpdateAllLifecyclePhases();
   Color system_background_color = LayoutTheme::GetTheme().SystemColor(
-      CSSValueID::kCanvas, mojom::blink::ColorScheme::kLight);
+      CSSValueID::kCanvas, ColorScheme::kLight);
 
   EXPECT_EQ(system_background_color,
             GetDocument().View()->BaseBackgroundColor());
@@ -2420,7 +2420,7 @@
   UpdateAllLifecyclePhases();
 
   EXPECT_EQ(
-      mojom::blink::ColorScheme::kLight,
+      ColorScheme::kLight,
       GetDocument().documentElement()->GetComputedStyle()->UsedColorScheme());
 
   GetDocument().GetPage()->SetMediaFeatureOverride("prefers-color-scheme",
@@ -2428,7 +2428,7 @@
 
   UpdateAllLifecyclePhases();
   EXPECT_EQ(
-      mojom::blink::ColorScheme::kDark,
+      ColorScheme::kDark,
       GetDocument().documentElement()->GetComputedStyle()->UsedColorScheme());
 }
 
@@ -2984,7 +2984,7 @@
 
   EXPECT_EQ(Color::kWhite, root->GetComputedStyle()->VisitedDependentColor(
                                GetCSSPropertyColor()));
-  EXPECT_EQ(mojom::blink::ColorScheme::kDark,
+  EXPECT_EQ(ColorScheme::kDark,
             root->GetComputedStyle()->UsedColorSchemeForInitialColors());
   EXPECT_EQ(MakeRGB(255, 0, 0), body->GetComputedStyle()->VisitedDependentColor(
                                     GetCSSPropertyColor()));
@@ -2993,7 +2993,7 @@
   GetDocument().GetFrame()->StartPrinting(page_size, page_size, 1);
   EXPECT_EQ(Color::kBlack, root->GetComputedStyle()->VisitedDependentColor(
                                GetCSSPropertyColor()));
-  EXPECT_EQ(mojom::blink::ColorScheme::kLight,
+  EXPECT_EQ(ColorScheme::kLight,
             root->GetComputedStyle()->UsedColorSchemeForInitialColors());
   EXPECT_EQ(MakeRGB(0, 128, 0), body->GetComputedStyle()->VisitedDependentColor(
                                     GetCSSPropertyColor()));
@@ -3001,7 +3001,7 @@
   GetDocument().GetFrame()->EndPrinting();
   EXPECT_EQ(Color::kWhite, root->GetComputedStyle()->VisitedDependentColor(
                                GetCSSPropertyColor()));
-  EXPECT_EQ(mojom::blink::ColorScheme::kDark,
+  EXPECT_EQ(ColorScheme::kDark,
             root->GetComputedStyle()->UsedColorSchemeForInitialColors());
   EXPECT_EQ(MakeRGB(255, 0, 0), body->GetComputedStyle()->VisitedDependentColor(
                                     GetCSSPropertyColor()));
@@ -3492,14 +3492,14 @@
       To<HTMLIFrameElement>(GetDocument().getElementById("frame"));
   auto* frame_document = frame_element->contentDocument();
   ASSERT_TRUE(frame_document);
-  EXPECT_EQ(mojom::blink::ColorScheme::kDark,
+  EXPECT_EQ(ColorScheme::kDark,
             frame_document->GetStyleEngine().GetOwnerColorScheme());
 
   frame_element->SetInlineStyleProperty(CSSPropertyID::kColorScheme, "light");
 
   test::RunPendingTasks();
   Compositor().BeginFrame();
-  EXPECT_EQ(mojom::blink::ColorScheme::kLight,
+  EXPECT_EQ(ColorScheme::kLight,
             frame_document->GetStyleEngine().GetOwnerColorScheme());
 }
 
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index b08ad0c..810da9e6 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -5703,7 +5703,7 @@
     int margin_height,
     mojom::blink::ScrollbarMode scrollbar_mode,
     bool is_display_none,
-    mojom::blink::ColorScheme color_scheme) {
+    ColorScheme color_scheme) {
   DCHECK(GetFrame() && GetFrame()->Owner());
   FrameOwner* owner = GetFrame()->Owner();
 
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 2e98959..6c100bb 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -992,7 +992,7 @@
                                       int margin_height,
                                       mojom::blink::ScrollbarMode,
                                       bool is_display_none,
-                                      mojom::ColorScheme color_scheme);
+                                      ColorScheme color_scheme);
 
   String title() const { return title_; }
   void setTitle(const String&);
diff --git a/third_party/blink/renderer/core/dom/text_link_colors.cc b/third_party/blink/renderer/core/dom/text_link_colors.cc
index d08b167..aa3bf1ac 100644
--- a/third_party/blink/renderer/core/dom/text_link_colors.cc
+++ b/third_party/blink/renderer/core/dom/text_link_colors.cc
@@ -29,7 +29,6 @@
 
 #include "third_party/blink/renderer/core/dom/text_link_colors.h"
 
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink.h"
 #include "third_party/blink/renderer/core/css/css_color_value.h"
 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
 #include "third_party/blink/renderer/core/css/css_light_dark_value_pair.h"
@@ -61,16 +60,11 @@
   has_custom_text_color_ = true;
 }
 
-Color TextLinkColors::TextColor() const {
-  return TextColor(mojom::ColorScheme::kLight);
-}
-
-Color TextLinkColors::TextColor(mojom::blink::ColorScheme color_scheme) const {
+Color TextLinkColors::TextColor(ColorScheme color_scheme) const {
   return has_custom_text_color_
              ? text_color_
-             : color_scheme == mojom::blink::ColorScheme::kLight
-                   ? Color::kBlack
-                   : Color::kWhite;
+             : color_scheme == ColorScheme::kLight ? Color::kBlack
+                                                   : Color::kWhite;
 }
 
 void TextLinkColors::SetLinkColor(const Color& color) {
@@ -78,17 +72,11 @@
   has_custom_link_color_ = true;
 }
 
-const Color& TextLinkColors::LinkColor() const {
-  return LinkColor(mojom::ColorScheme::kLight);
-}
-
-const Color& TextLinkColors::LinkColor(
-    mojom::blink::ColorScheme color_scheme) const {
+const Color& TextLinkColors::LinkColor(ColorScheme color_scheme) const {
   return has_custom_link_color_
              ? link_color_
-             : color_scheme == mojom::blink::ColorScheme::kLight
-                   ? kDefaultLinkColorLight
-                   : kDefaultLinkColorDark;
+             : color_scheme == ColorScheme::kLight ? kDefaultLinkColorLight
+                                                   : kDefaultLinkColorDark;
 }
 
 void TextLinkColors::SetVisitedLinkColor(const Color& color) {
@@ -96,17 +84,11 @@
   has_custom_visited_link_color_ = true;
 }
 
-const Color& TextLinkColors::VisitedLinkColor() const {
-  return VisitedLinkColor(mojom::ColorScheme::kLight);
-}
-
-const Color& TextLinkColors::VisitedLinkColor(
-    mojom::blink::ColorScheme color_scheme) const {
-  return has_custom_visited_link_color_
-             ? visited_link_color_
-             : color_scheme == mojom::blink::ColorScheme::kLight
-                   ? kDefaultVisitedLinkColorLight
-                   : kDefaultVisitedLinkColorDark;
+const Color& TextLinkColors::VisitedLinkColor(ColorScheme color_scheme) const {
+  return has_custom_visited_link_color_ ? visited_link_color_
+                                        : color_scheme == ColorScheme::kLight
+                                              ? kDefaultVisitedLinkColorLight
+                                              : kDefaultVisitedLinkColorDark;
 }
 
 void TextLinkColors::SetActiveLinkColor(const Color& color) {
@@ -114,30 +96,23 @@
   has_custom_active_link_color_ = true;
 }
 
-const Color& TextLinkColors::ActiveLinkColor() const {
-  return ActiveLinkColor(mojom::ColorScheme::kLight);
-}
-
-const Color& TextLinkColors::ActiveLinkColor(
-    mojom::blink::ColorScheme color_scheme) const {
-  return has_custom_active_link_color_
-             ? active_link_color_
-             : color_scheme == mojom::blink::ColorScheme::kLight
-                   ? kDefaultActiveLinkColorLight
-                   : kDefaultActiveLinkColorDark;
+const Color& TextLinkColors::ActiveLinkColor(ColorScheme color_scheme) const {
+  return has_custom_active_link_color_ ? active_link_color_
+                                       : color_scheme == ColorScheme::kLight
+                                             ? kDefaultActiveLinkColorLight
+                                             : kDefaultActiveLinkColorDark;
 }
 
 Color TextLinkColors::ColorFromCSSValue(const CSSValue& value,
                                         Color current_color,
-                                        mojom::blink::ColorScheme color_scheme,
+                                        ColorScheme color_scheme,
                                         bool for_visited_link) const {
   if (auto* color_value = DynamicTo<cssvalue::CSSColorValue>(value))
     return color_value->Value();
 
   if (auto* pair = DynamicTo<CSSLightDarkValuePair>(value)) {
     const CSSValue& color_value =
-        color_scheme == mojom::blink::ColorScheme::kLight ? pair->First()
-                                                          : pair->Second();
+        color_scheme == ColorScheme::kLight ? pair->First() : pair->Second();
     return ColorFromCSSValue(color_value, current_color, color_scheme,
                              for_visited_link);
   }
diff --git a/third_party/blink/renderer/core/dom/text_link_colors.h b/third_party/blink/renderer/core/dom/text_link_colors.h
index 23a5faf1..14efed8a 100644
--- a/third_party/blink/renderer/core/dom/text_link_colors.h
+++ b/third_party/blink/renderer/core/dom/text_link_colors.h
@@ -30,7 +30,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_TEXT_LINK_COLORS_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_TEXT_LINK_COLORS_H_
 
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-forward.h"
+#include "third_party/blink/public/common/css/color_scheme.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
@@ -47,15 +47,13 @@
   TextLinkColors& operator=(const TextLinkColors&) = delete;
 
   void SetTextColor(const Color& color);
-  Color TextColor() const;
-  Color TextColor(mojom::ColorScheme color_scheme) const;
+  Color TextColor(ColorScheme color_scheme = ColorScheme::kLight) const;
 
-  const Color& LinkColor() const;
-  const Color& LinkColor(mojom::ColorScheme color_scheme) const;
-  const Color& VisitedLinkColor() const;
-  const Color& VisitedLinkColor(mojom::ColorScheme color_scheme) const;
-  const Color& ActiveLinkColor() const;
-  const Color& ActiveLinkColor(mojom::ColorScheme color_scheme) const;
+  const Color& LinkColor(ColorScheme color_scheme = ColorScheme::kLight) const;
+  const Color& VisitedLinkColor(
+      ColorScheme color_scheme = ColorScheme::kLight) const;
+  const Color& ActiveLinkColor(
+      ColorScheme color_scheme = ColorScheme::kLight) const;
   void SetLinkColor(const Color& color);
   void SetVisitedLinkColor(const Color& color);
   void SetActiveLinkColor(const Color& color);
@@ -64,7 +62,7 @@
   void ResetActiveLinkColor() { has_custom_active_link_color_ = false; }
   Color ColorFromCSSValue(const CSSValue&,
                           Color current_color,
-                          mojom::ColorScheme color_scheme,
+                          ColorScheme color_scheme,
                           bool for_visited_link = false) const;
 
  private:
diff --git a/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc b/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc
index 75f9a5b1..33434d705 100644
--- a/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc
@@ -73,6 +73,7 @@
 #include "third_party/blink/renderer/core/inspector/inspector_overlay_agent.h"
 #include "third_party/blink/renderer/core/inspector/inspector_page_agent.h"
 #include "third_party/blink/renderer/core/inspector/inspector_performance_agent.h"
+#include "third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.h"
 #include "third_party/blink/renderer/core/inspector/inspector_resource_container.h"
 #include "third_party/blink/renderer/core/inspector/inspector_resource_content_loader.h"
 #include "third_party/blink/renderer/core/inspector/inspector_task_runner.h"
@@ -288,6 +289,9 @@
   session->Append(MakeGarbageCollected<InspectorEmulationAgent>(
       web_local_frame_impl_.Get()));
 
+  session->Append(MakeGarbageCollected<InspectorPerformanceTimelineAgent>(
+      inspected_frames));
+
   // Call session init callbacks registered from higher layers.
   CoreInitializer::GetInstance().InitInspectorAgentSession(
       session, include_view_agents_, dom_agent, inspected_frames,
diff --git a/third_party/blink/renderer/core/exported/web_page_popup_impl.cc b/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
index eb962ab2..1110c224 100644
--- a/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
@@ -356,8 +356,7 @@
     bool in_forced_colors_mode =
         popup_client_->OwnerElement().GetDocument().InForcedColorsMode();
     page_->GetSettings().SetPreferredColorScheme(
-        style->UsedColorScheme() == mojom::blink::ColorScheme::kDark &&
-                !in_forced_colors_mode
+        style->UsedColorScheme() == ColorScheme::kDark && !in_forced_colors_mode
             ? mojom::blink::PreferredColorScheme::kDark
             : mojom::blink::PreferredColorScheme::kLight);
   }
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc
index 4144357..b2fe17a4 100644
--- a/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -593,7 +593,7 @@
   UpdateAllLifecyclePhases();
 
   Color system_background_color = LayoutTheme::GetTheme().SystemColor(
-      CSSValueID::kCanvas, mojom::blink::ColorScheme::kLight);
+      CSSValueID::kCanvas, ColorScheme::kLight);
   EXPECT_EQ(system_background_color, frame_view->BaseBackgroundColor());
 
   color_scheme_helper.SetForcedColors(*(web_view->GetPage()),
diff --git a/third_party/blink/renderer/core/frame/frame_owner.h b/third_party/blink/renderer/core/frame/frame_owner.h
index 90c1b81..163493e 100644
--- a/third_party/blink/renderer/core/frame/frame_owner.h
+++ b/third_party/blink/renderer/core/frame/frame_owner.h
@@ -4,7 +4,6 @@
 
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_OWNER_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_OWNER_H_
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-shared.h"
 
 #include "third_party/blink/public/common/frame/frame_policy.h"
 #include "third_party/blink/public/mojom/scroll/scrollbar_mode.mojom-blink.h"
@@ -73,7 +72,7 @@
   virtual bool AllowFullscreen() const = 0;
   virtual bool AllowPaymentRequest() const = 0;
   virtual bool IsDisplayNone() const = 0;
-  virtual mojom::ColorScheme GetColorScheme() const = 0;
+  virtual ColorScheme GetColorScheme() const = 0;
   virtual AtomicString RequiredCsp() const = 0;
 
   // Returns whether or not children of the owned frame should be lazily loaded.
@@ -152,9 +151,7 @@
   bool AllowFullscreen() const override { return false; }
   bool AllowPaymentRequest() const override { return false; }
   bool IsDisplayNone() const override { return false; }
-  mojom::ColorScheme GetColorScheme() const override {
-    return mojom::ColorScheme::kLight;
-  }
+  ColorScheme GetColorScheme() const override { return ColorScheme::kLight; }
   AtomicString RequiredCsp() const override { return g_null_atom; }
   bool ShouldLazyLoadChildren() const override { return false; }
 
diff --git a/third_party/blink/renderer/core/frame/local_frame_view_test.cc b/third_party/blink/renderer/core/frame/local_frame_view_test.cc
index f4d780e..612655ae 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view_test.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view_test.cc
@@ -196,8 +196,7 @@
   EXPECT_FALSE(ChildDocument().View()->CanHaveScrollbars());
 
   ChildDocument().WillChangeFrameOwnerProperties(
-      0, 0, mojom::blink::ScrollbarMode::kAlwaysOn, false,
-      mojom::blink::ColorScheme::kLight);
+      0, 0, mojom::blink::ScrollbarMode::kAlwaysOn, false, ColorScheme::kLight);
   EXPECT_TRUE(ChildDocument().View()->CanHaveScrollbars());
 }
 
diff --git a/third_party/blink/renderer/core/frame/remote_frame_owner.h b/third_party/blink/renderer/core/frame/remote_frame_owner.h
index 1350a6bc1..1094753 100644
--- a/third_party/blink/renderer/core/frame/remote_frame_owner.h
+++ b/third_party/blink/renderer/core/frame/remote_frame_owner.h
@@ -56,7 +56,7 @@
   bool AllowFullscreen() const override { return allow_fullscreen_; }
   bool AllowPaymentRequest() const override { return allow_payment_request_; }
   bool IsDisplayNone() const override { return is_display_none_; }
-  mojom::ColorScheme GetColorScheme() const override { return color_scheme_; }
+  ColorScheme GetColorScheme() const override { return color_scheme_; }
   AtomicString RequiredCsp() const override { return required_csp_; }
   bool ShouldLazyLoadChildren() const final;
 
@@ -78,7 +78,7 @@
   void SetIsDisplayNone(bool is_display_none) {
     is_display_none_ = is_display_none;
   }
-  void SetColorScheme(mojom::ColorScheme color_scheme) {
+  void SetColorScheme(ColorScheme color_scheme) {
     color_scheme_ = color_scheme;
   }
   void SetRequiredCsp(const WebString& required_csp) {
@@ -102,7 +102,7 @@
   bool allow_fullscreen_;
   bool allow_payment_request_;
   bool is_display_none_;
-  mojom::ColorScheme color_scheme_;
+  ColorScheme color_scheme_;
   bool needs_occlusion_tracking_;
   WebString required_csp_;
   const mojom::blink::FrameOwnerElementType frame_owner_element_type_;
diff --git a/third_party/blink/renderer/core/frame/root_frame_viewport.cc b/third_party/blink/renderer/core/frame/root_frame_viewport.cc
index d2f47ad..eda9c839 100644
--- a/third_party/blink/renderer/core/frame/root_frame_viewport.cc
+++ b/third_party/blink/renderer/core/frame/root_frame_viewport.cc
@@ -310,7 +310,7 @@
   return LayoutViewport().ScrollBehaviorStyle();
 }
 
-mojom::blink::ColorScheme RootFrameViewport::UsedColorScheme() const {
+ColorScheme RootFrameViewport::UsedColorScheme() const {
   return LayoutViewport().UsedColorScheme();
 }
 
diff --git a/third_party/blink/renderer/core/frame/root_frame_viewport.h b/third_party/blink/renderer/core/frame/root_frame_viewport.h
index 58fe030..c1c339645 100644
--- a/third_party/blink/renderer/core/frame/root_frame_viewport.h
+++ b/third_party/blink/renderer/core/frame/root_frame_viewport.h
@@ -112,7 +112,7 @@
   void UpdateCompositorScrollAnimations() override;
   void CancelProgrammaticScrollAnimation() override;
   mojom::blink::ScrollBehavior ScrollBehaviorStyle() const override;
-  mojom::blink::ColorScheme UsedColorScheme() const override;
+  ColorScheme UsedColorScheme() const override;
   void ClearScrollableArea() override;
   LayoutBox* GetLayoutBox() const override;
   FloatQuad LocalToVisibleContentQuad(const FloatQuad&,
diff --git a/third_party/blink/renderer/core/frame/root_frame_viewport_test.cc b/third_party/blink/renderer/core/frame/root_frame_viewport_test.cc
index bac6d698c..75a58b3a 100644
--- a/third_party/blink/renderer/core/frame/root_frame_viewport_test.cc
+++ b/third_party/blink/renderer/core/frame/root_frame_viewport_test.cc
@@ -107,7 +107,7 @@
                                                : user_input_scrollable_y_;
   }
   bool ScheduleAnimation() override { return true; }
-  mojom::blink::ColorScheme UsedColorScheme() const override {
+  ColorScheme UsedColorScheme() const override {
     return ComputedStyle::InitialStyle().UsedColorScheme();
   }
 
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.cc b/third_party/blink/renderer/core/frame/visual_viewport.cc
index c0e9b4c0..6951851 100644
--- a/third_party/blink/renderer/core/frame/visual_viewport.cc
+++ b/third_party/blink/renderer/core/frame/visual_viewport.cc
@@ -836,7 +836,7 @@
   return LocalMainFrame()->GetTaskRunner(TaskType::kInternalDefault);
 }
 
-mojom::blink::ColorScheme VisualViewport::UsedColorScheme() const {
+ColorScheme VisualViewport::UsedColorScheme() const {
   if (LocalFrame* main_frame = LocalMainFrame()) {
     if (Document* main_document = main_frame->GetDocument())
       return main_document->GetLayoutView()->StyleRef().UsedColorScheme();
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.h b/third_party/blink/renderer/core/frame/visual_viewport.h
index 4dc38ebe..0a6fa4d8 100644
--- a/third_party/blink/renderer/core/frame/visual_viewport.h
+++ b/third_party/blink/renderer/core/frame/visual_viewport.h
@@ -220,7 +220,7 @@
       IncludeScrollbarsInRect = kExcludeScrollbars) const override;
   scoped_refptr<base::SingleThreadTaskRunner> GetTimerTaskRunner()
       const override;
-  mojom::blink::ColorScheme UsedColorScheme() const override;
+  ColorScheme UsedColorScheme() const override;
 
   // VisualViewport scrolling may involve pinch zoom and gets routed through
   // WebViewImpl explicitly rather than via ScrollingCoordinator::DidScroll
diff --git a/third_party/blink/renderer/core/frame/visual_viewport_test.cc b/third_party/blink/renderer/core/frame/visual_viewport_test.cc
index 3855370f9..18923ee 100644
--- a/third_party/blink/renderer/core/frame/visual_viewport_test.cc
+++ b/third_party/blink/renderer/core/frame/visual_viewport_test.cc
@@ -2729,8 +2729,7 @@
   const VisualViewport& visual_viewport =
       WebView().GetPage()->GetVisualViewport();
 
-  EXPECT_EQ(mojom::blink::ColorScheme::kLight,
-            visual_viewport.UsedColorScheme());
+  EXPECT_EQ(ColorScheme::kLight, visual_viewport.UsedColorScheme());
 
   SimRequest request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
@@ -2742,8 +2741,7 @@
       )HTML");
   Compositor().BeginFrame();
 
-  EXPECT_EQ(mojom::blink::ColorScheme::kDark,
-            visual_viewport.UsedColorScheme());
+  EXPECT_EQ(ColorScheme::kDark, visual_viewport.UsedColorScheme());
 }
 
 TEST_P(VisualViewportTest, SetLocationBeforePrePaint) {
diff --git a/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc b/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc
index 6855e10..4e79ecf 100644
--- a/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc
+++ b/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc
@@ -218,8 +218,8 @@
     AddProperty("otherDateLabel", other_date_label_string, data);
 
     const ComputedStyle* style = OwnerElement().GetComputedStyle();
-    mojom::blink::ColorScheme color_scheme =
-        style ? style->UsedColorScheme() : mojom::blink::ColorScheme::kLight;
+    ColorScheme color_scheme =
+        style ? style->UsedColorScheme() : ColorScheme::kLight;
 
     AddProperty("suggestionHighlightColor",
                 LayoutTheme::GetTheme()
diff --git a/third_party/blink/renderer/core/html/html_frame_owner_element.cc b/third_party/blink/renderer/core/html/html_frame_owner_element.cc
index cc54e54d..761d1d93 100644
--- a/third_party/blink/renderer/core/html/html_frame_owner_element.cc
+++ b/third_party/blink/renderer/core/html/html_frame_owner_element.cc
@@ -23,7 +23,6 @@
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink.h"
 #include "third_party/blink/public/mojom/frame/frame_owner_properties.mojom-blink.h"
 #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
 #include "third_party/blink/renderer/core/css/style_change_reason.h"
@@ -690,14 +689,13 @@
   return content_frame_->IsAdSubframe();
 }
 
-mojom::blink::ColorScheme HTMLFrameOwnerElement::GetColorScheme() const {
+ColorScheme HTMLFrameOwnerElement::GetColorScheme() const {
   if (const auto* style = GetComputedStyle())
     return style->UsedColorSchemeForInitialColors();
-  return mojom::blink::ColorScheme::kLight;
+  return ColorScheme::kLight;
 }
 
-void HTMLFrameOwnerElement::SetColorScheme(
-    mojom::blink::ColorScheme color_scheme) {
+void HTMLFrameOwnerElement::SetColorScheme(ColorScheme color_scheme) {
   Document* doc = contentDocument();
   if (doc && doc->GetFrame()) {
     doc->WillChangeFrameOwnerProperties(MarginWidth(), MarginHeight(),
diff --git a/third_party/blink/renderer/core/html/html_frame_owner_element.h b/third_party/blink/renderer/core/html/html_frame_owner_element.h
index 320bda1b..268bc70c 100644
--- a/third_party/blink/renderer/core/html/html_frame_owner_element.h
+++ b/third_party/blink/renderer/core/html/html_frame_owner_element.h
@@ -74,7 +74,7 @@
     return embedded_content_view_;
   }
 
-  void SetColorScheme(mojom::ColorScheme);
+  void SetColorScheme(ColorScheme);
 
   class PluginDisposeSuspendScope {
     STACK_ALLOCATED();
@@ -118,7 +118,7 @@
   bool AllowFullscreen() const override { return false; }
   bool AllowPaymentRequest() const override { return false; }
   bool IsDisplayNone() const override { return !embedded_content_view_; }
-  mojom::ColorScheme GetColorScheme() const override;
+  ColorScheme GetColorScheme() const override;
   AtomicString RequiredCsp() const override { return g_null_atom; }
   bool ShouldLazyLoadChildren() const final;
 
diff --git a/third_party/blink/renderer/core/html/html_meta_element.cc b/third_party/blink/renderer/core/html/html_meta_element.cc
index d6b0d29..389dcc9 100644
--- a/third_party/blink/renderer/core/html/html_meta_element.cc
+++ b/third_party/blink/renderer/core/html/html_meta_element.cc
@@ -22,8 +22,8 @@
 
 #include "third_party/blink/renderer/core/html/html_meta_element.h"
 
+#include "third_party/blink/public/common/css/color_scheme.h"
 #include "third_party/blink/public/common/features.h"
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink.h"
 #include "third_party/blink/renderer/core/css/style_engine.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element_traversal.h"
diff --git a/third_party/blink/renderer/core/inspector/BUILD.gn b/third_party/blink/renderer/core/inspector/BUILD.gn
index 19432a8..ae8bfda8 100644
--- a/third_party/blink/renderer/core/inspector/BUILD.gn
+++ b/third_party/blink/renderer/core/inspector/BUILD.gn
@@ -77,6 +77,8 @@
     "inspector/protocol/Page.h",
     "inspector/protocol/Performance.cpp",
     "inspector/protocol/Performance.h",
+    "inspector/protocol/PerformanceTimeline.cpp",
+    "inspector/protocol/PerformanceTimeline.h",
     "inspector/protocol/Protocol.cpp",
     "inspector/protocol/Protocol.h",
     "inspector/protocol/Runtime.h",
diff --git a/third_party/blink/renderer/core/inspector/build.gni b/third_party/blink/renderer/core/inspector/build.gni
index a87c36b..a2ffc12 100644
--- a/third_party/blink/renderer/core/inspector/build.gni
+++ b/third_party/blink/renderer/core/inspector/build.gni
@@ -77,6 +77,8 @@
   "inspector_page_agent.h",
   "inspector_performance_agent.cc",
   "inspector_performance_agent.h",
+  "inspector_performance_timeline_agent.cc",
+  "inspector_performance_timeline_agent.h",
   "inspector_resource_container.cc",
   "inspector_resource_container.h",
   "inspector_resource_content_loader.cc",
diff --git a/third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.cc b/third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.cc
new file mode 100644
index 0000000..1ccefd5
--- /dev/null
+++ b/third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.cc
@@ -0,0 +1,177 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.h"
+
+#include <utility>
+
+#include "build/build_config.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/inspector/identifiers_factory.h"
+#include "third_party/blink/renderer/core/inspector/inspected_frames.h"
+#include "third_party/blink/renderer/core/probe/core_probes.h"
+#include "third_party/blink/renderer/core/timing/dom_window_performance.h"
+#include "third_party/blink/renderer/core/timing/largest_contentful_paint.h"
+#include "third_party/blink/renderer/core/timing/worker_global_scope_performance.h"
+
+namespace blink {
+
+namespace {
+
+constexpr PerformanceEntryType kSupportedTypes =
+    PerformanceEntry::EntryType::kLargestContentfulPaint;
+
+std::unique_ptr<protocol::PerformanceTimeline::LargestContentfulPaint>
+BuildEventDetails(LargestContentfulPaint* lcp, DOMHighResTimeStamp timeOrigin) {
+  const double renderTime =
+      lcp->renderTime()
+          ? ConvertDOMHighResTimeStampToSeconds(timeOrigin + lcp->renderTime())
+          : 0;
+  const double loadTime =
+      lcp->loadTime()
+          ? ConvertDOMHighResTimeStampToSeconds(timeOrigin + lcp->loadTime())
+          : 0;
+  auto result = protocol::PerformanceTimeline::LargestContentfulPaint::create()
+                    .setRenderTime(renderTime)
+                    .setLoadTime(loadTime)
+                    .setSize(lcp->size())
+                    .build();
+  if (!lcp->id().IsEmpty())
+    result->setElementId(lcp->id());
+  if (Element* element = lcp->element())
+    result->setNodeId(IdentifiersFactory::IntIdForNode(element));
+  if (!lcp->url().IsEmpty())
+    result->setUrl(lcp->url());
+  return result;
+}
+
+std::unique_ptr<protocol::PerformanceTimeline::TimelineEvent>
+BuildProtocolEvent(String frame_id,
+                   DOMHighResTimeStamp timeOrigin,
+                   PerformanceEntry* entry) {
+  auto result = protocol::PerformanceTimeline::TimelineEvent::create()
+                    .setFrameId(frame_id)
+                    .setType(entry->entryType())
+                    .setName(entry->name())
+                    // TODO(caseq): entry time is clamped; consider exposing an
+                    // unclamped time.
+                    .setTime(ConvertDOMHighResTimeStampToSeconds(
+                        timeOrigin + entry->startTime()))
+                    .build();
+  if (entry->duration())
+    result->setDuration(ConvertDOMHighResTimeStampToSeconds(entry->duration()));
+  if (auto* lcp = DynamicTo<LargestContentfulPaint>(entry))
+    result->setLcpDetails(BuildEventDetails(lcp, timeOrigin));
+  return result;
+}
+
+}  // namespace
+
+using protocol::Response;
+
+InspectorPerformanceTimelineAgent::InspectorPerformanceTimelineAgent(
+    InspectedFrames* inspected_frames)
+    : inspected_frames_(inspected_frames),
+      enabled_types_(&agent_state_, /*default_value=*/false) {}
+
+InspectorPerformanceTimelineAgent::~InspectorPerformanceTimelineAgent() =
+    default;
+
+void InspectorPerformanceTimelineAgent::Trace(Visitor* visitor) const {
+  visitor->Trace(inspected_frames_);
+  InspectorBaseAgent<protocol::PerformanceTimeline::Metainfo>::Trace(visitor);
+}
+
+void InspectorPerformanceTimelineAgent::Restore() {
+  if (IsEnabled())
+    InnerEnable();
+}
+
+void InspectorPerformanceTimelineAgent::InnerEnable() {
+  DCHECK(IsEnabled());
+  instrumenting_agents_->AddInspectorPerformanceTimelineAgent(this);
+}
+
+void InspectorPerformanceTimelineAgent::PerformanceEntryAdded(
+    ExecutionContext* context,
+    PerformanceEntry* entry) {
+  if (!(entry->EntryTypeEnum() & enabled_types_.Get()))
+    return;
+  String frame_id;
+  Performance* performance = nullptr;
+  if (auto* window = DynamicTo<LocalDOMWindow>(context)) {
+    frame_id = IdentifiersFactory::FrameId(window->GetFrame());
+    performance = DOMWindowPerformance::performance(*window);
+  } else if (auto* global_scope = DynamicTo<WorkerGlobalScope>(context)) {
+    performance = WorkerGlobalScopePerformance::performance(*global_scope);
+  } else {
+    NOTREACHED() << "Unexpected subtype of ExecutionContext";
+  }
+  GetFrontend()->timelineEventAdded(
+      BuildProtocolEvent(frame_id, performance->timeOrigin(), entry));
+}
+
+protocol::Response InspectorPerformanceTimelineAgent::enable(
+    std::unique_ptr<protocol::Array<String>> entry_types) {
+  EventsVector buffered_events;
+
+  const int old_types = enabled_types_.Get();
+  PerformanceEntryType new_types = 0;
+  for (const auto& type_str : *entry_types) {
+    AtomicString type_atomic(type_str);
+    PerformanceEntryType type_enum =
+        PerformanceEntry::ToEntryTypeEnum(type_atomic);
+    if (type_enum == PerformanceEntry::EntryType::kInvalid ||
+        (type_enum & kSupportedTypes) != type_enum) {
+      return Response::InvalidParams("Unknown or unsupported entry type");
+    }
+
+    // Gather buffered entries for types that haven't been enabled previously
+    // (but disregard duplicate type specifiers).
+    if (!(old_types & type_enum) && !(new_types & type_enum))
+      CollectEntries(type_atomic, &buffered_events);
+    new_types |= type_enum;
+  }
+  enabled_types_.Set(new_types);
+  if (!old_types != !new_types) {
+    if (!new_types)
+      return disable();
+    InnerEnable();
+  }
+  for (auto& event : buffered_events)
+    GetFrontend()->timelineEventAdded(std::move(event));
+
+  return Response::Success();
+}
+
+protocol::Response InspectorPerformanceTimelineAgent::disable() {
+  enabled_types_.Clear();
+  instrumenting_agents_->RemoveInspectorPerformanceTimelineAgent(this);
+  return Response::Success();
+}
+
+bool InspectorPerformanceTimelineAgent::IsEnabled() const {
+  return !!enabled_types_.Get();
+}
+
+void InspectorPerformanceTimelineAgent::CollectEntries(AtomicString type,
+                                                       EventsVector* events) {
+  for (LocalFrame* frame : *inspected_frames_) {
+    String frame_id = IdentifiersFactory::FrameId(frame);
+    LocalDOMWindow* window = frame->DomWindow();
+    if (!window)
+      continue;
+    WindowPerformance* performance = DOMWindowPerformance::performance(*window);
+    for (Member<PerformanceEntry> entry :
+         performance->getBufferedEntriesByType(type)) {
+      events->push_back(
+          BuildProtocolEvent(frame_id, performance->timeOrigin(), entry));
+    }
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.h b/third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.h
new file mode 100644
index 0000000..94c106d2
--- /dev/null
+++ b/third_party/blink/renderer/core/inspector/inspector_performance_timeline_agent.h
@@ -0,0 +1,55 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INSPECTOR_PERFORMANCE_TIMELINE_AGENT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INSPECTOR_PERFORMANCE_TIMELINE_AGENT_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/task/sequence_manager/task_time_observer.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/inspector/inspector_base_agent.h"
+#include "third_party/blink/renderer/core/inspector/inspector_session_state.h"
+#include "third_party/blink/renderer/core/inspector/protocol/PerformanceTimeline.h"
+
+namespace blink {
+
+class ExecutionContext;
+class InspectedFrames;
+class PerformanceEntry;
+
+class CORE_EXPORT InspectorPerformanceTimelineAgent final
+    : public InspectorBaseAgent<protocol::PerformanceTimeline::Metainfo> {
+ public:
+  explicit InspectorPerformanceTimelineAgent(InspectedFrames*);
+  ~InspectorPerformanceTimelineAgent() override;
+
+  // PerformanceTimeline probes implementation.
+  void PerformanceEntryAdded(ExecutionContext*, PerformanceEntry*);
+
+  void Trace(Visitor*) const override;
+
+ private:
+  // Performance protocol domain implementation.
+  protocol::Response enable(
+      std::unique_ptr<protocol::Array<String>> event_types) override;
+  protocol::Response disable() override;
+  void Restore() override;
+
+  void InnerEnable();
+  bool IsEnabled() const;
+
+  using EventsVector =
+      protocol::Array<protocol::PerformanceTimeline::TimelineEvent>;
+  void CollectEntries(AtomicString type, EventsVector* events);
+
+  Member<InspectedFrames> inspected_frames_;
+  InspectorAgentState::Integer enabled_types_;
+  DISALLOW_COPY_AND_ASSIGN(InspectorPerformanceTimelineAgent);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INSPECTOR_PERFORMANCE_TIMELINE_AGENT_H_
diff --git a/third_party/blink/renderer/core/inspector/inspector_protocol_config.json b/third_party/blink/renderer/core/inspector/inspector_protocol_config.json
index 99fc5eb5..2efe99a3 100644
--- a/third_party/blink/renderer/core/inspector/inspector_protocol_config.json
+++ b/third_party/blink/renderer/core/inspector/inspector_protocol_config.json
@@ -82,6 +82,9 @@
                 "domain": "Performance"
             },
             {
+                "domain": "PerformanceTimeline"
+            },
+            {
                 "domain": "Emulation",
                 "include": ["forceViewport", "resetViewport", "resetPageScaleFactor", "setPageScaleFactor", "setScriptExecutionDisabled", "setTouchEmulationEnabled",
                             "setEmulatedMedia", "setEmulatedVisionDeficiency", "setCPUThrottlingRate", "setVirtualTimePolicy", "setTimezoneOverride", "setNavigatorOverrides", "setDefaultBackgroundColorOverride", "setDeviceMetricsOverride", "clearDeviceMetricsOverride",
diff --git a/third_party/blink/renderer/core/layout/layout_theme.cc b/third_party/blink/renderer/core/layout/layout_theme.cc
index de02277e..6628945 100644
--- a/third_party/blink/renderer/core/layout/layout_theme.cc
+++ b/third_party/blink/renderer/core/layout/layout_theme.cc
@@ -325,50 +325,50 @@
 }
 
 Color LayoutTheme::ActiveSelectionBackgroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   Color color = PlatformActiveSelectionBackgroundColor(color_scheme);
 #if defined(OS_MAC)
   // BlendWithWhite() darkens Mac system colors too much.
   // Apply .8 (204/255) alpha instead, same as Safari.
-  if (color_scheme == mojom::blink::ColorScheme::kDark)
+  if (color_scheme == ColorScheme::kDark)
     return Color(color.Red(), color.Green(), color.Blue(), 204);
 #endif
   return color.BlendWithWhite();
 }
 
 Color LayoutTheme::InactiveSelectionBackgroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return PlatformInactiveSelectionBackgroundColor(color_scheme)
       .BlendWithWhite();
 }
 
 Color LayoutTheme::ActiveSelectionForegroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return PlatformActiveSelectionForegroundColor(color_scheme);
 }
 
 Color LayoutTheme::InactiveSelectionForegroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return PlatformInactiveSelectionForegroundColor(color_scheme);
 }
 
 Color LayoutTheme::ActiveListBoxSelectionBackgroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return PlatformActiveListBoxSelectionBackgroundColor(color_scheme);
 }
 
 Color LayoutTheme::InactiveListBoxSelectionBackgroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return PlatformInactiveListBoxSelectionBackgroundColor(color_scheme);
 }
 
 Color LayoutTheme::ActiveListBoxSelectionForegroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return PlatformActiveListBoxSelectionForegroundColor(color_scheme);
 }
 
 Color LayoutTheme::InactiveListBoxSelectionForegroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return PlatformInactiveListBoxSelectionForegroundColor(color_scheme);
 }
 
@@ -385,47 +385,47 @@
 }
 
 Color LayoutTheme::PlatformActiveSelectionBackgroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   // Use a blue color by default if the platform theme doesn't define anything.
   return Color(0, 0, 255);
 }
 
 Color LayoutTheme::PlatformActiveSelectionForegroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   // Use a white color by default if the platform theme doesn't define anything.
   return Color::kWhite;
 }
 
 Color LayoutTheme::PlatformInactiveSelectionBackgroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   // Use a grey color by default if the platform theme doesn't define anything.
   // This color matches Firefox's inactive color.
   return Color(176, 176, 176);
 }
 
 Color LayoutTheme::PlatformInactiveSelectionForegroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   // Use a black color by default.
   return Color::kBlack;
 }
 
 Color LayoutTheme::PlatformActiveListBoxSelectionBackgroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return PlatformActiveSelectionBackgroundColor(color_scheme);
 }
 
 Color LayoutTheme::PlatformActiveListBoxSelectionForegroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return PlatformActiveSelectionForegroundColor(color_scheme);
 }
 
 Color LayoutTheme::PlatformInactiveListBoxSelectionBackgroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return PlatformInactiveSelectionBackgroundColor(color_scheme);
 }
 
 Color LayoutTheme::PlatformInactiveListBoxSelectionForegroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return PlatformInactiveSelectionForegroundColor(color_scheme);
 }
 
@@ -618,7 +618,7 @@
 }
 
 Color LayoutTheme::SystemColor(CSSValueID css_value_id,
-                               mojom::blink::ColorScheme color_scheme) const {
+                               ColorScheme color_scheme) const {
   switch (css_value_id) {
     case CSSValueID::kActiveborder:
       return 0xFFFFFFFF;
@@ -627,36 +627,29 @@
     case CSSValueID::kActivetext:
       return 0xFFFF0000;
     case CSSValueID::kAppworkspace:
-      return color_scheme == mojom::blink::ColorScheme::kDark ? 0xFF000000
-                                                              : 0xFFFFFFFF;
+      return color_scheme == ColorScheme::kDark ? 0xFF000000 : 0xFFFFFFFF;
     case CSSValueID::kBackground:
       return 0xFF6363CE;
     case CSSValueID::kButtonface:
-      return color_scheme == mojom::blink::ColorScheme::kDark ? 0xFF444444
-                                                              : 0xFFDDDDDD;
+      return color_scheme == ColorScheme::kDark ? 0xFF444444 : 0xFFDDDDDD;
     case CSSValueID::kButtonhighlight:
       return 0xFFDDDDDD;
     case CSSValueID::kButtonshadow:
       return 0xFF888888;
     case CSSValueID::kButtontext:
-      return color_scheme == mojom::blink::ColorScheme::kDark ? 0xFFAAAAAA
-                                                              : 0xFF000000;
+      return color_scheme == ColorScheme::kDark ? 0xFFAAAAAA : 0xFF000000;
     case CSSValueID::kCaptiontext:
-      return color_scheme == mojom::blink::ColorScheme::kDark ? 0xFFFFFFFF
-                                                              : 0xFF000000;
+      return color_scheme == ColorScheme::kDark ? 0xFFFFFFFF : 0xFF000000;
     case CSSValueID::kField:
-      return color_scheme == mojom::blink::ColorScheme::kDark ? 0xFF000000
-                                                              : 0xFFFFFFFF;
+      return color_scheme == ColorScheme::kDark ? 0xFF000000 : 0xFFFFFFFF;
     case CSSValueID::kFieldtext:
-      return color_scheme == mojom::blink::ColorScheme::kDark ? 0xFFFFFFFF
-                                                              : 0xFF000000;
+      return color_scheme == ColorScheme::kDark ? 0xFFFFFFFF : 0xFF000000;
     case CSSValueID::kGraytext:
       return 0xFF808080;
     case CSSValueID::kHighlight:
       return 0xFFB5D5FF;
     case CSSValueID::kHighlighttext:
-      return color_scheme == mojom::blink::ColorScheme::kDark ? 0xFFFFFFFF
-                                                              : 0xFF000000;
+      return color_scheme == ColorScheme::kDark ? 0xFFFFFFFF : 0xFF000000;
     case CSSValueID::kInactiveborder:
       return 0xFFFFFFFF;
     case CSSValueID::kInactivecaption:
@@ -664,24 +657,19 @@
     case CSSValueID::kInactivecaptiontext:
       return 0xFF7F7F7F;
     case CSSValueID::kInfobackground:
-      return color_scheme == mojom::blink::ColorScheme::kDark ? 0xFFB46E32
-                                                              : 0xFFFBFCC5;
+      return color_scheme == ColorScheme::kDark ? 0xFFB46E32 : 0xFFFBFCC5;
     case CSSValueID::kInfotext:
-      return color_scheme == mojom::blink::ColorScheme::kDark ? 0xFFFFFFFF
-                                                              : 0xFF000000;
+      return color_scheme == ColorScheme::kDark ? 0xFFFFFFFF : 0xFF000000;
     case CSSValueID::kLinktext:
       return 0xFF0000EE;
     case CSSValueID::kMenu:
-      return color_scheme == mojom::blink::ColorScheme::kDark ? 0xFF404040
-                                                              : 0xFFF7F7F7;
+      return color_scheme == ColorScheme::kDark ? 0xFF404040 : 0xFFF7F7F7;
     case CSSValueID::kMenutext:
-      return color_scheme == mojom::blink::ColorScheme::kDark ? 0xFFFFFFFF
-                                                              : 0xFF000000;
+      return color_scheme == ColorScheme::kDark ? 0xFFFFFFFF : 0xFF000000;
     case CSSValueID::kScrollbar:
       return 0xFFFFFFFF;
     case CSSValueID::kText:
-      return color_scheme == mojom::blink::ColorScheme::kDark ? 0xFFFFFFFF
-                                                              : 0xFF000000;
+      return color_scheme == ColorScheme::kDark ? 0xFFFFFFFF : 0xFF000000;
     case CSSValueID::kThreeddarkshadow:
       return 0xFF666666;
     case CSSValueID::kThreedface:
@@ -696,14 +684,12 @@
       return 0xFF551A8B;
     case CSSValueID::kWindow:
     case CSSValueID::kCanvas:
-      return color_scheme == mojom::blink::ColorScheme::kDark ? 0xFF000000
-                                                              : 0xFFFFFFFF;
+      return color_scheme == ColorScheme::kDark ? 0xFF000000 : 0xFFFFFFFF;
     case CSSValueID::kWindowframe:
       return 0xFFCCCCCC;
     case CSSValueID::kWindowtext:
     case CSSValueID::kCanvastext:
-      return color_scheme == mojom::blink::ColorScheme::kDark ? 0xFFFFFFFF
-                                                              : 0xFF000000;
+      return color_scheme == ColorScheme::kDark ? 0xFFFFFFFF : 0xFF000000;
     case CSSValueID::kInternalActiveListBoxSelection:
       return ActiveListBoxSelectionBackgroundColor(color_scheme);
     case CSSValueID::kInternalActiveListBoxSelectionText:
@@ -722,7 +708,7 @@
 Color LayoutTheme::PlatformTextSearchHighlightColor(
     bool active_match,
     bool in_forced_colors_mode,
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   if (active_match) {
     if (in_forced_colors_mode)
       return GetTheme().SystemColor(CSSValueID::kHighlight, color_scheme);
@@ -731,10 +717,9 @@
   return Color(255, 255, 0);     // Yellow.
 }
 
-Color LayoutTheme::PlatformTextSearchColor(
-    bool active_match,
-    bool in_forced_colors_mode,
-    mojom::blink::ColorScheme color_scheme) const {
+Color LayoutTheme::PlatformTextSearchColor(bool active_match,
+                                           bool in_forced_colors_mode,
+                                           ColorScheme color_scheme) const {
   if (in_forced_colors_mode && active_match)
     return GetTheme().SystemColor(CSSValueID::kHighlighttext, color_scheme);
   return Color::kBlack;
diff --git a/third_party/blink/renderer/core/layout/layout_theme.h b/third_party/blink/renderer/core/layout/layout_theme.h
index 927f9f0..e6d9e20 100644
--- a/third_party/blink/renderer/core/layout/layout_theme.h
+++ b/third_party/blink/renderer/core/layout/layout_theme.h
@@ -23,7 +23,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_THEME_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_THEME_H_
 
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink-forward.h"
+#include "third_party/blink/public/common/css/color_scheme.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css_value_keywords.h"
 #include "third_party/blink/renderer/core/scroll/scroll_types.h"
@@ -91,28 +91,20 @@
   virtual bool SupportsCalendarPicker(const AtomicString&) const;
 
   // Text selection colors.
-  Color ActiveSelectionBackgroundColor(
-      mojom::blink::ColorScheme color_scheme) const;
-  Color InactiveSelectionBackgroundColor(
-      mojom::blink::ColorScheme color_scheme) const;
-  Color ActiveSelectionForegroundColor(
-      mojom::blink::ColorScheme color_scheme) const;
-  Color InactiveSelectionForegroundColor(
-      mojom::blink::ColorScheme color_scheme) const;
+  Color ActiveSelectionBackgroundColor(ColorScheme color_scheme) const;
+  Color InactiveSelectionBackgroundColor(ColorScheme color_scheme) const;
+  Color ActiveSelectionForegroundColor(ColorScheme color_scheme) const;
+  Color InactiveSelectionForegroundColor(ColorScheme color_scheme) const;
   virtual void SetSelectionColors(Color active_background_color,
                                   Color active_foreground_color,
                                   Color inactive_background_color,
                                   Color inactive_foreground_color) {}
 
   // List box selection colors
-  Color ActiveListBoxSelectionBackgroundColor(
-      mojom::blink::ColorScheme color_scheme) const;
-  Color ActiveListBoxSelectionForegroundColor(
-      mojom::blink::ColorScheme color_scheme) const;
-  Color InactiveListBoxSelectionBackgroundColor(
-      mojom::blink::ColorScheme color_scheme) const;
-  Color InactiveListBoxSelectionForegroundColor(
-      mojom::blink::ColorScheme color_scheme) const;
+  Color ActiveListBoxSelectionBackgroundColor(ColorScheme color_scheme) const;
+  Color ActiveListBoxSelectionForegroundColor(ColorScheme color_scheme) const;
+  Color InactiveListBoxSelectionBackgroundColor(ColorScheme color_scheme) const;
+  Color InactiveListBoxSelectionForegroundColor(ColorScheme color_scheme) const;
 
   virtual Color PlatformSpellingMarkerUnderlineColor() const;
   virtual Color PlatformGrammarMarkerUnderlineColor() const;
@@ -120,13 +112,12 @@
   Color PlatformActiveSpellingMarkerHighlightColor() const;
 
   // Highlight and text colors for TextMatches.
-  Color PlatformTextSearchHighlightColor(
-      bool active_match,
-      bool in_forced_colors_mode,
-      mojom::blink::ColorScheme color_scheme) const;
+  Color PlatformTextSearchHighlightColor(bool active_match,
+                                         bool in_forced_colors_mode,
+                                         ColorScheme color_scheme) const;
   Color PlatformTextSearchColor(bool active_match,
                                 bool in_forced_colors_mode,
-                                mojom::blink::ColorScheme color_scheme) const;
+                                ColorScheme color_scheme) const;
 
   virtual Color FocusRingColor() const;
   virtual Color PlatformFocusRingColor() const { return Color(0, 0, 0); }
@@ -147,8 +138,7 @@
 
   // System fonts and colors for CSS.
   void SystemFont(CSSValueID system_font_id, FontDescription&);
-  virtual Color SystemColor(CSSValueID,
-                            mojom::blink::ColorScheme color_scheme) const;
+  virtual Color SystemColor(CSSValueID, ColorScheme color_scheme) const;
 
   virtual void AdjustSliderThumbSize(ComputedStyle&) const;
 
@@ -188,22 +178,22 @@
  protected:
   // The platform selection color.
   virtual Color PlatformActiveSelectionBackgroundColor(
-      mojom::blink::ColorScheme color_scheme) const;
+      ColorScheme color_scheme) const;
   virtual Color PlatformInactiveSelectionBackgroundColor(
-      mojom::blink::ColorScheme color_scheme) const;
+      ColorScheme color_scheme) const;
   virtual Color PlatformActiveSelectionForegroundColor(
-      mojom::blink::ColorScheme color_scheme) const;
+      ColorScheme color_scheme) const;
   virtual Color PlatformInactiveSelectionForegroundColor(
-      mojom::blink::ColorScheme color_scheme) const;
+      ColorScheme color_scheme) const;
 
   virtual Color PlatformActiveListBoxSelectionBackgroundColor(
-      mojom::blink::ColorScheme color_scheme) const;
+      ColorScheme color_scheme) const;
   virtual Color PlatformInactiveListBoxSelectionBackgroundColor(
-      mojom::blink::ColorScheme color_scheme) const;
+      ColorScheme color_scheme) const;
   virtual Color PlatformActiveListBoxSelectionForegroundColor(
-      mojom::blink::ColorScheme color_scheme) const;
+      ColorScheme color_scheme) const;
   virtual Color PlatformInactiveListBoxSelectionForegroundColor(
-      mojom::blink::ColorScheme color_scheme) const;
+      ColorScheme color_scheme) const;
 
   // Methods for each appearance value.
   virtual void AdjustCheckboxStyle(ComputedStyle&) const;
diff --git a/third_party/blink/renderer/core/layout/layout_theme_default.cc b/third_party/blink/renderer/core/layout/layout_theme_default.cc
index 4f4845e..ee082c7f 100644
--- a/third_party/blink/renderer/core/layout/layout_theme_default.cc
+++ b/third_party/blink/renderer/core/layout/layout_theme_default.cc
@@ -86,22 +86,22 @@
 }
 
 Color LayoutThemeDefault::PlatformActiveSelectionBackgroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return active_selection_background_color_;
 }
 
 Color LayoutThemeDefault::PlatformInactiveSelectionBackgroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return inactive_selection_background_color_;
 }
 
 Color LayoutThemeDefault::PlatformActiveSelectionForegroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return active_selection_foreground_color_;
 }
 
 Color LayoutThemeDefault::PlatformInactiveSelectionForegroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return inactive_selection_foreground_color_;
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_theme_default.h b/third_party/blink/renderer/core/layout/layout_theme_default.h
index f249604c..3111958 100644
--- a/third_party/blink/renderer/core/layout/layout_theme_default.h
+++ b/third_party/blink/renderer/core/layout/layout_theme_default.h
@@ -41,13 +41,13 @@
   String ExtraQuirksStyleSheet() override;
 
   Color PlatformActiveSelectionBackgroundColor(
-      mojom::blink::ColorScheme color_scheme) const override;
+      ColorScheme color_scheme) const override;
   Color PlatformInactiveSelectionBackgroundColor(
-      mojom::blink::ColorScheme color_scheme) const override;
+      ColorScheme color_scheme) const override;
   Color PlatformActiveSelectionForegroundColor(
-      mojom::blink::ColorScheme color_scheme) const override;
+      ColorScheme color_scheme) const override;
   Color PlatformInactiveSelectionForegroundColor(
-      mojom::blink::ColorScheme color_scheme) const override;
+      ColorScheme color_scheme) const override;
 
   IntSize SliderTickSize() const override;
   int SliderTickOffsetFromTrackCenter() const override;
diff --git a/third_party/blink/renderer/core/layout/layout_theme_mac.h b/third_party/blink/renderer/core/layout/layout_theme_mac.h
index 61bbb5c..9e3d799 100644
--- a/third_party/blink/renderer/core/layout/layout_theme_mac.h
+++ b/third_party/blink/renderer/core/layout/layout_theme_mac.h
@@ -38,11 +38,11 @@
   }
 
   Color PlatformActiveSelectionBackgroundColor(
-      mojom::blink::ColorScheme color_scheme) const override;
+      ColorScheme color_scheme) const override;
   Color PlatformInactiveSelectionBackgroundColor(
-      mojom::blink::ColorScheme color_scheme) const override;
+      ColorScheme color_scheme) const override;
   Color PlatformActiveSelectionForegroundColor(
-      mojom::blink::ColorScheme color_scheme) const override;
+      ColorScheme color_scheme) const override;
   Color PlatformSpellingMarkerUnderlineColor() const override;
   Color PlatformGrammarMarkerUnderlineColor() const override;
   Color FocusRingColor() const override;
@@ -54,7 +54,7 @@
  protected:
   // Controls color values returned from FocusRingColor().
   bool UsesTestModeFocusRingColor() const;
-  bool IsAccentColorCustomized(mojom::blink::ColorScheme color_scheme) const;
+  bool IsAccentColorCustomized(ColorScheme color_scheme) const;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_theme_mac.mm b/third_party/blink/renderer/core/layout/layout_theme_mac.mm
index 748da2b..6fd8ee5d 100644
--- a/third_party/blink/renderer/core/layout/layout_theme_mac.mm
+++ b/third_party/blink/renderer/core/layout/layout_theme_mac.mm
@@ -34,8 +34,7 @@
 namespace blink {
 
 namespace {
-Color GetSystemColor(MacSystemColorID color_id,
-                     mojom::blink::ColorScheme color_scheme) {
+Color GetSystemColor(MacSystemColorID color_id, ColorScheme color_scheme) {
   // In tests, a WebSandboxSupport may not be set up. Just return a dummy
   // color, in this case, black.
   auto* sandbox_support = Platform::Current()->GetSandboxSupport();
@@ -52,19 +51,19 @@
 }
 
 Color LayoutThemeMac::PlatformActiveSelectionBackgroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return GetSystemColor(MacSystemColorID::kSelectedTextBackground,
                         color_scheme);
 }
 
 Color LayoutThemeMac::PlatformInactiveSelectionBackgroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return GetSystemColor(MacSystemColorID::kSecondarySelectedControl,
                         color_scheme);
 }
 
 Color LayoutThemeMac::PlatformActiveSelectionForegroundColor(
-    mojom::blink::ColorScheme color_scheme) const {
+    ColorScheme color_scheme) const {
   return Color::kBlack;
 }
 
@@ -76,8 +75,7 @@
   return Color(107, 107, 107);
 }
 
-bool LayoutThemeMac::IsAccentColorCustomized(
-    mojom::blink::ColorScheme color_scheme) const {
+bool LayoutThemeMac::IsAccentColorCustomized(ColorScheme color_scheme) const {
   if (@available(macOS 10.14, *)) {
     static const Color kControlBlueAccentColor =
         GetSystemColor(MacSystemColorID::kControlAccentBlueColor, color_scheme);
@@ -109,8 +107,7 @@
   }
 
   // TODO(crbug.com/929098) Need to pass an appropriate color scheme here.
-  mojom::blink::ColorScheme color_scheme =
-      ComputedStyle::InitialStyle().UsedColorScheme();
+  ColorScheme color_scheme = ComputedStyle::InitialStyle().UsedColorScheme();
 
   SkColor keyboard_focus_indicator = SkColor(
       GetSystemColor(MacSystemColorID::kKeyboardFocusIndicator, color_scheme));
diff --git a/third_party/blink/renderer/core/layout/layout_theme_mobile.h b/third_party/blink/renderer/core/layout/layout_theme_mobile.h
index 09ee09d..185be962 100644
--- a/third_party/blink/renderer/core/layout/layout_theme_mobile.h
+++ b/third_party/blink/renderer/core/layout/layout_theme_mobile.h
@@ -44,7 +44,7 @@
   }
 
   Color PlatformActiveSelectionBackgroundColor(
-      mojom::blink::ColorScheme color_scheme) const override {
+      ColorScheme color_scheme) const override {
     return LayoutThemeMobile::kDefaultActiveSelectionBackgroundColor;
   }
 
diff --git a/third_party/blink/renderer/core/layout/layout_theme_test.cc b/third_party/blink/renderer/core/layout/layout_theme_test.cc
index 10d1803..76d7557 100644
--- a/third_party/blink/renderer/core/layout/layout_theme_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_theme_test.cc
@@ -95,7 +95,7 @@
   ASSERT_TRUE(dark_element);
 
   const ComputedStyle* style = dark_element->GetComputedStyle();
-  EXPECT_EQ(mojom::blink::ColorScheme::kLight, style->UsedColorScheme());
+  EXPECT_EQ(ColorScheme::kLight, style->UsedColorScheme());
   EXPECT_EQ(Color(0xdd, 0xdd, 0xdd),
             style->VisitedDependentColor(GetCSSPropertyColor()));
 
@@ -106,7 +106,7 @@
   UpdateAllLifecyclePhasesForTest();
 
   style = dark_element->GetComputedStyle();
-  EXPECT_EQ(mojom::blink::ColorScheme::kDark, style->UsedColorScheme());
+  EXPECT_EQ(ColorScheme::kDark, style->UsedColorScheme());
   EXPECT_EQ(Color(0x44, 0x44, 0x44),
             style->VisitedDependentColor(GetCSSPropertyColor()));
 }
@@ -116,7 +116,7 @@
                                              Color::kBlack, Color::kBlack);
   EXPECT_EQ(Color::kBlack,
             LayoutTheme::GetTheme().ActiveSelectionForegroundColor(
-                mojom::blink::ColorScheme::kLight));
+                ColorScheme::kLight));
   {
     // Enabling MobileLayoutTheme switches which instance is returned from
     // LayoutTheme::GetTheme(). Devtools expect SetSelectionColors() to affect
@@ -124,17 +124,17 @@
     ScopedMobileLayoutThemeForTest scope(true);
     EXPECT_EQ(Color::kBlack,
               LayoutTheme::GetTheme().ActiveSelectionForegroundColor(
-                  mojom::blink::ColorScheme::kLight));
+                  ColorScheme::kLight));
 
     LayoutTheme::GetTheme().SetSelectionColors(Color::kWhite, Color::kWhite,
                                                Color::kWhite, Color::kWhite);
     EXPECT_EQ(Color::kWhite,
               LayoutTheme::GetTheme().ActiveSelectionForegroundColor(
-                  mojom::blink::ColorScheme::kLight));
+                  ColorScheme::kLight));
   }
   EXPECT_EQ(Color::kWhite,
             LayoutTheme::GetTheme().ActiveSelectionForegroundColor(
-                mojom::blink::ColorScheme::kLight));
+                ColorScheme::kLight));
 }
 #endif  // !defined(OS_MAC)
 
diff --git a/third_party/blink/renderer/core/layout/layout_theme_win.cc b/third_party/blink/renderer/core/layout/layout_theme_win.cc
index 6db48d7..7c23535 100644
--- a/third_party/blink/renderer/core/layout/layout_theme_win.cc
+++ b/third_party/blink/renderer/core/layout/layout_theme_win.cc
@@ -21,9 +21,8 @@
   return *layout_theme;
 }
 
-Color LayoutThemeWin::SystemColor(
-    CSSValueID css_value_id,
-    mojom::blink::ColorScheme color_scheme) const {
+Color LayoutThemeWin::SystemColor(CSSValueID css_value_id,
+                                  ColorScheme color_scheme) const {
   blink::WebThemeEngine::SystemThemeColor theme_color;
   switch (css_value_id) {
     case CSSValueID::kActivetext:
diff --git a/third_party/blink/renderer/core/layout/layout_theme_win.h b/third_party/blink/renderer/core/layout/layout_theme_win.h
index 20ff279..97c897a 100644
--- a/third_party/blink/renderer/core/layout/layout_theme_win.h
+++ b/third_party/blink/renderer/core/layout/layout_theme_win.h
@@ -14,7 +14,7 @@
   static scoped_refptr<LayoutTheme> Create();
 
   Color SystemColor(CSSValueID css_value_id,
-                    mojom::blink::ColorScheme color_scheme) const override;
+                    ColorScheme color_scheme) const override;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/scrollbars_test.cc b/third_party/blink/renderer/core/layout/scrollbars_test.cc
index c802f8e..028a8c4 100644
--- a/third_party/blink/renderer/core/layout/scrollbars_test.cc
+++ b/third_party/blink/renderer/core/layout/scrollbars_test.cc
@@ -38,9 +38,7 @@
 
 class StubWebThemeEngine : public WebThemeEngine {
  public:
-  StubWebThemeEngine() {
-    painted_color_scheme_.fill(mojom::blink::ColorScheme::kLight);
-  }
+  StubWebThemeEngine() { painted_color_scheme_.fill(ColorScheme::kLight); }
 
   gfx::Size GetSize(Part part) override {
     switch (part) {
@@ -67,19 +65,18 @@
              State,
              const gfx::Rect&,
              const ExtraParams*,
-             mojom::blink::ColorScheme color_scheme) override {
+             blink::ColorScheme color_scheme) override {
     // Make  sure we don't overflow the array.
     DCHECK(part <= kPartProgressBar);
     painted_color_scheme_[part] = color_scheme;
   }
 
-  mojom::blink::ColorScheme GetPaintedPartColorScheme(Part part) const {
+  ColorScheme GetPaintedPartColorScheme(Part part) const {
     return painted_color_scheme_[part];
   }
 
  private:
-  std::array<mojom::blink::ColorScheme, kPartProgressBar + 1>
-      painted_color_scheme_;
+  std::array<ColorScheme, kPartProgressBar + 1> painted_color_scheme_;
 };
 
 constexpr int StubWebThemeEngine::kMinimumHorizontalLength;
@@ -3015,15 +3012,14 @@
 
   auto* theme_engine =
       static_cast<StubWebThemeEngine*>(Platform::Current()->ThemeEngine());
-  EXPECT_EQ(mojom::blink::ColorScheme::kDark,
+  EXPECT_EQ(ColorScheme::kDark,
             theme_engine->GetPaintedPartColorScheme(
                 WebThemeEngine::kPartScrollbarHorizontalThumb));
-  EXPECT_EQ(mojom::blink::ColorScheme::kDark,
+  EXPECT_EQ(ColorScheme::kDark,
             theme_engine->GetPaintedPartColorScheme(
                 WebThemeEngine::kPartScrollbarVerticalThumb));
-  EXPECT_EQ(mojom::blink::ColorScheme::kDark,
-            theme_engine->GetPaintedPartColorScheme(
-                WebThemeEngine::kPartScrollbarCorner));
+  EXPECT_EQ(ColorScheme::kDark, theme_engine->GetPaintedPartColorScheme(
+                                    WebThemeEngine::kPartScrollbarCorner));
 }
 
 // Test scrollbar-gutter values with classic scrollbars and horizontal-tb text.
diff --git a/third_party/blink/renderer/core/paint/custom_scrollbar_theme.cc b/third_party/blink/renderer/core/paint/custom_scrollbar_theme.cc
index bf189b3d..cbec2f6 100644
--- a/third_party/blink/renderer/core/paint/custom_scrollbar_theme.cc
+++ b/third_party/blink/renderer/core/paint/custom_scrollbar_theme.cc
@@ -135,7 +135,7 @@
     const Scrollbar* vertical_scrollbar,
     const DisplayItemClient& display_item_client,
     const IntRect& corner_rect,
-    mojom::blink::ColorScheme color_scheme) {
+    ColorScheme color_scheme) {
   if (DrawingRecorder::UseCachedDrawingIfPossible(context, display_item_client,
                                                   DisplayItem::kScrollCorner))
     return;
diff --git a/third_party/blink/renderer/core/paint/custom_scrollbar_theme.h b/third_party/blink/renderer/core/paint/custom_scrollbar_theme.h
index ec8a9ec3..43cacd9 100644
--- a/third_party/blink/renderer/core/paint/custom_scrollbar_theme.h
+++ b/third_party/blink/renderer/core/paint/custom_scrollbar_theme.h
@@ -50,7 +50,7 @@
                          const Scrollbar* vertical_scrollbar,
                          const DisplayItemClient&,
                          const IntRect& corner_rect,
-                         mojom::blink::ColorScheme color_scheme) override;
+                         ColorScheme color_scheme) override;
 
   bool ShouldCenterOnThumb(const Scrollbar& scrollbar,
                            const WebMouseEvent& event) override {
diff --git a/third_party/blink/renderer/core/paint/highlight_painting_utils.cc b/third_party/blink/renderer/core/paint/highlight_painting_utils.cc
index ed8594f..5804267 100644
--- a/third_party/blink/renderer/core/paint/highlight_painting_utils.cc
+++ b/third_party/blink/renderer/core/paint/highlight_painting_utils.cc
@@ -35,7 +35,7 @@
 }
 
 Color ForcedSystemForegroundColor(PseudoId pseudo_id,
-                                  mojom::blink::ColorScheme color_scheme) {
+                                  ColorScheme color_scheme) {
   CSSValueID keyword = CSSValueID::kHighlighttext;
   switch (pseudo_id) {
     case kPseudoIdTargetText:
@@ -53,7 +53,7 @@
 }
 
 Color ForcedSystemBackgroundColor(PseudoId pseudo_id,
-                                  mojom::blink::ColorScheme color_scheme) {
+                                  ColorScheme color_scheme) {
   CSSValueID keyword = CSSValueID::kHighlight;
   switch (pseudo_id) {
     case kPseudoIdTargetText:
@@ -174,7 +174,7 @@
   scoped_refptr<const ComputedStyle> pseudo_style =
       HighlightPseudoStyle(node, pseudo);
 
-  mojom::blink::ColorScheme color_scheme = style.UsedColorScheme();
+  ColorScheme color_scheme = style.UsedColorScheme();
   if (pseudo_style) {
     if (!document.InForcedColorsMode() ||
         pseudo_style->ForcedColorAdjust() == EForcedColorAdjust::kNone) {
@@ -200,7 +200,7 @@
       return Color::kTransparent;
   }
 
-  mojom::blink::ColorScheme color_scheme = style.UsedColorScheme();
+  ColorScheme color_scheme = style.UsedColorScheme();
   if (scoped_refptr<const ComputedStyle> pseudo_style =
           HighlightPseudoStyle(node, pseudo)) {
     if (!document.InForcedColorsMode() ||
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index 21236ef..a93098f5 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -1249,7 +1249,7 @@
   return GetLayoutBox()->StyleRef().GetScrollBehavior();
 }
 
-mojom::blink::ColorScheme PaintLayerScrollableArea::UsedColorScheme() const {
+ColorScheme PaintLayerScrollableArea::UsedColorScheme() const {
   return GetLayoutBox()->StyleRef().UsedColorScheme();
 }
 
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
index 6fad682f..a7a2903 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
@@ -350,7 +350,7 @@
   bool ShouldPlaceVerticalScrollbarOnLeft() const override;
   int PageStep(ScrollbarOrientation) const override;
   mojom::blink::ScrollBehavior ScrollBehaviorStyle() const override;
-  mojom::blink::ColorScheme UsedColorScheme() const override;
+  ColorScheme UsedColorScheme() const override;
   cc::AnimationHost* GetCompositorAnimationHost() const override;
   CompositorAnimationTimeline* GetCompositorAnimationTimeline() const override;
   bool HasTickmarks() const override;
diff --git a/third_party/blink/renderer/core/paint/text_paint_style.h b/third_party/blink/renderer/core/paint/text_paint_style.h
index 0ad9c1e..515c9c3 100644
--- a/third_party/blink/renderer/core/paint/text_paint_style.h
+++ b/third_party/blink/renderer/core/paint/text_paint_style.h
@@ -5,7 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_TEXT_PAINT_STYLE_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_TEXT_PAINT_STYLE_H_
 
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink-forward.h"
+#include "third_party/blink/public/common/css/color_scheme.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/style/applied_text_decoration.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
@@ -24,7 +24,7 @@
   Color stroke_color;
   Color emphasis_mark_color;
   float stroke_width;
-  mojom::blink::ColorScheme color_scheme;
+  ColorScheme color_scheme;
   const ShadowList* shadow;
   base::Optional<AppliedTextDecoration> selection_text_decoration;
 
diff --git a/third_party/blink/renderer/core/paint/theme_painter_default.cc b/third_party/blink/renderer/core/paint/theme_painter_default.cc
index f982084..3dbb624 100644
--- a/third_party/blink/renderer/core/paint/theme_painter_default.cc
+++ b/third_party/blink/renderer/core/paint/theme_painter_default.cc
@@ -523,8 +523,7 @@
       cancel_button_size, cancel_button_size);
   IntRect painting_rect = ConvertToPaintingRect(
       input_layout_box, cancel_button_object, cancel_button_rect, r);
-  mojom::blink::ColorScheme color_scheme =
-      cancel_button_object.StyleRef().UsedColorScheme();
+  ColorScheme color_scheme = cancel_button_object.StyleRef().UsedColorScheme();
   DEFINE_STATIC_REF(Image, cancel_image,
                     (Image::LoadPlatformResource(IDR_SEARCH_CANCEL)));
   DEFINE_STATIC_REF(Image, cancel_pressed_image,
@@ -559,14 +558,12 @@
             text_is_dark ? cancel_pressed_image_hc_light_mode
                          : cancel_pressed_image_dark_mode;
   } else {
-    color_scheme_adjusted_cancel_image =
-        color_scheme == mojom::blink::ColorScheme::kLight
-            ? cancel_image
-            : cancel_image_dark_mode;
+    color_scheme_adjusted_cancel_image = color_scheme == ColorScheme::kLight
+                                             ? cancel_image
+                                             : cancel_image_dark_mode;
     color_scheme_adjusted_cancel_pressed_image =
-        color_scheme == mojom::blink::ColorScheme::kLight
-            ? cancel_pressed_image
-            : cancel_pressed_image_dark_mode;
+        color_scheme == ColorScheme::kLight ? cancel_pressed_image
+                                            : cancel_pressed_image_dark_mode;
   }
   paint_info.context.DrawImage(
       To<Element>(cancel_button_object.GetNode())->IsActive()
diff --git a/third_party/blink/renderer/core/probe/core_probes.json5 b/third_party/blink/renderer/core/probe/core_probes.json5
index 12c6e887..5d753dc1 100644
--- a/third_party/blink/renderer/core/probe/core_probes.json5
+++ b/third_party/blink/renderer/core/probe/core_probes.json5
@@ -236,6 +236,11 @@
         "DidFinishDebuggerTask",
       ]
     },
+    InspectorPerformanceTimelineAgent: {
+      probes: [
+        "PerformanceEntryAdded",
+      ]
+    },
     InspectorTraceEvents: {
       probes: [
         "CallFunction",
diff --git a/third_party/blink/renderer/core/probe/core_probes.pidl b/third_party/blink/renderer/core/probe/core_probes.pidl
index 9079833..bbec0cf4 100644
--- a/third_party/blink/renderer/core/probe/core_probes.pidl
+++ b/third_party/blink/renderer/core/probe/core_probes.pidl
@@ -61,6 +61,7 @@
   class XMLHttpRequest;
   class HTMLInputElement;
   class HTMLPortalElement;
+  class PerformanceEntry;
 
   void DidClearDocumentOfWindowObject([Keep] LocalFrame*);
   void WillInsertDOMNode([Keep] Node* parent);
@@ -189,4 +190,5 @@
   void GetDisabledImageTypes(ExecutionContext*, HashSet<String>* result);
   void OnContentSecurityPolicyViolation(ExecutionContext* context, const blink::ContentSecurityPolicy::ContentSecurityPolicyViolationType violationType);
   void IsCacheDisabled(ExecutionContext*, bool* is_cache_disabled);
+  void PerformanceEntryAdded([Keep] ExecutionContext*, PerformanceEntry*);
 }
diff --git a/third_party/blink/renderer/core/scroll/scroll_animator_test.cc b/third_party/blink/renderer/core/scroll/scroll_animator_test.cc
index 8bd5f668..e5dbd2b6 100644
--- a/third_party/blink/renderer/core/scroll/scroll_animator_test.cc
+++ b/third_party/blink/renderer/core/scroll/scroll_animator_test.cc
@@ -81,7 +81,7 @@
   MOCK_CONST_METHOD0(ScrollbarsCanBeActive, bool());
   MOCK_METHOD0(RegisterForAnimation, void());
   MOCK_METHOD0(ScheduleAnimation, bool());
-  MOCK_CONST_METHOD0(UsedColorScheme, mojom::blink::ColorScheme());
+  MOCK_CONST_METHOD0(UsedColorScheme, ColorScheme());
 
   bool UserInputScrollable(ScrollbarOrientation) const override { return true; }
   bool ShouldPlaceVerticalScrollbarOnLeft() const override { return false; }
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.h b/third_party/blink/renderer/core/scroll/scrollable_area.h
index c15845a..9f81f06 100644
--- a/third_party/blink/renderer/core/scroll/scrollable_area.h
+++ b/third_party/blink/renderer/core/scroll/scrollable_area.h
@@ -28,7 +28,7 @@
 
 #include "base/callback_helpers.h"
 #include "cc/input/scroll_snap_data.h"
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink-forward.h"
+#include "third_party/blink/public/common/css/color_scheme.h"
 #include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink-forward.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
@@ -471,7 +471,7 @@
     return mojom::blink::ScrollBehavior::kInstant;
   }
 
-  virtual mojom::blink::ColorScheme UsedColorScheme() const = 0;
+  virtual ColorScheme UsedColorScheme() const = 0;
 
   // Subtracts space occupied by this ScrollableArea's scrollbars.
   // Does nothing if overlay scrollbars are enabled.
diff --git a/third_party/blink/renderer/core/scroll/scrollbar.cc b/third_party/blink/renderer/core/scroll/scrollbar.cc
index 6dad36bd..3e7beab 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar.cc
+++ b/third_party/blink/renderer/core/scroll/scrollbar.cc
@@ -833,7 +833,7 @@
   return false;
 }
 
-mojom::blink::ColorScheme Scrollbar::UsedColorScheme() const {
+ColorScheme Scrollbar::UsedColorScheme() const {
   return scrollable_area_->UsedColorScheme();
 }
 
diff --git a/third_party/blink/renderer/core/scroll/scrollbar.h b/third_party/blink/renderer/core/scroll/scrollbar.h
index 71d8652..d4b4dcd 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar.h
+++ b/third_party/blink/renderer/core/scroll/scrollbar.h
@@ -26,7 +26,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SCROLL_SCROLLBAR_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_SCROLL_SCROLLBAR_H_
 
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink-forward.h"
+#include "third_party/blink/public/common/css/color_scheme.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/scroll/scroll_types.h"
 #include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
@@ -199,7 +199,7 @@
   // is the element that owns our PaintLayerScrollableArea.
   Element* StyleSource() const { return style_source_.Get(); }
 
-  mojom::blink::ColorScheme UsedColorScheme() const;
+  ColorScheme UsedColorScheme() const;
 
   virtual void Trace(Visitor*) const;
 
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_test_suite.h b/third_party/blink/renderer/core/scroll/scrollbar_test_suite.h
index e162dcc..4e163575 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_test_suite.h
+++ b/third_party/blink/renderer/core/scroll/scrollbar_test_suite.h
@@ -71,7 +71,7 @@
   MOCK_CONST_METHOD0(VerticalScrollbar, Scrollbar*());
   MOCK_CONST_METHOD0(ScrollbarsHiddenIfOverlay, bool());
   MOCK_METHOD0(ScheduleAnimation, bool());
-  MOCK_CONST_METHOD0(UsedColorScheme, mojom::blink::ColorScheme());
+  MOCK_CONST_METHOD0(UsedColorScheme, ColorScheme());
 
   bool UserInputScrollable(ScrollbarOrientation) const override { return true; }
   bool ScrollbarsCanBeActive() const override { return true; }
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme.cc b/third_party/blink/renderer/core/scroll/scrollbar_theme.cc
index 311edef..fdd88700 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_theme.cc
+++ b/third_party/blink/renderer/core/scroll/scrollbar_theme.cc
@@ -108,7 +108,7 @@
     const Scrollbar* vertical_scrollbar,
     const DisplayItemClient& display_item_client,
     const IntRect& corner_rect,
-    mojom::blink::ColorScheme color_scheme) {
+    ColorScheme color_scheme) {
   if (corner_rect.IsEmpty())
     return;
 
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme.h b/third_party/blink/renderer/core/scroll/scrollbar_theme.h
index 0405fe4..a015ace 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_theme.h
+++ b/third_party/blink/renderer/core/scroll/scrollbar_theme.h
@@ -97,7 +97,7 @@
                                  const Scrollbar* vertical_scrollbar,
                                  const DisplayItemClient&,
                                  const IntRect& corner_rect,
-                                 mojom::blink::ColorScheme color_scheme);
+                                 ColorScheme color_scheme);
   virtual void PaintTickmarks(GraphicsContext&,
                               const Scrollbar&,
                               const IntRect&);
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.h b/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.h
index c0188034..84325bb 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.h
+++ b/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.h
@@ -125,7 +125,7 @@
                          const Scrollbar* vertical_scrollbar,
                          const DisplayItemClient&,
                          const IntRect& corner_rect,
-                         mojom::blink::ColorScheme color_scheme) override;
+                         ColorScheme color_scheme) override;
   void PaintThumbInternal(GraphicsContext&,
                           const Scrollbar&,
                           const IntRect&,
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm b/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm
index 4a9ca3c..bf96ece 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm
+++ b/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm
@@ -238,17 +238,15 @@
   }
 
   params.scrollbar_extra.scrollbar_theme =
-      (scrollbar.UsedColorScheme() == mojom::blink::ColorScheme::kDark)
-          ? mojom::blink::ColorScheme::kDark
-          : mojom::blink::ColorScheme::kLight;
+      (scrollbar.UsedColorScheme() == ColorScheme::kDark) ? kDark : kLight;
   params.scrollbar_extra.is_overlay = overlay;
 
   if (overlay) {
     params.scrollbar_extra.scrollbar_theme =
         (scrollbar.GetScrollbarOverlayColorTheme() ==
          kScrollbarOverlayColorThemeLight)
-            ? mojom::blink::ColorScheme::kDark
-            : mojom::blink::ColorScheme::kLight;
+            ? kDark
+            : kLight;
   }
 
   params.scrollbar_extra.is_hovering =
@@ -298,12 +296,11 @@
     context.EndLayer();
 }
 
-void ScrollbarThemeMac::PaintScrollCorner(
-    GraphicsContext& context,
-    const Scrollbar* vertical_scrollbar,
-    const DisplayItemClient& item,
-    const IntRect& rect,
-    mojom::blink::ColorScheme color_scheme) {
+void ScrollbarThemeMac::PaintScrollCorner(GraphicsContext& context,
+                                          const Scrollbar* vertical_scrollbar,
+                                          const DisplayItemClient& item,
+                                          const IntRect& rect,
+                                          ColorScheme color_scheme) {
   if (!vertical_scrollbar) {
     ScrollbarTheme::PaintScrollCorner(context, vertical_scrollbar, item, rect,
                                       color_scheme);
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index 39d7b2e1..111f1549 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2626,18 +2626,17 @@
   // Load the images of CSS properties that were deferred by LazyLoad.
   void LoadDeferredImages(Document&) const;
 
-  mojom::blink::ColorScheme ComputedColorScheme() const {
-    return DarkColorScheme() ? mojom::blink::ColorScheme::kDark
-                             : mojom::blink::ColorScheme::kLight;
+  enum ColorScheme ComputedColorScheme() const {
+    return DarkColorScheme() ? ColorScheme::kDark : ColorScheme::kLight;
   }
 
-  mojom::blink::ColorScheme UsedColorScheme() const {
+  enum ColorScheme UsedColorScheme() const {
     return RuntimeEnabledFeatures::CSSColorSchemeUARenderingEnabled()
                ? ComputedColorScheme()
-               : mojom::blink::ColorScheme::kLight;
+               : ColorScheme::kLight;
   }
 
-  mojom::blink::ColorScheme UsedColorSchemeForInitialColors() const {
+  enum ColorScheme UsedColorSchemeForInitialColors() const {
     return ComputedColorScheme();
   }
 
diff --git a/third_party/blink/renderer/core/style/computed_style_test.cc b/third_party/blink/renderer/core/style/computed_style_test.cc
index 346813780..219f8b1 100644
--- a/third_party/blink/renderer/core/style/computed_style_test.cc
+++ b/third_party/blink/renderer/core/style/computed_style_test.cc
@@ -690,10 +690,10 @@
   light_value->Append(*CSSIdentifierValue::Create(CSSValueID::kLight));
 
   To<Longhand>(ref.GetProperty()).ApplyValue(state, *dark_value);
-  EXPECT_EQ(mojom::blink::ColorScheme::kDark, style->UsedColorScheme());
+  EXPECT_EQ(ColorScheme::kDark, style->UsedColorScheme());
 
   To<Longhand>(ref.GetProperty()).ApplyValue(state, *light_value);
-  EXPECT_EQ(mojom::blink::ColorScheme::kLight, style->UsedColorScheme());
+  EXPECT_EQ(ColorScheme::kLight, style->UsedColorScheme());
 }
 
 TEST(ComputedStyleTest, ApplyInternalLightDarkColor) {
diff --git a/third_party/blink/renderer/core/style/shadow_list.cc b/third_party/blink/renderer/core/style/shadow_list.cc
index 64ed569..7d0a0a82 100644
--- a/third_party/blink/renderer/core/style/shadow_list.cc
+++ b/third_party/blink/renderer/core/style/shadow_list.cc
@@ -52,7 +52,7 @@
 sk_sp<SkDrawLooper> ShadowList::CreateDrawLooper(
     DrawLooperBuilder::ShadowAlphaMode alpha_mode,
     const Color& current_color,
-    mojom::blink::ColorScheme color_scheme,
+    ColorScheme color_scheme,
     bool is_horizontal) const {
   DrawLooperBuilder draw_looper_builder;
   for (wtf_size_t i = Shadows().size(); i--;) {
diff --git a/third_party/blink/renderer/core/style/shadow_list.h b/third_party/blink/renderer/core/style/shadow_list.h
index 78ee292..fa73caa 100644
--- a/third_party/blink/renderer/core/style/shadow_list.h
+++ b/third_party/blink/renderer/core/style/shadow_list.h
@@ -67,7 +67,7 @@
 
   sk_sp<SkDrawLooper> CreateDrawLooper(DrawLooperBuilder::ShadowAlphaMode,
                                        const Color& current_color,
-                                       mojom::blink::ColorScheme color_scheme,
+                                       ColorScheme color_scheme,
                                        bool is_horizontal = true) const;
 
  private:
diff --git a/third_party/blink/renderer/core/svg/svg_animated_color.cc b/third_party/blink/renderer/core/svg/svg_animated_color.cc
index 483620b..abe32f0e 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_color.cc
+++ b/third_party/blink/renderer/core/svg/svg_animated_color.cc
@@ -56,12 +56,12 @@
   return Color::kTransparent;
 }
 
-static inline mojom::blink::ColorScheme ColorSchemeForSVGElement(
+static inline ColorScheme ColorSchemeForSVGElement(
     const SVGElement* target_element) {
   DCHECK(target_element);
   if (const ComputedStyle* target_style = target_element->GetComputedStyle())
     return target_style->UsedColorScheme();
-  return mojom::blink::ColorScheme::kLight;
+  return ColorScheme::kLight;
 }
 
 void SVGColorProperty::Add(const SVGPropertyBase* other,
@@ -69,8 +69,7 @@
   DCHECK(context_element);
 
   Color fallback_color = FallbackColorForCurrentColor(context_element);
-  mojom::blink::ColorScheme color_scheme =
-      ColorSchemeForSVGElement(context_element);
+  ColorScheme color_scheme = ColorSchemeForSVGElement(context_element);
   Color from_color = To<SVGColorProperty>(other)->style_color_.Resolve(
       fallback_color, color_scheme);
   Color to_color = style_color_.Resolve(fallback_color, color_scheme);
@@ -93,8 +92,7 @@
   // Apply currentColor rules.
   DCHECK(context_element);
   Color fallback_color = FallbackColorForCurrentColor(context_element);
-  mojom::blink::ColorScheme color_scheme =
-      ColorSchemeForSVGElement(context_element);
+  ColorScheme color_scheme = ColorSchemeForSVGElement(context_element);
   Color from_color = from_style_color.Resolve(fallback_color, color_scheme);
   Color to_color = to_style_color.Resolve(fallback_color, color_scheme);
   Color to_at_end_of_duration_color =
@@ -131,8 +129,7 @@
     const SVGElement* context_element) const {
   DCHECK(context_element);
   Color fallback_color = FallbackColorForCurrentColor(context_element);
-  mojom::blink::ColorScheme color_scheme =
-      ColorSchemeForSVGElement(context_element);
+  ColorScheme color_scheme = ColorSchemeForSVGElement(context_element);
 
   Color from_color = style_color_.Resolve(fallback_color, color_scheme);
   Color to_color = To<SVGColorProperty>(to_value)->style_color_.Resolve(
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index 6876f634..84eb2756 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -1085,10 +1085,10 @@
     document->Markers().AddGrammarMarker(EphemeralRange(range));
 }
 
-unsigned Internals::markerCountForNode(Node* node,
+unsigned Internals::markerCountForNode(Text* text,
                                        const String& marker_type,
                                        ExceptionState& exception_state) {
-  DCHECK(node);
+  DCHECK(text);
   base::Optional<DocumentMarker::MarkerTypes> marker_types =
       MarkerTypesFrom(marker_type);
   if (!marker_types) {
@@ -1098,18 +1098,18 @@
     return 0;
   }
 
-  return node->GetDocument()
+  return text->GetDocument()
       .Markers()
-      .MarkersFor(To<Text>(*node), marker_types.value())
+      .MarkersFor(*text, marker_types.value())
       .size();
 }
 
-unsigned Internals::activeMarkerCountForNode(Node* node) {
-  DCHECK(node);
+unsigned Internals::activeMarkerCountForNode(Text* text) {
+  DCHECK(text);
 
   // Only TextMatch markers can be active.
-  DocumentMarkerVector markers = node->GetDocument().Markers().MarkersFor(
-      To<Text>(*node), DocumentMarker::MarkerTypes::TextMatch());
+  DocumentMarkerVector markers = text->GetDocument().Markers().MarkersFor(
+      *text, DocumentMarker::MarkerTypes::TextMatch());
 
   unsigned active_marker_count = 0;
   for (const auto& marker : markers) {
@@ -1120,11 +1120,11 @@
   return active_marker_count;
 }
 
-DocumentMarker* Internals::MarkerAt(Node* node,
+DocumentMarker* Internals::MarkerAt(Text* text,
                                     const String& marker_type,
                                     unsigned index,
                                     ExceptionState& exception_state) {
-  DCHECK(node);
+  DCHECK(text);
   base::Optional<DocumentMarker::MarkerTypes> marker_types =
       MarkerTypesFrom(marker_type);
   if (!marker_types) {
@@ -1134,42 +1134,42 @@
     return nullptr;
   }
 
-  DocumentMarkerVector markers = node->GetDocument().Markers().MarkersFor(
-      To<Text>(*node), marker_types.value());
+  DocumentMarkerVector markers =
+      text->GetDocument().Markers().MarkersFor(*text, marker_types.value());
   if (markers.size() <= index)
     return nullptr;
   return markers[index];
 }
 
-Range* Internals::markerRangeForNode(Node* node,
+Range* Internals::markerRangeForNode(Text* text,
                                      const String& marker_type,
                                      unsigned index,
                                      ExceptionState& exception_state) {
-  DCHECK(node);
-  DocumentMarker* marker = MarkerAt(node, marker_type, index, exception_state);
+  DCHECK(text);
+  DocumentMarker* marker = MarkerAt(text, marker_type, index, exception_state);
   if (!marker)
     return nullptr;
-  return MakeGarbageCollected<Range>(node->GetDocument(), node,
-                                     marker->StartOffset(), node,
+  return MakeGarbageCollected<Range>(text->GetDocument(), text,
+                                     marker->StartOffset(), text,
                                      marker->EndOffset());
 }
 
-String Internals::markerDescriptionForNode(Node* node,
+String Internals::markerDescriptionForNode(Text* text,
                                            const String& marker_type,
                                            unsigned index,
                                            ExceptionState& exception_state) {
-  DocumentMarker* marker = MarkerAt(node, marker_type, index, exception_state);
+  DocumentMarker* marker = MarkerAt(text, marker_type, index, exception_state);
   if (!marker || !IsSpellCheckMarker(*marker))
     return String();
   return To<SpellCheckMarker>(marker)->Description();
 }
 
 unsigned Internals::markerBackgroundColorForNode(
-    Node* node,
+    Text* text,
     const String& marker_type,
     unsigned index,
     ExceptionState& exception_state) {
-  DocumentMarker* marker = MarkerAt(node, marker_type, index, exception_state);
+  DocumentMarker* marker = MarkerAt(text, marker_type, index, exception_state);
   auto* style_marker = DynamicTo<StyleableMarker>(marker);
   if (!style_marker)
     return 0;
@@ -1177,11 +1177,11 @@
 }
 
 unsigned Internals::markerUnderlineColorForNode(
-    Node* node,
+    Text* text,
     const String& marker_type,
     unsigned index,
     ExceptionState& exception_state) {
-  DocumentMarker* marker = MarkerAt(node, marker_type, index, exception_state);
+  DocumentMarker* marker = MarkerAt(text, marker_type, index, exception_state);
   auto* style_marker = DynamicTo<StyleableMarker>(marker);
   if (!style_marker)
     return 0;
diff --git a/third_party/blink/renderer/core/testing/internals.h b/third_party/blink/renderer/core/testing/internals.h
index af5a2a4..b17bf26 100644
--- a/third_party/blink/renderer/core/testing/internals.h
+++ b/third_party/blink/renderer/core/testing/internals.h
@@ -80,6 +80,7 @@
 class SequenceTest;
 class ShadowRoot;
 class StaticSelection;
+class Text;
 class TypeConversions;
 class UnionTypesTest;
 
@@ -178,21 +179,21 @@
   DOMRectReadOnly* boundingBox(Element*);
 
   void setMarker(Document*, const Range*, const String&, ExceptionState&);
-  unsigned markerCountForNode(Node*, const String&, ExceptionState&);
-  unsigned activeMarkerCountForNode(Node*);
-  Range* markerRangeForNode(Node*,
+  unsigned markerCountForNode(Text*, const String&, ExceptionState&);
+  unsigned activeMarkerCountForNode(Text*);
+  Range* markerRangeForNode(Text*,
                             const String& marker_type,
                             unsigned index,
                             ExceptionState&);
-  String markerDescriptionForNode(Node*,
+  String markerDescriptionForNode(Text*,
                                   const String& marker_type,
                                   unsigned index,
                                   ExceptionState&);
-  unsigned markerBackgroundColorForNode(Node*,
+  unsigned markerBackgroundColorForNode(Text*,
                                         const String& marker_type,
                                         unsigned index,
                                         ExceptionState&);
-  unsigned markerUnderlineColorForNode(Node*,
+  unsigned markerUnderlineColorForNode(Text*,
                                        const String& marker_type,
                                        unsigned index,
                                        ExceptionState&);
@@ -629,7 +630,7 @@
                    int height,
                    Document*);
 
-  DocumentMarker* MarkerAt(Node*,
+  DocumentMarker* MarkerAt(Text*,
                            const String& marker_type,
                            unsigned index,
                            ExceptionState&);
diff --git a/third_party/blink/renderer/core/testing/internals.idl b/third_party/blink/renderer/core/testing/internals.idl
index 7a95557..7741af5 100644
--- a/third_party/blink/renderer/core/testing/internals.idl
+++ b/third_party/blink/renderer/core/testing/internals.idl
@@ -103,12 +103,12 @@
     DOMRectReadOnly boundingBox(Element element);
 
     [RaisesException] void setMarker(Document document, Range range, DOMString markerType);
-    [RaisesException] unsigned long markerCountForNode(Node node, DOMString markerType);
-    unsigned long activeMarkerCountForNode(Node node);
-    [RaisesException] Range markerRangeForNode(Node node, DOMString markerType, unsigned long index);
-    [RaisesException] DOMString markerDescriptionForNode(Node node, DOMString markerType, unsigned long index);
-    [RaisesException] unsigned long markerBackgroundColorForNode(Node node, DOMString markerType, unsigned long index);
-    [RaisesException] unsigned long markerUnderlineColorForNode(Node node, DOMString markerType, unsigned long index);
+    [RaisesException] unsigned long markerCountForNode(Text text, DOMString markerType);
+    unsigned long activeMarkerCountForNode(Text text);
+    [RaisesException] Range markerRangeForNode(Text text, DOMString markerType, unsigned long index);
+    [RaisesException] DOMString markerDescriptionForNode(Text text, DOMString markerType, unsigned long index);
+    [RaisesException] unsigned long markerBackgroundColorForNode(Text text, DOMString markerType, unsigned long index);
+    [RaisesException] unsigned long markerUnderlineColorForNode(Text text, DOMString markerType, unsigned long index);
     [RaisesException] void addTextMatchMarker(Range range, DOMString matchStatus);
     [RaisesException] void addCompositionMarker(Range range, DOMString underlineColorValue, DOMString thicknessValue, DOMString underlineStyleValue, DOMString textColorValue, DOMString backgroundColorValue);
     [RaisesException] void addActiveSuggestionMarker(Range range, DOMString underlineColorValue, DOMString thicknessValue, DOMString backgroundColorValue);
diff --git a/third_party/blink/renderer/core/timing/largest_contentful_paint.h b/third_party/blink/renderer/core/timing/largest_contentful_paint.h
index bbebf97..d43150989 100644
--- a/third_party/blink/renderer/core/timing/largest_contentful_paint.h
+++ b/third_party/blink/renderer/core/timing/largest_contentful_paint.h
@@ -51,6 +51,14 @@
   WeakMember<Element> element_;
 };
 
+template <>
+struct DowncastTraits<LargestContentfulPaint> {
+  static bool AllowFrom(const PerformanceEntry& entry) {
+    return entry.EntryTypeEnum() ==
+           PerformanceEntry::EntryType::kLargestContentfulPaint;
+  }
+};
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_LARGEST_CONTENTFUL_PAINT_H_
diff --git a/third_party/blink/renderer/core/timing/performance.cc b/third_party/blink/renderer/core/timing/performance.cc
index ec2368c..cff9d95 100644
--- a/third_party/blink/renderer/core/timing/performance.cc
+++ b/third_party/blink/renderer/core/timing/performance.cc
@@ -56,6 +56,7 @@
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/core/loader/document_load_timing.h"
 #include "third_party/blink/renderer/core/loader/document_loader.h"
+#include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/core/timing/largest_contentful_paint.h"
 #include "third_party/blink/renderer/core/timing/layout_shift.h"
 #include "third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.h"
@@ -637,6 +638,7 @@
 }
 
 void Performance::AddLargestContentfulPaint(LargestContentfulPaint* entry) {
+  probe::PerformanceEntryAdded(GetExecutionContext(), entry);
   if (largest_contentful_paint_buffer_.size() <
       kDefaultLargestContenfulPaintSize) {
     largest_contentful_paint_buffer_.push_back(entry);
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.cc
index 4fecf3d..89c1c49c 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.cc
@@ -52,7 +52,7 @@
 
 static ColorParseResult ParseColor(Color& parsed_color,
                                    const String& color_string,
-                                   mojom::blink::ColorScheme color_scheme) {
+                                   ColorScheme color_scheme) {
   if (EqualIgnoringASCIICase(color_string, "currentcolor"))
     return kParsedCurrentColor;
   const bool kUseStrictParsing = true;
@@ -72,7 +72,7 @@
   return color;
 }
 
-static mojom::blink::ColorScheme ColorScheme(HTMLCanvasElement* canvas) {
+static ColorScheme ColorScheme(HTMLCanvasElement* canvas) {
   if (canvas && canvas->isConnected()) {
     if (auto* style = canvas->GetComputedStyle())
       return style->UsedColorScheme();
diff --git a/third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper.cc b/third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper.cc
index cf274d9..3d770bf1a 100644
--- a/third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper.cc
+++ b/third_party/blink/renderer/modules/direct_sockets/tcp_readable_stream_wrapper.cc
@@ -142,6 +142,9 @@
 }
 
 void TCPReadableStreamWrapper::ReadFromPipeAndEnqueue() {
+  if (!script_state_->ContextIsValid())
+    return;
+
   DVLOG(1) << "TCPReadableStreamWrapper::ReadFromPipeAndEnqueue() this=" << this
            << " in_two_phase_read_=" << in_two_phase_read_
            << " read_pending_=" << read_pending_;
diff --git a/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc b/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc
index 59b4904..a101a87 100644
--- a/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc
+++ b/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc
@@ -7,8 +7,8 @@
 #include "third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h"
 
 #include "device/gamepad/public/cpp/gamepads.h"
-#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
-#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.h"
 #include "third_party/blink/renderer/modules/gamepad/navigator_gamepad.h"
 
@@ -41,21 +41,23 @@
 }
 
 GamepadDispatcher::GamepadDispatcher(ExecutionContext& context)
-    :  // See https://bit.ly/2S0zRAS for task types.
-      task_runner_(context.GetTaskRunner(TaskType::kMiscPlatformAPI)),
-      gamepad_haptics_manager_remote_(&context) {}
+    : execution_context_(&context), gamepad_haptics_manager_remote_(&context) {}
 
 GamepadDispatcher::~GamepadDispatcher() = default;
 
 void GamepadDispatcher::InitializeHaptics() {
-  if (!gamepad_haptics_manager_remote_.is_bound()) {
-    Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
+  if (!gamepad_haptics_manager_remote_.is_bound() && execution_context_) {
+    // See https://bit.ly/2S0zRAS for task types.
+    auto task_runner =
+        execution_context_->GetTaskRunner(TaskType::kMiscPlatformAPI);
+    execution_context_->GetBrowserInterfaceBroker().GetInterface(
         gamepad_haptics_manager_remote_.BindNewPipeAndPassReceiver(
-            task_runner_));
+            std::move(task_runner)));
   }
 }
 
 void GamepadDispatcher::Trace(Visitor* visitor) const {
+  visitor->Trace(execution_context_);
   visitor->Trace(reader_);
   visitor->Trace(gamepad_haptics_manager_remote_);
   PlatformEventDispatcher::Trace(visitor);
diff --git a/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h b/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h
index 84dc548..51357217 100644
--- a/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h
+++ b/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h
@@ -60,7 +60,7 @@
                                              const device::Gamepad&,
                                              bool connected);
 
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+  WeakMember<ExecutionContext> execution_context_;
   Member<GamepadSharedMemoryReader> reader_;
   HeapMojoRemote<device::mojom::blink::GamepadHapticsManager,
                  HeapMojoWrapperMode::kWithoutContextObserver>
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.cc
index c9127f5..d68f882 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.cc
@@ -12,7 +12,7 @@
 
 MediaStreamVideoTrackUnderlyingSink::MediaStreamVideoTrackUnderlyingSink(
     PushableMediaStreamVideoSource* source)
-    : source_(source) {}
+    : source_(source->GetWeakPtr()) {}
 
 ScriptPromise MediaStreamVideoTrackUnderlyingSink::start(
     ScriptState* script_state,
@@ -39,14 +39,16 @@
     return ScriptPromise();
   }
 
-  if (!source_->running()) {
+  PushableMediaStreamVideoSource* pushable_source =
+      static_cast<PushableMediaStreamVideoSource*>(source_.get());
+  if (!pushable_source || !pushable_source->running()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                       "Stream closed");
     return ScriptPromise();
   }
 
   base::TimeTicks estimated_capture_time = base::TimeTicks::Now();
-  source_->PushFrame(video_frame->frame(), estimated_capture_time);
+  pushable_source->PushFrame(video_frame->frame(), estimated_capture_time);
   // Invalidate the JS |video_frame|. Otherwise, the media frames might not be
   // released, which would leak resources and also cause some MediaStream
   // sources such as cameras to drop frames.
@@ -59,14 +61,16 @@
     ScriptState* script_state,
     ScriptValue reason,
     ExceptionState& exception_state) {
-  source_->StopSource();
+  if (source_)
+    source_->StopSource();
   return ScriptPromise::CastUndefined(script_state);
 }
 
 ScriptPromise MediaStreamVideoTrackUnderlyingSink::close(
     ScriptState* script_state,
     ExceptionState& exception_state) {
-  source_->StopSource();
+  if (source_)
+    source_->StopSource();
   return ScriptPromise::CastUndefined(script_state);
 }
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.h b/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.h
index 6df20ef..967f06a 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.h
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink.h
@@ -10,6 +10,7 @@
 
 namespace blink {
 
+class MediaStreamVideoSource;
 class PushableMediaStreamVideoSource;
 
 class MODULES_EXPORT MediaStreamVideoTrackUnderlyingSink
@@ -34,7 +35,7 @@
                       ExceptionState& exception_state) override;
 
  private:
-  PushableMediaStreamVideoSource* source_;
+  base::WeakPtr<MediaStreamVideoSource> source_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/nfc/ndef_reader.cc b/third_party/blink/renderer/modules/nfc/ndef_reader.cc
index 8201ee7..b13006e5 100644
--- a/third_party/blink/renderer/modules/nfc/ndef_reader.cc
+++ b/third_party/blink/renderer/modules/nfc/ndef_reader.cc
@@ -4,9 +4,6 @@
 
 #include "third_party/blink/renderer/modules/nfc/ndef_reader.h"
 
-#include <utility>
-
-#include "mojo/public/cpp/bindings/callback_helpers.h"
 #include "services/device/public/mojom/nfc.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/modules/v8/string_or_array_buffer_or_array_buffer_view_or_ndef_message_init.h"
@@ -26,7 +23,6 @@
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
 #include "third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
 
 namespace blink {
 
@@ -70,7 +66,9 @@
 constexpr char kChildFrameErrorMessage[] =
     "Web NFC can only be accessed in a top-level browsing context.";
 
-constexpr char kInvalidStateErrorMessage[] = "A scan() operation is ongoing.";
+constexpr char kScanAbortMessage[] = "The NFC scan operation was cancelled.";
+
+constexpr char kWriteAbortMessage[] = "The NFC write operation was cancelled.";
 }  // namespace
 
 // static
@@ -119,33 +117,18 @@
   // "AbortError" DOMException and return p.
   if (options->hasSignal() && options->signal()->aborted()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kAbortError,
-                                      "The NFC scan operation was cancelled.");
+                                      kScanAbortMessage);
     return ScriptPromise();
   }
 
-  if (has_pending_scan_request_) {
+  // Reject promise when there's already an ongoing scan.
+  if (scan_resolver_ || GetNfcProxy()->IsReading(this)) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
-                                      kInvalidStateErrorMessage);
-    return ScriptPromise();
-  }
-  has_pending_scan_request_ = true;
-
-  // https://github.com/w3c/web-nfc/issues/592
-  // reject scan promise when there's already an ongoing scan.
-  if (GetNfcProxy()->IsReading(this)) {
-    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
-                                      kInvalidStateErrorMessage);
+                                      "A scan() operation is ongoing.");
     return ScriptPromise();
   }
 
   scan_resolver_ = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
-  // 8. If |signal| is not null, then add the following abort steps
-  // to |signal|:
-  if (options->hasSignal()) {
-    options->signal()->AddAlgorithm(
-        WTF::Bind(&NDEFReader::ReadAbort, WrapPersistent(this)));
-  }
-
   GetPermissionService()->RequestPermission(
       CreatePermissionDescriptor(PermissionName::NFC),
       LocalFrame::HasTransientUserActivation(DomWindow()->GetFrame()),
@@ -156,25 +139,25 @@
 
 void NDEFReader::ReadOnRequestPermission(const NDEFScanOptions* options,
                                          PermissionStatus status) {
-  if (!scan_resolver_) {
-    has_pending_scan_request_ = false;
+  if (!scan_resolver_)
     return;
-  }
 
   if (status != PermissionStatus::GRANTED) {
-    has_pending_scan_request_ = false;
     scan_resolver_->Reject(MakeGarbageCollected<DOMException>(
         DOMExceptionCode::kNotAllowedError, "NFC permission request denied."));
     scan_resolver_.Clear();
     return;
   }
-  if (options->hasSignal() && options->signal()->aborted()) {
-    has_pending_scan_request_ = false;
-    scan_resolver_->Reject(MakeGarbageCollected<DOMException>(
-        DOMExceptionCode::kAbortError,
-        "The NFC scan operation was cancelled."));
-    scan_resolver_.Clear();
-    return;
+
+  if (options->hasSignal()) {
+    if (options->signal()->aborted()) {
+      scan_resolver_->Reject(MakeGarbageCollected<DOMException>(
+          DOMExceptionCode::kAbortError, kScanAbortMessage));
+      scan_resolver_.Clear();
+      return;
+    }
+    options->signal()->AddAlgorithm(
+        WTF::Bind(&NDEFReader::ReadAbort, WrapPersistent(this)));
   }
 
   GetNfcProxy()->StartReading(
@@ -184,7 +167,6 @@
 
 void NDEFReader::ReadOnRequestCompleted(
     device::mojom::blink::NDEFErrorPtr error) {
-  has_pending_scan_request_ = false;
   if (!scan_resolver_)
     return;
 
@@ -220,8 +202,7 @@
 void NDEFReader::ReadAbort() {
   if (scan_resolver_) {
     scan_resolver_->Reject(MakeGarbageCollected<DOMException>(
-        DOMExceptionCode::kAbortError,
-        "The NFC scan operation was cancelled."));
+        DOMExceptionCode::kAbortError, kScanAbortMessage));
     scan_resolver_.Clear();
   }
 
@@ -246,7 +227,7 @@
     // If signal’s aborted flag is set, then reject p with an "AbortError"
     // DOMException and return p.
     exception_state.ThrowDOMException(DOMExceptionCode::kAbortError,
-                                      "The NFC write operation was cancelled.");
+                                      kWriteAbortMessage);
     return ScriptPromise();
   }
 
@@ -289,18 +270,14 @@
     return;
   }
 
-  if (options->hasSignal() && options->signal()->aborted()) {
-    resolver->Reject(MakeGarbageCollected<DOMException>(
-        DOMExceptionCode::kAbortError,
-        "The NFC write operation was cancelled."));
-    return;
-  }
-
-  // If signal is not null, then add the abort steps to signal.
-  if (options->hasSignal() && !options->signal()->aborted()) {
-    options->signal()->AddAlgorithm(WTF::Bind(&NDEFReader::WriteAbort,
-                                              WrapPersistent(this),
-                                              WrapPersistent(resolver)));
+  if (options->hasSignal()) {
+    if (options->signal()->aborted()) {
+      resolver->Reject(MakeGarbageCollected<DOMException>(
+          DOMExceptionCode::kAbortError, kWriteAbortMessage));
+      return;
+    }
+    options->signal()->AddAlgorithm(
+        WTF::Bind(&NDEFReader::WriteAbort, WrapPersistent(this)));
   }
 
   auto callback = WTF::Bind(&NDEFReader::WriteOnRequestCompleted,
@@ -325,7 +302,7 @@
   }
 }
 
-void NDEFReader::WriteAbort(ScriptPromiseResolver* resolver) {
+void NDEFReader::WriteAbort() {
   // WriteOnRequestCompleted() should always be called whether the push
   // operation is cancelled successfully or not.
   GetNfcProxy()->CancelPush();
diff --git a/third_party/blink/renderer/modules/nfc/ndef_reader.h b/third_party/blink/renderer/modules/nfc/ndef_reader.h
index 377e0b6..9f18556 100644
--- a/third_party/blink/renderer/modules/nfc/ndef_reader.h
+++ b/third_party/blink/renderer/modules/nfc/ndef_reader.h
@@ -78,7 +78,7 @@
   void ReadAbort();
   void ReadOnRequestCompleted(device::mojom::blink::NDEFErrorPtr error);
 
-  void WriteAbort(ScriptPromiseResolver* resolver);
+  void WriteAbort();
   void WriteOnRequestCompleted(ScriptPromiseResolver* resolver,
                                device::mojom::blink::NDEFErrorPtr error);
 
@@ -97,8 +97,6 @@
   // that case the callback passed to Watch() won't be called and
   // mojo::WrapCallbackWithDefaultInvokeIfNotRun() is forbidden in Blink.
   Member<ScriptPromiseResolver> scan_resolver_;
-  // To reject if there is already an ongoing scan.
-  bool has_pending_scan_request_ = false;
 
   HeapMojoRemote<mojom::blink::PermissionService,
                  HeapMojoWrapperMode::kWithoutContextObserver>
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 2f13be3b..1d87a9f 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1616,7 +1616,6 @@
     "//mojo/public/cpp/base",
     "//mojo/public/cpp/bindings",
     "//services/network/public/mojom:mojom_headers",
-    "//third_party/blink/public/mojom:color_scheme_mojo_bindings",
     "//third_party/blink/public/mojom:embedded_frame_sink_mojo_bindings_blink",
     "//third_party/blink/renderer/platform/blob",
     "//third_party/blink/renderer/platform/heap",
diff --git a/third_party/blink/renderer/platform/graphics/DEPS b/third_party/blink/renderer/platform/graphics/DEPS
index 978c513b..44d4fa7 100644
--- a/third_party/blink/renderer/platform/graphics/DEPS
+++ b/third_party/blink/renderer/platform/graphics/DEPS
@@ -75,9 +75,6 @@
     "+ui/gl/buffer_format_utils.h",
   ],
   "(graphics_context|skia_utils)\.cc" : [ "+ui/base/ui_base_features.h" ],
-  "graphics_context.h": [
-    "+third_party/blink/public/mojom/frame/frame_owner_properties.mojom-blink.h",
-  ],
   "rw_buffer_test.cc": [
     "+base/threading/platform_thread.h",
   ],
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.cc b/third_party/blink/renderer/platform/graphics/graphics_context.cc
index 2eaf3516..847557a 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.cc
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -32,7 +32,6 @@
 #include "build/build_config.h"
 #include "components/paint_preview/common/paint_preview_tracker.h"
 #include "skia/ext/platform_canvas.h"
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink.h"
 #include "third_party/blink/renderer/platform/fonts/text_run_paint_info.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
 #include "third_party/blink/renderer/platform/geometry/float_rounded_rect.h"
@@ -453,14 +452,14 @@
                                     float border_radius,
                                     float min_border_width,
                                     const Color& color,
-                                    mojom::blink::ColorScheme color_scheme) {
+                                    ColorScheme color_scheme) {
 #if defined(OS_MAC)
-  const Color& inner_color = color_scheme == mojom::blink::ColorScheme::kDark
+  const Color& inner_color = color_scheme == ColorScheme::kDark
                                  ? SkColorSetRGB(0x99, 0xC8, 0xFF)
                                  : color;
 #else
   const Color& inner_color =
-      color_scheme == mojom::blink::ColorScheme::kDark ? SK_ColorWHITE : color;
+      color_scheme == ColorScheme::kDark ? SK_ColorWHITE : color;
 #endif
   if (::features::IsFormControlsRefreshEnabled()) {
     // The focus ring is made of two borders which have a 2:1 ratio.
@@ -472,7 +471,7 @@
     if (min_border_width >= inside_border_width) {
       offset -= inside_border_width;
     }
-    const Color& outer_color = color_scheme == mojom::blink::ColorScheme::kDark
+    const Color& outer_color = color_scheme == ColorScheme::kDark
                                    ? SkColorSetRGB(0x10, 0x10, 0x10)
                                    : SK_ColorWHITE;
     // The outer ring is drawn first, and we overdraw to ensure no gaps or AA
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.h b/third_party/blink/renderer/platform/graphics/graphics_context.h
index 6b8821b..98e8be7 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.h
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.h
@@ -31,7 +31,7 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink-forward.h"
+#include "third_party/blink/public/common/css/color_scheme.h"
 #include "third_party/blink/renderer/platform/fonts/font.h"
 #include "third_party/blink/renderer/platform/graphics/dark_mode_filter.h"
 #include "third_party/blink/renderer/platform/graphics/dark_mode_settings.h"
@@ -362,7 +362,7 @@
                      float border_radius,
                      float min_border_width,
                      const Color&,
-                     mojom::blink::ColorScheme color_scheme);
+                     ColorScheme color_scheme);
   void DrawFocusRing(const Path&, float width, int offset, const Color&);
 
   enum Edge {
diff --git a/third_party/blink/renderer/platform/weborigin/scheme_registry.cc b/third_party/blink/renderer/platform/weborigin/scheme_registry.cc
index 8a09026..ba96b90 100644
--- a/third_party/blink/renderer/platform/weborigin/scheme_registry.cc
+++ b/third_party/blink/renderer/platform/weborigin/scheme_registry.cc
@@ -86,6 +86,14 @@
   }
   ~URLSchemesRegistry() = default;
 
+  // As URLSchemesRegistry is accessed from multiple threads, be very careful to
+  // ensure that
+  // - URLSchemesRegistry is initialized/modified through
+  //   GetMutableURLSchemesRegistry() before threads can be created, and
+  // - The URLSchemesRegistry members below aren't modified when accessed after
+  //   initialization.
+  //   Particularly, Strings inside them shouldn't be copied, as it modifies
+  //   reference counts of StringImpls (IsolatedCopy() should be taken instead).
   URLSchemesSet local_schemes;
   URLSchemesSet display_isolated_url_schemes;
   URLSchemesSet secure_schemes;
@@ -258,7 +266,10 @@
     else
       add_separator = true;
 
-    builder.Append(scheme);
+    // As |cors_enabled_schemes| can be accessed from multiple threads, we need
+    // IsolatedCopy() here before passing it to |StringBuilder| that can
+    // ref/deref Strings.
+    builder.Append(scheme.IsolatedCopy());
   }
   return builder.ToString();
 }
diff --git a/third_party/blink/tools/blinkpy/third_party/README.chromium b/third_party/blink/tools/blinkpy/third_party/README.chromium
index 97dfbb2..5c1413bc 100644
--- a/third_party/blink/tools/blinkpy/third_party/README.chromium
+++ b/third_party/blink/tools/blinkpy/third_party/README.chromium
@@ -22,7 +22,7 @@
 Name: web-platform-tests - Test Suites for Web Platform specifications
 Short Name: wpt
 URL: https://github.com/web-platform-tests/wpt/
-Version: 0fb69997a8b5154bf39ba3ffa586c2aa25442da8
+Version: d3ce095fcc6b5a85e6056fdebbf939caf2e2719f
 License: LICENSES FOR W3C TEST SUITES (https://www.w3.org/Consortium/Legal/2008/03-bsd-license.html)
 License File: wpt/wpt/LICENSE.md
 Security Critical: no
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/WPTIncludeList b/third_party/blink/tools/blinkpy/third_party/wpt/WPTIncludeList
index fdd34e2..ca0b1119 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/WPTIncludeList
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/WPTIncludeList
@@ -111,6 +111,25 @@
 ./tools/third_party/hyperframe/hyperframe/exceptions.py
 ./tools/third_party/hyperframe/hyperframe/flags.py
 ./tools/third_party/hyperframe/hyperframe/frame.py
+./tools/third_party/pywebsocket3/LICENSE
+./tools/third_party/pywebsocket3/mod_pywebsocket/__init__.py
+./tools/third_party/pywebsocket3/mod_pywebsocket/common.py
+./tools/third_party/pywebsocket3/mod_pywebsocket/dispatch.py
+./tools/third_party/pywebsocket3/mod_pywebsocket/extensions.py
+./tools/third_party/pywebsocket3/mod_pywebsocket/fast_masking.i
+./tools/third_party/pywebsocket3/mod_pywebsocket/handshake/_base.py
+./tools/third_party/pywebsocket3/mod_pywebsocket/handshake/hybi.py
+./tools/third_party/pywebsocket3/mod_pywebsocket/handshake/__init__.py
+./tools/third_party/pywebsocket3/mod_pywebsocket/http_header_util.py
+./tools/third_party/pywebsocket3/mod_pywebsocket/memorizingfile.py
+./tools/third_party/pywebsocket3/mod_pywebsocket/msgutil.py
+./tools/third_party/pywebsocket3/mod_pywebsocket/request_handler.py
+./tools/third_party/pywebsocket3/mod_pywebsocket/server_util.py
+./tools/third_party/pywebsocket3/mod_pywebsocket/standalone.py
+./tools/third_party/pywebsocket3/mod_pywebsocket/_stream_exceptions.py
+./tools/third_party/pywebsocket3/mod_pywebsocket/stream.py
+./tools/third_party/pywebsocket3/mod_pywebsocket/util.py
+./tools/third_party/pywebsocket3/mod_pywebsocket/websocket_server.py
 ./tools/third_party/six/LICENSE
 ./tools/third_party/six/six.py
 ./tools/third_party/webencodings/PKG-INFO
@@ -167,5 +186,6 @@
 ./tools/wptserve/wptserve/stash.py
 ./tools/wptserve/wptserve/utils.py
 ./tools/wptserve/wptserve/wptserve.py
+./tools/wptserve/wptserve/ws_h2_handshake.py
 ./wpt
 ./wpt.py
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh b/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh
index 644a1d1..9ae703f4 100755
--- a/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh
@@ -9,7 +9,7 @@
 
 TARGET_DIR=$DIR/wpt
 REMOTE_REPO="https://github.com/web-platform-tests/wpt.git"
-WPT_HEAD=0fb69997a8b5154bf39ba3ffa586c2aa25442da8
+WPT_HEAD=d3ce095fcc6b5a85e6056fdebbf939caf2e2719f
 
 function clone {
   # Remove existing repo if already exists.
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/docs/commands.json b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/docs/commands.json
index 55408d8..f3494b8 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/docs/commands.json
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/docs/commands.json
@@ -3,6 +3,7 @@
     "path": "frontend.py",
     "script": "build",
     "help": "Build documentation",
+    "py3only": true,
     "virtualenv": true,
     "requirements": [
       "./requirements.txt"
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/localpaths.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/localpaths.py
index 51aecea..a79acb82 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/localpaths.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/localpaths.py
@@ -10,8 +10,11 @@
 sys.path.insert(0, os.path.join(here, "third_party", "attrs", "src"))
 sys.path.insert(0, os.path.join(here, "third_party", "funcsigs"))
 sys.path.insert(0, os.path.join(here, "third_party", "html5lib"))
+sys.path.insert(0, os.path.join(here, "third_party", "zipp"))
 sys.path.insert(0, os.path.join(here, "third_party", "more-itertools"))
-sys.path.insert(0, os.path.join(here, "third_party", "pluggy"))
+sys.path.insert(0, os.path.join(here, "third_party", "packaging"))
+sys.path.insert(0, os.path.join(here, "third_party", "pathlib2"))
+sys.path.insert(0, os.path.join(here, "third_party", "pluggy", "src"))
 sys.path.insert(0, os.path.join(here, "third_party", "py"))
 sys.path.insert(0, os.path.join(here, "third_party", "pytest"))
 sys.path.insert(0, os.path.join(here, "third_party", "pytest", "src"))
@@ -22,6 +25,8 @@
 sys.path.insert(0, os.path.join(here, "third_party", "hyperframe"))
 sys.path.insert(0, os.path.join(here, "third_party", "certifi"))
 sys.path.insert(0, os.path.join(here, "third_party", "hyper"))
+if sys.version_info < (3, 8):
+    sys.path.insert(0, os.path.join(here, "third_party", "importlib_metadata"))
 sys.path.insert(0, os.path.join(here, "webdriver"))
 sys.path.insert(0, os.path.join(here, "wptrunner"))
 
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/item.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/item.py
index 9a43a68..857c8485 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/item.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/item.py
@@ -1,7 +1,7 @@
 import os.path
 from inspect import isabstract
 from six import iteritems, with_metaclass
-from six.moves.urllib.parse import urljoin, urlparse
+from six.moves.urllib.parse import urljoin, urlparse, parse_qs
 from abc import ABCMeta, abstractproperty
 
 from .utils import to_os_path
@@ -104,7 +104,7 @@
 
 
 class URLManifestItem(ManifestItem):
-    __slots__ = ("url_base", "_url", "_extras")
+    __slots__ = ("url_base", "_url", "_extras", "_flags")
 
     def __init__(self,
                  tests_root,  # type: Text
@@ -120,6 +120,9 @@
         assert url is None or url[0] != "/"
         self._url = url
         self._extras = extras
+        parsed_url = urlparse(self.url)
+        self._flags = (set(parsed_url.path.rsplit("/", 1)[1].split(".")[1:-1]) |
+                       set(parse_qs(parsed_url.query).get("wpt_flags", [])))
 
     @property
     def id(self):
@@ -138,22 +141,19 @@
     @property
     def https(self):
         # type: () -> bool
-        flags = set(urlparse(self.url).path.rsplit("/", 1)[1].split(".")[1:-1])
-        return "https" in flags or "serviceworker" in flags
+        return "https" in self._flags or "serviceworker" in self._flags
 
     @property
     def h2(self):
         # type: () -> bool
-        flags = set(urlparse(self.url).path.rsplit("/", 1)[1].split(".")[1:-1])
-        return "h2" in flags
+        return "h2" in self._flags
 
     @property
     def subdomain(self):
         # type: () -> bool
-        flags = set(urlparse(self.url).path.rsplit("/", 1)[1].split(".")[1:-1])
         # Note: this is currently hard-coded to check for `www`, rather than
         # all possible valid subdomains. It can be extended if needed.
-        return "www" in flags
+        return "www" in self._flags
 
     def to_json(self):
         # type: () -> Tuple[Optional[Text], Dict[Any, Any]]
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py
index 3a1c782..0a5f16ef 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py
@@ -6,6 +6,7 @@
 import argparse
 import json
 import logging
+import multiprocessing
 import os
 import platform
 import signal
@@ -19,7 +20,6 @@
 import uuid
 from collections import defaultdict, OrderedDict
 from itertools import chain, product
-from multiprocessing import Process, Event
 
 from localpaths import repo_root
 from six.moves import reload_module
@@ -407,18 +407,19 @@
 
 
 class ServerProc(object):
-    def __init__(self, scheme=None):
+    def __init__(self, mp_context, scheme=None):
         self.proc = None
         self.daemon = None
-        self.stop = Event()
+        self.mp_context = mp_context
+        self.stop = mp_context.Event()
         self.scheme = scheme
 
     def start(self, init_func, host, port, paths, routes, bind_address, config, **kwargs):
-        self.proc = Process(target=self.create_daemon,
-                            args=(init_func, host, port, paths, routes, bind_address,
-                                  config),
-                            name='%s on port %s' % (self.scheme, port),
-                            kwargs=kwargs)
+        self.proc = self.mp_context.Process(target=self.create_daemon,
+                                            args=(init_func, host, port, paths, routes, bind_address,
+                                                  config),
+                                            name='%s on port %s' % (self.scheme, port),
+                                            kwargs=kwargs)
         self.proc.daemon = True
         self.proc.start()
 
@@ -470,7 +471,7 @@
         return self.proc.is_alive()
 
 
-def check_subdomains(config, routes):
+def check_subdomains(config, routes, mp_context):
     paths = config.paths
     bind_address = config.bind_address
 
@@ -478,7 +479,7 @@
     port = get_port()
     logger.debug("Going to use port %d to check subdomains" % port)
 
-    wrapper = ServerProc()
+    wrapper = ServerProc(mp_context)
     wrapper.start(start_http_server, host, port, paths, routes,
                   bind_address, config)
 
@@ -530,7 +531,8 @@
     return "".join(rv)
 
 
-def start_servers(host, ports, paths, routes, bind_address, config, **kwargs):
+def start_servers(host, ports, paths, routes, bind_address, config,
+                  mp_context, **kwargs):
     servers = defaultdict(list)
     for scheme, ports in ports.items():
         assert len(ports) == {"http": 2, "https": 2}.get(scheme, 1)
@@ -551,7 +553,7 @@
                          "wss": start_wss_server,
                          "quic-transport": start_quic_transport_server}[scheme]
 
-            server_proc = ServerProc(scheme=scheme)
+            server_proc = ServerProc(mp_context, scheme=scheme)
             server_proc.start(init_func, host, port, paths, routes, bind_address,
                               config, **kwargs)
             servers[scheme].append((port, server_proc))
@@ -609,6 +611,7 @@
                                      port=port,
                                      handler_cls=wptserve.Http2WebTestRequestHandler,
                                      doc_root=paths["doc_root"],
+                                     ws_doc_root=paths["ws_doc_root"],
                                      routes=routes,
                                      rewrites=rewrites,
                                      bind_address=bind_address,
@@ -780,7 +783,7 @@
         startup_failed(log=False)
 
 
-def start(config, routes, **kwargs):
+def start(config, routes, mp_context, **kwargs):
     host = config["server_host"]
     ports = config.ports
     paths = config.paths
@@ -788,7 +791,7 @@
 
     logger.debug("Using ports: %r" % ports)
 
-    servers = start_servers(host, ports, paths, routes, bind_address, config, **kwargs)
+    servers = start_servers(host, ports, paths, routes, bind_address, config, mp_context, **kwargs)
 
     return servers
 
@@ -965,9 +968,20 @@
     return parser
 
 
-def run(config_cls=ConfigBuilder, route_builder=None, **kwargs):
+class MpContext(object):
+    def __getattr__(self, name):
+        return getattr(multiprocessing, name)
+
+
+def run(config_cls=ConfigBuilder, route_builder=None, mp_context=None, **kwargs):
     received_signal = threading.Event()
 
+    if mp_context is None:
+        if hasattr(multiprocessing, "get_context"):
+            mp_context = multiprocessing.get_context()
+        else:
+            mp_context = MpContext()
+
     with build_config(os.path.join(repo_root, "config.json"),
                       config_cls=config_cls,
                       **kwargs) as config:
@@ -997,7 +1011,7 @@
         routes = route_builder(config.aliases, config).get_routes()
 
         if config["check_subdomains"]:
-            check_subdomains(config, routes)
+            check_subdomains(config, routes, mp_context)
 
         stash_address = None
         if bind_address:
@@ -1005,7 +1019,7 @@
             logger.debug("Going to use port %d for stash" % stash_address[1])
 
         with stash.StashServer(stash_address, authkey=str(uuid.uuid4())):
-            servers = start(config, routes, **kwargs)
+            servers = start(config, routes, mp_context, **kwargs)
             signal.signal(signal.SIGTERM, handle_signal)
             signal.signal(signal.SIGINT, handle_signal)
 
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/LICENSE b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/LICENSE
new file mode 100644
index 0000000..c91bea90
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/LICENSE
@@ -0,0 +1,28 @@
+Copyright 2020, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+    * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/__init__.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/__init__.py
new file mode 100644
index 0000000..28d5f59
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/__init__.py
@@ -0,0 +1,172 @@
+# Copyright 2011, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+""" A Standalone WebSocket Server for testing purposes
+
+mod_pywebsocket is an API that provides WebSocket functionalities with
+a standalone WebSocket server. It is intended for testing or
+experimental purposes.
+
+Installation
+============
+1. Follow standalone server documentation to start running the
+standalone server. It can be read by running the following command:
+
+    $ pydoc mod_pywebsocket.standalone
+
+2. Once the standalone server is launched verify it by accessing
+http://localhost[:port]/console.html. Include the port number when
+specified on launch. If everything is working correctly, you
+will see a simple echo console.
+
+
+Writing WebSocket handlers
+==========================
+
+When a WebSocket request comes in, the resource name
+specified in the handshake is considered as if it is a file path under
+<websock_handlers> and the handler defined in
+<websock_handlers>/<resource_name>_wsh.py is invoked.
+
+For example, if the resource name is /example/chat, the handler defined in
+<websock_handlers>/example/chat_wsh.py is invoked.
+
+A WebSocket handler is composed of the following three functions:
+
+    web_socket_do_extra_handshake(request)
+    web_socket_transfer_data(request)
+    web_socket_passive_closing_handshake(request)
+
+where:
+    request: mod_python request.
+
+web_socket_do_extra_handshake is called during the handshake after the
+headers are successfully parsed and WebSocket properties (ws_origin,
+and ws_resource) are added to request. A handler
+can reject the request by raising an exception.
+
+A request object has the following properties that you can use during the
+extra handshake (web_socket_do_extra_handshake):
+- ws_resource
+- ws_origin
+- ws_version
+- ws_extensions
+- ws_deflate
+- ws_protocol
+- ws_requested_protocols
+
+The last two are a bit tricky. See the next subsection.
+
+
+Subprotocol Negotiation
+-----------------------
+
+ws_protocol is always set to None when
+web_socket_do_extra_handshake is called. If ws_requested_protocols is not
+None, you must choose one subprotocol from this list and set it to
+ws_protocol.
+
+Data Transfer
+-------------
+
+web_socket_transfer_data is called after the handshake completed
+successfully. A handler can receive/send messages from/to the client
+using request. mod_pywebsocket.msgutil module provides utilities
+for data transfer.
+
+You can receive a message by the following statement.
+
+    message = request.ws_stream.receive_message()
+
+This call blocks until any complete text frame arrives, and the payload data
+of the incoming frame will be stored into message. When you're using IETF
+HyBi 00 or later protocol, receive_message() will return None on receiving
+client-initiated closing handshake. When any error occurs, receive_message()
+will raise some exception.
+
+You can send a message by the following statement.
+
+    request.ws_stream.send_message(message)
+
+
+Closing Connection
+------------------
+
+Executing the following statement or just return-ing from
+web_socket_transfer_data cause connection close.
+
+    request.ws_stream.close_connection()
+
+close_connection will wait
+for closing handshake acknowledgement coming from the client. When it
+couldn't receive a valid acknowledgement, raises an exception.
+
+web_socket_passive_closing_handshake is called after the server receives
+incoming closing frame from the client peer immediately. You can specify
+code and reason by return values. They are sent as a outgoing closing frame
+from the server. A request object has the following properties that you can
+use in web_socket_passive_closing_handshake.
+- ws_close_code
+- ws_close_reason
+
+
+Threading
+---------
+
+A WebSocket handler must be thread-safe. The standalone
+server uses threads by default.
+
+
+Configuring WebSocket Extension Processors
+------------------------------------------
+
+See extensions.py for supported WebSocket extensions. Note that they are
+unstable and their APIs are subject to change substantially.
+
+A request object has these extension processing related attributes.
+
+- ws_requested_extensions:
+
+  A list of common.ExtensionParameter instances representing extension
+  parameters received from the client in the client's opening handshake.
+  You shouldn't modify it manually.
+
+- ws_extensions:
+
+  A list of common.ExtensionParameter instances representing extension
+  parameters to send back to the client in the server's opening handshake.
+  You shouldn't touch it directly. Instead, call methods on extension
+  processors.
+
+- ws_extension_processors:
+
+  A list of loaded extension processors. Find the processor for the
+  extension you want to configure from it, and call its methods.
+"""
+
+# vi:sts=4 sw=4 et tw=72
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/_stream_exceptions.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/_stream_exceptions.py
new file mode 100644
index 0000000..b47878bc
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/_stream_exceptions.py
@@ -0,0 +1,82 @@
+# Copyright 2020, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""Stream Exceptions.
+"""
+
+# Note: request.connection.write/read are used in this module, even though
+# mod_python document says that they should be used only in connection
+# handlers. Unfortunately, we have no other options. For example,
+# request.write/read are not suitable because they don't allow direct raw bytes
+# writing/reading.
+
+
+# Exceptions
+class ConnectionTerminatedException(Exception):
+    """This exception will be raised when a connection is terminated
+    unexpectedly.
+    """
+
+    pass
+
+
+class InvalidFrameException(ConnectionTerminatedException):
+    """This exception will be raised when we received an invalid frame we
+    cannot parse.
+    """
+
+    pass
+
+
+class BadOperationException(Exception):
+    """This exception will be raised when send_message() is called on
+    server-terminated connection or receive_message() is called on
+    client-terminated connection.
+    """
+
+    pass
+
+
+class UnsupportedFrameException(Exception):
+    """This exception will be raised when we receive a frame with flag, opcode
+    we cannot handle. Handlers can just catch and ignore this exception and
+    call receive_message() again to continue processing the next frame.
+    """
+
+    pass
+
+
+class InvalidUTF8Exception(Exception):
+    """This exception will be raised when we receive a text frame which
+    contains invalid UTF-8 strings.
+    """
+
+    pass
+
+
+# vi:sts=4 sw=4 et
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/common.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/common.py
new file mode 100644
index 0000000..9cb11f1
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/common.py
@@ -0,0 +1,273 @@
+# Copyright 2012, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""This file must not depend on any module specific to the WebSocket protocol.
+"""
+
+from __future__ import absolute_import
+from mod_pywebsocket import http_header_util
+
+# Additional log level definitions.
+LOGLEVEL_FINE = 9
+
+# Constants indicating WebSocket protocol version.
+VERSION_HYBI13 = 13
+VERSION_HYBI14 = 13
+VERSION_HYBI15 = 13
+VERSION_HYBI16 = 13
+VERSION_HYBI17 = 13
+
+# Constants indicating WebSocket protocol latest version.
+VERSION_HYBI_LATEST = VERSION_HYBI13
+
+# Port numbers
+DEFAULT_WEB_SOCKET_PORT = 80
+DEFAULT_WEB_SOCKET_SECURE_PORT = 443
+
+# Schemes
+WEB_SOCKET_SCHEME = 'ws'
+WEB_SOCKET_SECURE_SCHEME = 'wss'
+
+# Frame opcodes defined in the spec.
+OPCODE_CONTINUATION = 0x0
+OPCODE_TEXT = 0x1
+OPCODE_BINARY = 0x2
+OPCODE_CLOSE = 0x8
+OPCODE_PING = 0x9
+OPCODE_PONG = 0xa
+
+# UUID for the opening handshake and frame masking.
+WEBSOCKET_ACCEPT_UUID = b'258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
+
+# Opening handshake header names and expected values.
+UPGRADE_HEADER = 'Upgrade'
+WEBSOCKET_UPGRADE_TYPE = 'websocket'
+CONNECTION_HEADER = 'Connection'
+UPGRADE_CONNECTION_TYPE = 'Upgrade'
+HOST_HEADER = 'Host'
+ORIGIN_HEADER = 'Origin'
+SEC_WEBSOCKET_KEY_HEADER = 'Sec-WebSocket-Key'
+SEC_WEBSOCKET_ACCEPT_HEADER = 'Sec-WebSocket-Accept'
+SEC_WEBSOCKET_VERSION_HEADER = 'Sec-WebSocket-Version'
+SEC_WEBSOCKET_PROTOCOL_HEADER = 'Sec-WebSocket-Protocol'
+SEC_WEBSOCKET_EXTENSIONS_HEADER = 'Sec-WebSocket-Extensions'
+
+# Extensions
+PERMESSAGE_DEFLATE_EXTENSION = 'permessage-deflate'
+
+# Status codes
+# Code STATUS_NO_STATUS_RECEIVED, STATUS_ABNORMAL_CLOSURE, and
+# STATUS_TLS_HANDSHAKE are pseudo codes to indicate specific error cases.
+# Could not be used for codes in actual closing frames.
+# Application level errors must use codes in the range
+# STATUS_USER_REGISTERED_BASE to STATUS_USER_PRIVATE_MAX. The codes in the
+# range STATUS_USER_REGISTERED_BASE to STATUS_USER_REGISTERED_MAX are managed
+# by IANA. Usually application must define user protocol level errors in the
+# range STATUS_USER_PRIVATE_BASE to STATUS_USER_PRIVATE_MAX.
+STATUS_NORMAL_CLOSURE = 1000
+STATUS_GOING_AWAY = 1001
+STATUS_PROTOCOL_ERROR = 1002
+STATUS_UNSUPPORTED_DATA = 1003
+STATUS_NO_STATUS_RECEIVED = 1005
+STATUS_ABNORMAL_CLOSURE = 1006
+STATUS_INVALID_FRAME_PAYLOAD_DATA = 1007
+STATUS_POLICY_VIOLATION = 1008
+STATUS_MESSAGE_TOO_BIG = 1009
+STATUS_MANDATORY_EXTENSION = 1010
+STATUS_INTERNAL_ENDPOINT_ERROR = 1011
+STATUS_TLS_HANDSHAKE = 1015
+STATUS_USER_REGISTERED_BASE = 3000
+STATUS_USER_REGISTERED_MAX = 3999
+STATUS_USER_PRIVATE_BASE = 4000
+STATUS_USER_PRIVATE_MAX = 4999
+# Following definitions are aliases to keep compatibility. Applications must
+# not use these obsoleted definitions anymore.
+STATUS_NORMAL = STATUS_NORMAL_CLOSURE
+STATUS_UNSUPPORTED = STATUS_UNSUPPORTED_DATA
+STATUS_CODE_NOT_AVAILABLE = STATUS_NO_STATUS_RECEIVED
+STATUS_ABNORMAL_CLOSE = STATUS_ABNORMAL_CLOSURE
+STATUS_INVALID_FRAME_PAYLOAD = STATUS_INVALID_FRAME_PAYLOAD_DATA
+STATUS_MANDATORY_EXT = STATUS_MANDATORY_EXTENSION
+
+# HTTP status codes
+HTTP_STATUS_BAD_REQUEST = 400
+HTTP_STATUS_FORBIDDEN = 403
+HTTP_STATUS_NOT_FOUND = 404
+
+
+def is_control_opcode(opcode):
+    return (opcode >> 3) == 1
+
+
+class ExtensionParameter(object):
+    """This is exchanged on extension negotiation in opening handshake."""
+    def __init__(self, name):
+        self._name = name
+        # TODO(tyoshino): Change the data structure to more efficient one such
+        # as dict when the spec changes to say like
+        # - Parameter names must be unique
+        # - The order of parameters is not significant
+        self._parameters = []
+
+    def name(self):
+        """Return the extension name."""
+        return self._name
+
+    def add_parameter(self, name, value):
+        """Add a parameter."""
+        self._parameters.append((name, value))
+
+    def get_parameters(self):
+        """Return the parameters."""
+        return self._parameters
+
+    def get_parameter_names(self):
+        """Return the names of the parameters."""
+        return [name for name, unused_value in self._parameters]
+
+    def has_parameter(self, name):
+        """Test if a parameter exists."""
+        for param_name, param_value in self._parameters:
+            if param_name == name:
+                return True
+        return False
+
+    def get_parameter_value(self, name):
+        """Get the value of a specific parameter."""
+        for param_name, param_value in self._parameters:
+            if param_name == name:
+                return param_value
+
+
+class ExtensionParsingException(Exception):
+    """Exception to handle errors in extension parsing."""
+    def __init__(self, name):
+        super(ExtensionParsingException, self).__init__(name)
+
+
+def _parse_extension_param(state, definition):
+    param_name = http_header_util.consume_token(state)
+
+    if param_name is None:
+        raise ExtensionParsingException('No valid parameter name found')
+
+    http_header_util.consume_lwses(state)
+
+    if not http_header_util.consume_string(state, '='):
+        definition.add_parameter(param_name, None)
+        return
+
+    http_header_util.consume_lwses(state)
+
+    # TODO(tyoshino): Add code to validate that parsed param_value is token
+    param_value = http_header_util.consume_token_or_quoted_string(state)
+    if param_value is None:
+        raise ExtensionParsingException(
+            'No valid parameter value found on the right-hand side of '
+            'parameter %r' % param_name)
+
+    definition.add_parameter(param_name, param_value)
+
+
+def _parse_extension(state):
+    extension_token = http_header_util.consume_token(state)
+    if extension_token is None:
+        return None
+
+    extension = ExtensionParameter(extension_token)
+
+    while True:
+        http_header_util.consume_lwses(state)
+
+        if not http_header_util.consume_string(state, ';'):
+            break
+
+        http_header_util.consume_lwses(state)
+
+        try:
+            _parse_extension_param(state, extension)
+        except ExtensionParsingException as e:
+            raise ExtensionParsingException(
+                'Failed to parse parameter for %r (%r)' % (extension_token, e))
+
+    return extension
+
+
+def parse_extensions(data):
+    """Parse Sec-WebSocket-Extensions header value.
+
+    Returns a list of ExtensionParameter objects.
+    Leading LWSes must be trimmed.
+    """
+    state = http_header_util.ParsingState(data)
+
+    extension_list = []
+    while True:
+        extension = _parse_extension(state)
+        if extension is not None:
+            extension_list.append(extension)
+
+        http_header_util.consume_lwses(state)
+
+        if http_header_util.peek(state) is None:
+            break
+
+        if not http_header_util.consume_string(state, ','):
+            raise ExtensionParsingException(
+                'Failed to parse Sec-WebSocket-Extensions header: '
+                'Expected a comma but found %r' % http_header_util.peek(state))
+
+        http_header_util.consume_lwses(state)
+
+    if len(extension_list) == 0:
+        raise ExtensionParsingException('No valid extension entry found')
+
+    return extension_list
+
+
+def format_extension(extension):
+    """Format an ExtensionParameter object."""
+    formatted_params = [extension.name()]
+    for param_name, param_value in extension.get_parameters():
+        if param_value is None:
+            formatted_params.append(param_name)
+        else:
+            quoted_value = http_header_util.quote_if_necessary(param_value)
+            formatted_params.append('%s=%s' % (param_name, quoted_value))
+    return '; '.join(formatted_params)
+
+
+def format_extensions(extension_list):
+    """Format a list of ExtensionParameter objects."""
+    formatted_extension_list = []
+    for extension in extension_list:
+        formatted_extension_list.append(format_extension(extension))
+    return ', '.join(formatted_extension_list)
+
+
+# vi:sts=4 sw=4 et
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/dispatch.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/dispatch.py
new file mode 100644
index 0000000..4ee943a5
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/dispatch.py
@@ -0,0 +1,385 @@
+# Copyright 2012, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""Dispatch WebSocket request.
+"""
+
+from __future__ import absolute_import
+import logging
+import os
+import re
+import traceback
+
+from mod_pywebsocket import common
+from mod_pywebsocket import handshake
+from mod_pywebsocket import msgutil
+from mod_pywebsocket import stream
+from mod_pywebsocket import util
+
+_SOURCE_PATH_PATTERN = re.compile(r'(?i)_wsh\.py$')
+_SOURCE_SUFFIX = '_wsh.py'
+_DO_EXTRA_HANDSHAKE_HANDLER_NAME = 'web_socket_do_extra_handshake'
+_TRANSFER_DATA_HANDLER_NAME = 'web_socket_transfer_data'
+_PASSIVE_CLOSING_HANDSHAKE_HANDLER_NAME = (
+    'web_socket_passive_closing_handshake')
+
+
+class DispatchException(Exception):
+    """Exception in dispatching WebSocket request."""
+    def __init__(self, name, status=common.HTTP_STATUS_NOT_FOUND):
+        super(DispatchException, self).__init__(name)
+        self.status = status
+
+
+def _default_passive_closing_handshake_handler(request):
+    """Default web_socket_passive_closing_handshake handler."""
+
+    return common.STATUS_NORMAL_CLOSURE, ''
+
+
+def _normalize_path(path):
+    """Normalize path.
+
+    Args:
+        path: the path to normalize.
+
+    Path is converted to the absolute path.
+    The input path can use either '\\' or '/' as the separator.
+    The normalized path always uses '/' regardless of the platform.
+    """
+
+    path = path.replace('\\', os.path.sep)
+    path = os.path.realpath(path)
+    path = path.replace('\\', '/')
+    return path
+
+
+def _create_path_to_resource_converter(base_dir):
+    """Returns a function that converts the path of a WebSocket handler source
+    file to a resource string by removing the path to the base directory from
+    its head, removing _SOURCE_SUFFIX from its tail, and replacing path
+    separators in it with '/'.
+
+    Args:
+        base_dir: the path to the base directory.
+    """
+
+    base_dir = _normalize_path(base_dir)
+
+    base_len = len(base_dir)
+    suffix_len = len(_SOURCE_SUFFIX)
+
+    def converter(path):
+        if not path.endswith(_SOURCE_SUFFIX):
+            return None
+        # _normalize_path must not be used because resolving symlink breaks
+        # following path check.
+        path = path.replace('\\', '/')
+        if not path.startswith(base_dir):
+            return None
+        return path[base_len:-suffix_len]
+
+    return converter
+
+
+def _enumerate_handler_file_paths(directory):
+    """Returns a generator that enumerates WebSocket Handler source file names
+    in the given directory.
+    """
+
+    for root, unused_dirs, files in os.walk(directory):
+        for base in files:
+            path = os.path.join(root, base)
+            if _SOURCE_PATH_PATTERN.search(path):
+                yield path
+
+
+class _HandlerSuite(object):
+    """A handler suite holder class."""
+    def __init__(self, do_extra_handshake, transfer_data,
+                 passive_closing_handshake):
+        self.do_extra_handshake = do_extra_handshake
+        self.transfer_data = transfer_data
+        self.passive_closing_handshake = passive_closing_handshake
+
+
+def _source_handler_file(handler_definition):
+    """Source a handler definition string.
+
+    Args:
+        handler_definition: a string containing Python statements that define
+                            handler functions.
+    """
+
+    global_dic = {}
+    try:
+        # This statement is gramatically different in python 2 and 3.
+        # Hence, yapf will complain about this. To overcome this, we disable
+        # yapf for this line.
+        exec(handler_definition, global_dic) # yapf: disable
+    except Exception:
+        raise DispatchException('Error in sourcing handler:' +
+                                traceback.format_exc())
+    passive_closing_handshake_handler = None
+    try:
+        passive_closing_handshake_handler = _extract_handler(
+            global_dic, _PASSIVE_CLOSING_HANDSHAKE_HANDLER_NAME)
+    except Exception:
+        passive_closing_handshake_handler = (
+            _default_passive_closing_handshake_handler)
+    return _HandlerSuite(
+        _extract_handler(global_dic, _DO_EXTRA_HANDSHAKE_HANDLER_NAME),
+        _extract_handler(global_dic, _TRANSFER_DATA_HANDLER_NAME),
+        passive_closing_handshake_handler)
+
+
+def _extract_handler(dic, name):
+    """Extracts a callable with the specified name from the given dictionary
+    dic.
+    """
+
+    if name not in dic:
+        raise DispatchException('%s is not defined.' % name)
+    handler = dic[name]
+    if not callable(handler):
+        raise DispatchException('%s is not callable.' % name)
+    return handler
+
+
+class Dispatcher(object):
+    """Dispatches WebSocket requests.
+
+    This class maintains a map from resource name to handlers.
+    """
+    def __init__(self,
+                 root_dir,
+                 scan_dir=None,
+                 allow_handlers_outside_root_dir=True):
+        """Construct an instance.
+
+        Args:
+            root_dir: The directory where handler definition files are
+                      placed.
+            scan_dir: The directory where handler definition files are
+                      searched. scan_dir must be a directory under root_dir,
+                      including root_dir itself.  If scan_dir is None,
+                      root_dir is used as scan_dir. scan_dir can be useful
+                      in saving scan time when root_dir contains many
+                      subdirectories.
+            allow_handlers_outside_root_dir: Scans handler files even if their
+                      canonical path is not under root_dir.
+        """
+
+        self._logger = util.get_class_logger(self)
+
+        self._handler_suite_map = {}
+        self._source_warnings = []
+        if scan_dir is None:
+            scan_dir = root_dir
+        if not os.path.realpath(scan_dir).startswith(
+                os.path.realpath(root_dir)):
+            raise DispatchException('scan_dir:%s must be a directory under '
+                                    'root_dir:%s.' % (scan_dir, root_dir))
+        self._source_handler_files_in_dir(root_dir, scan_dir,
+                                          allow_handlers_outside_root_dir)
+
+    def add_resource_path_alias(self, alias_resource_path,
+                                existing_resource_path):
+        """Add resource path alias.
+
+        Once added, request to alias_resource_path would be handled by
+        handler registered for existing_resource_path.
+
+        Args:
+            alias_resource_path: alias resource path
+            existing_resource_path: existing resource path
+        """
+        try:
+            handler_suite = self._handler_suite_map[existing_resource_path]
+            self._handler_suite_map[alias_resource_path] = handler_suite
+        except KeyError:
+            raise DispatchException('No handler for: %r' %
+                                    existing_resource_path)
+
+    def source_warnings(self):
+        """Return warnings in sourcing handlers."""
+
+        return self._source_warnings
+
+    def do_extra_handshake(self, request):
+        """Do extra checking in WebSocket handshake.
+
+        Select a handler based on request.uri and call its
+        web_socket_do_extra_handshake function.
+
+        Args:
+            request: mod_python request.
+
+        Raises:
+            DispatchException: when handler was not found
+            AbortedByUserException: when user handler abort connection
+            HandshakeException: when opening handshake failed
+        """
+
+        handler_suite = self.get_handler_suite(request.ws_resource)
+        if handler_suite is None:
+            raise DispatchException('No handler for: %r' % request.ws_resource)
+        do_extra_handshake_ = handler_suite.do_extra_handshake
+        try:
+            do_extra_handshake_(request)
+        except handshake.AbortedByUserException as e:
+            # Re-raise to tell the caller of this function to finish this
+            # connection without sending any error.
+            self._logger.debug('%s', traceback.format_exc())
+            raise
+        except Exception as e:
+            util.prepend_message_to_exception(
+                '%s raised exception for %s: ' %
+                (_DO_EXTRA_HANDSHAKE_HANDLER_NAME, request.ws_resource), e)
+            raise handshake.HandshakeException(e, common.HTTP_STATUS_FORBIDDEN)
+
+    def transfer_data(self, request):
+        """Let a handler transfer_data with a WebSocket client.
+
+        Select a handler based on request.ws_resource and call its
+        web_socket_transfer_data function.
+
+        Args:
+            request: mod_python request.
+
+        Raises:
+            DispatchException: when handler was not found
+            AbortedByUserException: when user handler abort connection
+        """
+
+        # TODO(tyoshino): Terminate underlying TCP connection if possible.
+        try:
+            handler_suite = self.get_handler_suite(request.ws_resource)
+            if handler_suite is None:
+                raise DispatchException('No handler for: %r' %
+                                        request.ws_resource)
+            transfer_data_ = handler_suite.transfer_data
+            transfer_data_(request)
+
+            if not request.server_terminated:
+                request.ws_stream.close_connection()
+        # Catch non-critical exceptions the handler didn't handle.
+        except handshake.AbortedByUserException as e:
+            self._logger.debug('%s', traceback.format_exc())
+            raise
+        except msgutil.BadOperationException as e:
+            self._logger.debug('%s', e)
+            request.ws_stream.close_connection(
+                common.STATUS_INTERNAL_ENDPOINT_ERROR)
+        except msgutil.InvalidFrameException as e:
+            # InvalidFrameException must be caught before
+            # ConnectionTerminatedException that catches InvalidFrameException.
+            self._logger.debug('%s', e)
+            request.ws_stream.close_connection(common.STATUS_PROTOCOL_ERROR)
+        except msgutil.UnsupportedFrameException as e:
+            self._logger.debug('%s', e)
+            request.ws_stream.close_connection(common.STATUS_UNSUPPORTED_DATA)
+        except stream.InvalidUTF8Exception as e:
+            self._logger.debug('%s', e)
+            request.ws_stream.close_connection(
+                common.STATUS_INVALID_FRAME_PAYLOAD_DATA)
+        except msgutil.ConnectionTerminatedException as e:
+            self._logger.debug('%s', e)
+        except Exception as e:
+            # Any other exceptions are forwarded to the caller of this
+            # function.
+            util.prepend_message_to_exception(
+                '%s raised exception for %s: ' %
+                (_TRANSFER_DATA_HANDLER_NAME, request.ws_resource), e)
+            raise
+
+    def passive_closing_handshake(self, request):
+        """Prepare code and reason for responding client initiated closing
+        handshake.
+        """
+
+        handler_suite = self.get_handler_suite(request.ws_resource)
+        if handler_suite is None:
+            return _default_passive_closing_handshake_handler(request)
+        return handler_suite.passive_closing_handshake(request)
+
+    def get_handler_suite(self, resource):
+        """Retrieves two handlers (one for extra handshake processing, and one
+        for data transfer) for the given request as a HandlerSuite object.
+        """
+
+        fragment = None
+        if '#' in resource:
+            resource, fragment = resource.split('#', 1)
+        if '?' in resource:
+            resource = resource.split('?', 1)[0]
+        handler_suite = self._handler_suite_map.get(resource)
+        if handler_suite and fragment:
+            raise DispatchException(
+                'Fragment identifiers MUST NOT be used on WebSocket URIs',
+                common.HTTP_STATUS_BAD_REQUEST)
+        return handler_suite
+
+    def _source_handler_files_in_dir(self, root_dir, scan_dir,
+                                     allow_handlers_outside_root_dir):
+        """Source all the handler source files in the scan_dir directory.
+
+        The resource path is determined relative to root_dir.
+        """
+
+        # We build a map from resource to handler code assuming that there's
+        # only one path from root_dir to scan_dir and it can be obtained by
+        # comparing realpath of them.
+
+        # Here we cannot use abspath. See
+        # https://bugs.webkit.org/show_bug.cgi?id=31603
+
+        convert = _create_path_to_resource_converter(root_dir)
+        scan_realpath = os.path.realpath(scan_dir)
+        root_realpath = os.path.realpath(root_dir)
+        for path in _enumerate_handler_file_paths(scan_realpath):
+            if (not allow_handlers_outside_root_dir and
+                (not os.path.realpath(path).startswith(root_realpath))):
+                self._logger.debug(
+                    'Canonical path of %s is not under root directory' % path)
+                continue
+            try:
+                with open(path) as handler_file:
+                    handler_suite = _source_handler_file(handler_file.read())
+            except DispatchException as e:
+                self._source_warnings.append('%s: %s' % (path, e))
+                continue
+            resource = convert(path)
+            if resource is None:
+                self._logger.debug('Path to resource conversion on %s failed' %
+                                   path)
+            else:
+                self._handler_suite_map[convert(path)] = handler_suite
+
+
+# vi:sts=4 sw=4 et
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/extensions.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/extensions.py
new file mode 100644
index 0000000..314a949
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/extensions.py
@@ -0,0 +1,474 @@
+# Copyright 2012, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from __future__ import absolute_import
+from mod_pywebsocket import common
+from mod_pywebsocket import util
+from mod_pywebsocket.http_header_util import quote_if_necessary
+
+# The list of available server side extension processor classes.
+_available_processors = {}
+
+
+class ExtensionProcessorInterface(object):
+    def __init__(self, request):
+        self._logger = util.get_class_logger(self)
+
+        self._request = request
+        self._active = True
+
+    def request(self):
+        return self._request
+
+    def name(self):
+        return None
+
+    def check_consistency_with_other_processors(self, processors):
+        pass
+
+    def set_active(self, active):
+        self._active = active
+
+    def is_active(self):
+        return self._active
+
+    def _get_extension_response_internal(self):
+        return None
+
+    def get_extension_response(self):
+        if not self._active:
+            self._logger.debug('Extension %s is deactivated', self.name())
+            return None
+
+        response = self._get_extension_response_internal()
+        if response is None:
+            self._active = False
+        return response
+
+    def _setup_stream_options_internal(self, stream_options):
+        pass
+
+    def setup_stream_options(self, stream_options):
+        if self._active:
+            self._setup_stream_options_internal(stream_options)
+
+
+def _log_outgoing_compression_ratio(logger, original_bytes, filtered_bytes,
+                                    average_ratio):
+    # Print inf when ratio is not available.
+    ratio = float('inf')
+    if original_bytes != 0:
+        ratio = float(filtered_bytes) / original_bytes
+
+    logger.debug('Outgoing compression ratio: %f (average: %f)' %
+                 (ratio, average_ratio))
+
+
+def _log_incoming_compression_ratio(logger, received_bytes, filtered_bytes,
+                                    average_ratio):
+    # Print inf when ratio is not available.
+    ratio = float('inf')
+    if filtered_bytes != 0:
+        ratio = float(received_bytes) / filtered_bytes
+
+    logger.debug('Incoming compression ratio: %f (average: %f)' %
+                 (ratio, average_ratio))
+
+
+def _parse_window_bits(bits):
+    """Return parsed integer value iff the given string conforms to the
+    grammar of the window bits extension parameters.
+    """
+
+    if bits is None:
+        raise ValueError('Value is required')
+
+    # For non integer values such as "10.0", ValueError will be raised.
+    int_bits = int(bits)
+
+    # First condition is to drop leading zero case e.g. "08".
+    if bits != str(int_bits) or int_bits < 8 or int_bits > 15:
+        raise ValueError('Invalid value: %r' % bits)
+
+    return int_bits
+
+
+class _AverageRatioCalculator(object):
+    """Stores total bytes of original and result data, and calculates average
+    result / original ratio.
+    """
+    def __init__(self):
+        self._total_original_bytes = 0
+        self._total_result_bytes = 0
+
+    def add_original_bytes(self, value):
+        self._total_original_bytes += value
+
+    def add_result_bytes(self, value):
+        self._total_result_bytes += value
+
+    def get_average_ratio(self):
+        if self._total_original_bytes != 0:
+            return (float(self._total_result_bytes) /
+                    self._total_original_bytes)
+        else:
+            return float('inf')
+
+
+class PerMessageDeflateExtensionProcessor(ExtensionProcessorInterface):
+    """permessage-deflate extension processor.
+
+    Specification:
+    http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-08
+    """
+
+    _SERVER_MAX_WINDOW_BITS_PARAM = 'server_max_window_bits'
+    _SERVER_NO_CONTEXT_TAKEOVER_PARAM = 'server_no_context_takeover'
+    _CLIENT_MAX_WINDOW_BITS_PARAM = 'client_max_window_bits'
+    _CLIENT_NO_CONTEXT_TAKEOVER_PARAM = 'client_no_context_takeover'
+
+    def __init__(self, request):
+        """Construct PerMessageDeflateExtensionProcessor."""
+
+        ExtensionProcessorInterface.__init__(self, request)
+        self._logger = util.get_class_logger(self)
+
+        self._preferred_client_max_window_bits = None
+        self._client_no_context_takeover = False
+
+    def name(self):
+        # This method returns "deflate" (not "permessage-deflate") for
+        # compatibility.
+        return 'deflate'
+
+    def _get_extension_response_internal(self):
+        for name in self._request.get_parameter_names():
+            if name not in [
+                    self._SERVER_MAX_WINDOW_BITS_PARAM,
+                    self._SERVER_NO_CONTEXT_TAKEOVER_PARAM,
+                    self._CLIENT_MAX_WINDOW_BITS_PARAM
+            ]:
+                self._logger.debug('Unknown parameter: %r', name)
+                return None
+
+        server_max_window_bits = None
+        if self._request.has_parameter(self._SERVER_MAX_WINDOW_BITS_PARAM):
+            server_max_window_bits = self._request.get_parameter_value(
+                self._SERVER_MAX_WINDOW_BITS_PARAM)
+            try:
+                server_max_window_bits = _parse_window_bits(
+                    server_max_window_bits)
+            except ValueError as e:
+                self._logger.debug('Bad %s parameter: %r',
+                                   self._SERVER_MAX_WINDOW_BITS_PARAM, e)
+                return None
+
+        server_no_context_takeover = self._request.has_parameter(
+            self._SERVER_NO_CONTEXT_TAKEOVER_PARAM)
+        if (server_no_context_takeover and self._request.get_parameter_value(
+                self._SERVER_NO_CONTEXT_TAKEOVER_PARAM) is not None):
+            self._logger.debug('%s parameter must not have a value: %r',
+                               self._SERVER_NO_CONTEXT_TAKEOVER_PARAM,
+                               server_no_context_takeover)
+            return None
+
+        # client_max_window_bits from a client indicates whether the client can
+        # accept client_max_window_bits from a server or not.
+        client_client_max_window_bits = self._request.has_parameter(
+            self._CLIENT_MAX_WINDOW_BITS_PARAM)
+        if (client_client_max_window_bits
+                and self._request.get_parameter_value(
+                    self._CLIENT_MAX_WINDOW_BITS_PARAM) is not None):
+            self._logger.debug(
+                '%s parameter must not have a value in a '
+                'client\'s opening handshake: %r',
+                self._CLIENT_MAX_WINDOW_BITS_PARAM,
+                client_client_max_window_bits)
+            return None
+
+        self._rfc1979_deflater = util._RFC1979Deflater(
+            server_max_window_bits, server_no_context_takeover)
+
+        # Note that we prepare for incoming messages compressed with window
+        # bits upto 15 regardless of the client_max_window_bits value to be
+        # sent to the client.
+        self._rfc1979_inflater = util._RFC1979Inflater()
+
+        self._framer = _PerMessageDeflateFramer(server_max_window_bits,
+                                                server_no_context_takeover)
+        self._framer.set_bfinal(False)
+        self._framer.set_compress_outgoing_enabled(True)
+
+        response = common.ExtensionParameter(self._request.name())
+
+        if server_max_window_bits is not None:
+            response.add_parameter(self._SERVER_MAX_WINDOW_BITS_PARAM,
+                                   str(server_max_window_bits))
+
+        if server_no_context_takeover:
+            response.add_parameter(self._SERVER_NO_CONTEXT_TAKEOVER_PARAM,
+                                   None)
+
+        if self._preferred_client_max_window_bits is not None:
+            if not client_client_max_window_bits:
+                self._logger.debug(
+                    'Processor is configured to use %s but '
+                    'the client cannot accept it',
+                    self._CLIENT_MAX_WINDOW_BITS_PARAM)
+                return None
+            response.add_parameter(self._CLIENT_MAX_WINDOW_BITS_PARAM,
+                                   str(self._preferred_client_max_window_bits))
+
+        if self._client_no_context_takeover:
+            response.add_parameter(self._CLIENT_NO_CONTEXT_TAKEOVER_PARAM,
+                                   None)
+
+        self._logger.debug('Enable %s extension ('
+                           'request: server_max_window_bits=%s; '
+                           'server_no_context_takeover=%r, '
+                           'response: client_max_window_bits=%s; '
+                           'client_no_context_takeover=%r)' %
+                           (self._request.name(), server_max_window_bits,
+                            server_no_context_takeover,
+                            self._preferred_client_max_window_bits,
+                            self._client_no_context_takeover))
+
+        return response
+
+    def _setup_stream_options_internal(self, stream_options):
+        self._framer.setup_stream_options(stream_options)
+
+    def set_client_max_window_bits(self, value):
+        """If this option is specified, this class adds the
+        client_max_window_bits extension parameter to the handshake response,
+        but doesn't reduce the LZ77 sliding window size of its inflater.
+        I.e., you can use this for testing client implementation but cannot
+        reduce memory usage of this class.
+
+        If this method has been called with True and an offer without the
+        client_max_window_bits extension parameter is received,
+
+        - (When processing the permessage-deflate extension) this processor
+          declines the request.
+        - (When processing the permessage-compress extension) this processor
+          accepts the request.
+        """
+
+        self._preferred_client_max_window_bits = value
+
+    def set_client_no_context_takeover(self, value):
+        """If this option is specified, this class adds the
+        client_no_context_takeover extension parameter to the handshake
+        response, but doesn't reset inflater for each message. I.e., you can
+        use this for testing client implementation but cannot reduce memory
+        usage of this class.
+        """
+
+        self._client_no_context_takeover = value
+
+    def set_bfinal(self, value):
+        self._framer.set_bfinal(value)
+
+    def enable_outgoing_compression(self):
+        self._framer.set_compress_outgoing_enabled(True)
+
+    def disable_outgoing_compression(self):
+        self._framer.set_compress_outgoing_enabled(False)
+
+
+class _PerMessageDeflateFramer(object):
+    """A framer for extensions with per-message DEFLATE feature."""
+    def __init__(self, deflate_max_window_bits, deflate_no_context_takeover):
+        self._logger = util.get_class_logger(self)
+
+        self._rfc1979_deflater = util._RFC1979Deflater(
+            deflate_max_window_bits, deflate_no_context_takeover)
+
+        self._rfc1979_inflater = util._RFC1979Inflater()
+
+        self._bfinal = False
+
+        self._compress_outgoing_enabled = False
+
+        # True if a message is fragmented and compression is ongoing.
+        self._compress_ongoing = False
+
+        # Calculates
+        #     (Total outgoing bytes supplied to this filter) /
+        #     (Total bytes sent to the network after applying this filter)
+        self._outgoing_average_ratio_calculator = _AverageRatioCalculator()
+
+        # Calculates
+        #     (Total bytes received from the network) /
+        #     (Total incoming bytes obtained after applying this filter)
+        self._incoming_average_ratio_calculator = _AverageRatioCalculator()
+
+    def set_bfinal(self, value):
+        self._bfinal = value
+
+    def set_compress_outgoing_enabled(self, value):
+        self._compress_outgoing_enabled = value
+
+    def _process_incoming_message(self, message, decompress):
+        if not decompress:
+            return message
+
+        received_payload_size = len(message)
+        self._incoming_average_ratio_calculator.add_result_bytes(
+            received_payload_size)
+
+        message = self._rfc1979_inflater.filter(message)
+
+        filtered_payload_size = len(message)
+        self._incoming_average_ratio_calculator.add_original_bytes(
+            filtered_payload_size)
+
+        _log_incoming_compression_ratio(
+            self._logger, received_payload_size, filtered_payload_size,
+            self._incoming_average_ratio_calculator.get_average_ratio())
+
+        return message
+
+    def _process_outgoing_message(self, message, end, binary):
+        if not binary:
+            message = message.encode('utf-8')
+
+        if not self._compress_outgoing_enabled:
+            return message
+
+        original_payload_size = len(message)
+        self._outgoing_average_ratio_calculator.add_original_bytes(
+            original_payload_size)
+
+        message = self._rfc1979_deflater.filter(message,
+                                                end=end,
+                                                bfinal=self._bfinal)
+
+        filtered_payload_size = len(message)
+        self._outgoing_average_ratio_calculator.add_result_bytes(
+            filtered_payload_size)
+
+        _log_outgoing_compression_ratio(
+            self._logger, original_payload_size, filtered_payload_size,
+            self._outgoing_average_ratio_calculator.get_average_ratio())
+
+        if not self._compress_ongoing:
+            self._outgoing_frame_filter.set_compression_bit()
+        self._compress_ongoing = not end
+        return message
+
+    def _process_incoming_frame(self, frame):
+        if frame.rsv1 == 1 and not common.is_control_opcode(frame.opcode):
+            self._incoming_message_filter.decompress_next_message()
+            frame.rsv1 = 0
+
+    def _process_outgoing_frame(self, frame, compression_bit):
+        if (not compression_bit or common.is_control_opcode(frame.opcode)):
+            return
+
+        frame.rsv1 = 1
+
+    def setup_stream_options(self, stream_options):
+        """Creates filters and sets them to the StreamOptions."""
+        class _OutgoingMessageFilter(object):
+            def __init__(self, parent):
+                self._parent = parent
+
+            def filter(self, message, end=True, binary=False):
+                return self._parent._process_outgoing_message(
+                    message, end, binary)
+
+        class _IncomingMessageFilter(object):
+            def __init__(self, parent):
+                self._parent = parent
+                self._decompress_next_message = False
+
+            def decompress_next_message(self):
+                self._decompress_next_message = True
+
+            def filter(self, message):
+                message = self._parent._process_incoming_message(
+                    message, self._decompress_next_message)
+                self._decompress_next_message = False
+                return message
+
+        self._outgoing_message_filter = _OutgoingMessageFilter(self)
+        self._incoming_message_filter = _IncomingMessageFilter(self)
+        stream_options.outgoing_message_filters.append(
+            self._outgoing_message_filter)
+        stream_options.incoming_message_filters.append(
+            self._incoming_message_filter)
+
+        class _OutgoingFrameFilter(object):
+            def __init__(self, parent):
+                self._parent = parent
+                self._set_compression_bit = False
+
+            def set_compression_bit(self):
+                self._set_compression_bit = True
+
+            def filter(self, frame):
+                self._parent._process_outgoing_frame(frame,
+                                                     self._set_compression_bit)
+                self._set_compression_bit = False
+
+        class _IncomingFrameFilter(object):
+            def __init__(self, parent):
+                self._parent = parent
+
+            def filter(self, frame):
+                self._parent._process_incoming_frame(frame)
+
+        self._outgoing_frame_filter = _OutgoingFrameFilter(self)
+        self._incoming_frame_filter = _IncomingFrameFilter(self)
+        stream_options.outgoing_frame_filters.append(
+            self._outgoing_frame_filter)
+        stream_options.incoming_frame_filters.append(
+            self._incoming_frame_filter)
+
+        stream_options.encode_text_message_to_utf8 = False
+
+
+_available_processors[common.PERMESSAGE_DEFLATE_EXTENSION] = (
+    PerMessageDeflateExtensionProcessor)
+
+
+def get_extension_processor(extension_request):
+    """Given an ExtensionParameter representing an extension offer received
+    from a client, configures and returns an instance of the corresponding
+    extension processor class.
+    """
+
+    processor_class = _available_processors.get(extension_request.name())
+    if processor_class is None:
+        return None
+    return processor_class(extension_request)
+
+
+# vi:sts=4 sw=4 et
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/fast_masking.i b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/fast_masking.i
new file mode 100644
index 0000000..ddaad27
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/fast_masking.i
@@ -0,0 +1,98 @@
+// Copyright 2013, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+%module fast_masking
+
+%include "cstring.i"
+
+%{
+#include <cstring>
+
+#ifdef __SSE2__
+#include <emmintrin.h>
+#endif
+%}
+
+%apply (char *STRING, int LENGTH) {
+    (const char* payload, int payload_length),
+    (const char* masking_key, int masking_key_length) };
+%cstring_output_allocate_size(
+    char** result, int* result_length, delete [] *$1);
+
+%inline %{
+
+void mask(
+    const char* payload, int payload_length,
+    const char* masking_key, int masking_key_length,
+    int masking_key_index,
+    char** result, int* result_length) {
+  *result = new char[payload_length];
+  *result_length = payload_length;
+  memcpy(*result, payload, payload_length);
+
+  char* cursor = *result;
+  char* cursor_end = *result + *result_length;
+
+#ifdef __SSE2__
+  while ((cursor < cursor_end) &&
+         (reinterpret_cast<size_t>(cursor) & 0xf)) {
+    *cursor ^= masking_key[masking_key_index];
+    ++cursor;
+    masking_key_index = (masking_key_index + 1) % masking_key_length;
+  }
+  if (cursor == cursor_end) {
+    return;
+  }
+
+  const int kBlockSize = 16;
+  __m128i masking_key_block;
+  for (int i = 0; i < kBlockSize; ++i) {
+    *(reinterpret_cast<char*>(&masking_key_block) + i) =
+        masking_key[masking_key_index];
+    masking_key_index = (masking_key_index + 1) % masking_key_length;
+  }
+
+  while (cursor + kBlockSize <= cursor_end) {
+    __m128i payload_block =
+        _mm_load_si128(reinterpret_cast<__m128i*>(cursor));
+    _mm_stream_si128(reinterpret_cast<__m128i*>(cursor),
+                     _mm_xor_si128(payload_block, masking_key_block));
+    cursor += kBlockSize;
+  }
+#endif
+
+  while (cursor < cursor_end) {
+    *cursor ^= masking_key[masking_key_index];
+    ++cursor;
+    masking_key_index = (masking_key_index + 1) % masking_key_length;
+  }
+}
+
+%}
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/__init__.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/__init__.py
new file mode 100644
index 0000000..82be5ae9f
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/__init__.py
@@ -0,0 +1,101 @@
+# Copyright 2011, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""WebSocket opening handshake processor. This class try to apply available
+opening handshake processors for each protocol version until a connection is
+successfully established.
+"""
+
+from __future__ import absolute_import
+import logging
+
+from mod_pywebsocket import common
+from mod_pywebsocket.handshake import hybi
+# Export AbortedByUserException, HandshakeException, and VersionException
+# symbol from this module.
+from mod_pywebsocket.handshake._base import AbortedByUserException
+from mod_pywebsocket.handshake._base import HandshakeException
+from mod_pywebsocket.handshake._base import VersionException
+
+_LOGGER = logging.getLogger(__name__)
+
+
+def do_handshake(request, dispatcher):
+    """Performs WebSocket handshake.
+
+    Args:
+        request: mod_python request.
+        dispatcher: Dispatcher (dispatch.Dispatcher).
+
+    Handshaker will add attributes such as ws_resource in performing
+    handshake.
+    """
+
+    _LOGGER.debug('Client\'s opening handshake resource: %r', request.uri)
+    # To print mimetools.Message as escaped one-line string, we converts
+    # headers_in to dict object. Without conversion, if we use %r, it just
+    # prints the type and address, and if we use %s, it prints the original
+    # header string as multiple lines.
+    #
+    # Both mimetools.Message and MpTable_Type of mod_python can be
+    # converted to dict.
+    #
+    # mimetools.Message.__str__ returns the original header string.
+    # dict(mimetools.Message object) returns the map from header names to
+    # header values. While MpTable_Type doesn't have such __str__ but just
+    # __repr__ which formats itself as well as dictionary object.
+    _LOGGER.debug('Client\'s opening handshake headers: %r',
+                  dict(request.headers_in))
+
+    handshakers = []
+    handshakers.append(('RFC 6455', hybi.Handshaker(request, dispatcher)))
+
+    for name, handshaker in handshakers:
+        _LOGGER.debug('Trying protocol version %s', name)
+        try:
+            handshaker.do_handshake()
+            _LOGGER.info('Established (%s protocol)', name)
+            return
+        except HandshakeException as e:
+            _LOGGER.debug(
+                'Failed to complete opening handshake as %s protocol: %r',
+                name, e)
+            if e.status:
+                raise e
+        except AbortedByUserException as e:
+            raise
+        except VersionException as e:
+            raise
+
+    # TODO(toyoshim): Add a test to cover the case all handshakers fail.
+    raise HandshakeException(
+        'Failed to complete opening handshake for all available protocols',
+        status=common.HTTP_STATUS_BAD_REQUEST)
+
+
+# vi:sts=4 sw=4 et
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/_base.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/_base.py
new file mode 100644
index 0000000..358dd8d4
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/_base.py
@@ -0,0 +1,179 @@
+# Copyright 2012, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""Common functions and exceptions used by WebSocket opening handshake
+processors.
+"""
+
+from __future__ import absolute_import
+from mod_pywebsocket import common
+from mod_pywebsocket import http_header_util
+
+
+class AbortedByUserException(Exception):
+    """Exception for aborting a connection intentionally.
+
+    If this exception is raised in do_extra_handshake handler, the connection
+    will be abandoned. No other WebSocket or HTTP(S) handler will be invoked.
+
+    If this exception is raised in transfer_data_handler, the connection will
+    be closed without closing handshake. No other WebSocket or HTTP(S) handler
+    will be invoked.
+    """
+
+    pass
+
+
+class HandshakeException(Exception):
+    """This exception will be raised when an error occurred while processing
+    WebSocket initial handshake.
+    """
+    def __init__(self, name, status=None):
+        super(HandshakeException, self).__init__(name)
+        self.status = status
+
+
+class VersionException(Exception):
+    """This exception will be raised when a version of client request does not
+    match with version the server supports.
+    """
+    def __init__(self, name, supported_versions=''):
+        """Construct an instance.
+
+        Args:
+            supported_version: a str object to show supported hybi versions.
+                               (e.g. '13')
+        """
+        super(VersionException, self).__init__(name)
+        self.supported_versions = supported_versions
+
+
+def get_default_port(is_secure):
+    if is_secure:
+        return common.DEFAULT_WEB_SOCKET_SECURE_PORT
+    else:
+        return common.DEFAULT_WEB_SOCKET_PORT
+
+
+def validate_subprotocol(subprotocol):
+    """Validate a value in the Sec-WebSocket-Protocol field.
+
+    See the Section 4.1., 4.2.2., and 4.3. of RFC 6455.
+    """
+
+    if not subprotocol:
+        raise HandshakeException('Invalid subprotocol name: empty')
+
+    # Parameter should be encoded HTTP token.
+    state = http_header_util.ParsingState(subprotocol)
+    token = http_header_util.consume_token(state)
+    rest = http_header_util.peek(state)
+    # If |rest| is not None, |subprotocol| is not one token or invalid. If
+    # |rest| is None, |token| must not be None because |subprotocol| is
+    # concatenation of |token| and |rest| and is not None.
+    if rest is not None:
+        raise HandshakeException('Invalid non-token string in subprotocol '
+                                 'name: %r' % rest)
+
+
+def parse_host_header(request):
+    fields = request.headers_in[common.HOST_HEADER].split(':', 1)
+    if len(fields) == 1:
+        return fields[0], get_default_port(request.is_https())
+    try:
+        return fields[0], int(fields[1])
+    except ValueError as e:
+        raise HandshakeException('Invalid port number format: %r' % e)
+
+
+def format_header(name, value):
+    return u'%s: %s\r\n' % (name, value)
+
+
+def get_mandatory_header(request, key):
+    value = request.headers_in.get(key)
+    if value is None:
+        raise HandshakeException('Header %s is not defined' % key)
+    return value
+
+
+def validate_mandatory_header(request, key, expected_value, fail_status=None):
+    value = get_mandatory_header(request, key)
+
+    if value.lower() != expected_value.lower():
+        raise HandshakeException(
+            'Expected %r for header %s but found %r (case-insensitive)' %
+            (expected_value, key, value),
+            status=fail_status)
+
+
+def check_request_line(request):
+    # 5.1 1. The three character UTF-8 string "GET".
+    # 5.1 2. A UTF-8-encoded U+0020 SPACE character (0x20 byte).
+    if request.method != u'GET':
+        raise HandshakeException('Method is not GET: %r' % request.method)
+
+    if request.protocol != u'HTTP/1.1':
+        raise HandshakeException('Version is not HTTP/1.1: %r' %
+                                 request.protocol)
+
+
+def parse_token_list(data):
+    """Parses a header value which follows 1#token and returns parsed elements
+    as a list of strings.
+
+    Leading LWSes must be trimmed.
+    """
+
+    state = http_header_util.ParsingState(data)
+
+    token_list = []
+
+    while True:
+        token = http_header_util.consume_token(state)
+        if token is not None:
+            token_list.append(token)
+
+        http_header_util.consume_lwses(state)
+
+        if http_header_util.peek(state) is None:
+            break
+
+        if not http_header_util.consume_string(state, ','):
+            raise HandshakeException('Expected a comma but found %r' %
+                                     http_header_util.peek(state))
+
+        http_header_util.consume_lwses(state)
+
+    if len(token_list) == 0:
+        raise HandshakeException('No valid token found')
+
+    return token_list
+
+
+# vi:sts=4 sw=4 et
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/hybi.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/hybi.py
new file mode 100644
index 0000000..7fd63eb
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/handshake/hybi.py
@@ -0,0 +1,395 @@
+# Copyright 2012, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""This file provides the opening handshake processor for the WebSocket
+protocol (RFC 6455).
+
+Specification:
+http://tools.ietf.org/html/rfc6455
+"""
+
+from __future__ import absolute_import
+import base64
+import logging
+import os
+import re
+from hashlib import sha1
+
+from mod_pywebsocket import common
+from mod_pywebsocket.extensions import get_extension_processor
+from mod_pywebsocket.handshake._base import check_request_line
+from mod_pywebsocket.handshake._base import format_header
+from mod_pywebsocket.handshake._base import get_mandatory_header
+from mod_pywebsocket.handshake._base import HandshakeException
+from mod_pywebsocket.handshake._base import parse_token_list
+from mod_pywebsocket.handshake._base import validate_mandatory_header
+from mod_pywebsocket.handshake._base import validate_subprotocol
+from mod_pywebsocket.handshake._base import VersionException
+from mod_pywebsocket.stream import Stream
+from mod_pywebsocket.stream import StreamOptions
+from mod_pywebsocket import util
+from six.moves import map
+from six.moves import range
+
+# Used to validate the value in the Sec-WebSocket-Key header strictly. RFC 4648
+# disallows non-zero padding, so the character right before == must be any of
+# A, Q, g and w.
+_SEC_WEBSOCKET_KEY_REGEX = re.compile('^[+/0-9A-Za-z]{21}[AQgw]==$')
+
+# Defining aliases for values used frequently.
+_VERSION_LATEST = common.VERSION_HYBI_LATEST
+_VERSION_LATEST_STRING = str(_VERSION_LATEST)
+_SUPPORTED_VERSIONS = [
+    _VERSION_LATEST,
+]
+
+
+def compute_accept(key):
+    """Computes value for the Sec-WebSocket-Accept header from value of the
+    Sec-WebSocket-Key header.
+    """
+
+    accept_binary = sha1(key + common.WEBSOCKET_ACCEPT_UUID).digest()
+    accept = base64.b64encode(accept_binary)
+
+    return accept
+
+
+def compute_accept_from_unicode(unicode_key):
+    """A wrapper function for compute_accept which takes a unicode string as an
+    argument, and encodes it to byte string. It then passes it on to
+    compute_accept.
+    """
+
+    key = unicode_key.encode('UTF-8')
+    return compute_accept(key)
+
+
+class Handshaker(object):
+    """Opening handshake processor for the WebSocket protocol (RFC 6455)."""
+    def __init__(self, request, dispatcher):
+        """Construct an instance.
+
+        Args:
+            request: mod_python request.
+            dispatcher: Dispatcher (dispatch.Dispatcher).
+
+        Handshaker will add attributes such as ws_resource during handshake.
+        """
+
+        self._logger = util.get_class_logger(self)
+
+        self._request = request
+        self._dispatcher = dispatcher
+
+    def _validate_connection_header(self):
+        connection = get_mandatory_header(self._request,
+                                          common.CONNECTION_HEADER)
+
+        try:
+            connection_tokens = parse_token_list(connection)
+        except HandshakeException as e:
+            raise HandshakeException('Failed to parse %s: %s' %
+                                     (common.CONNECTION_HEADER, e))
+
+        connection_is_valid = False
+        for token in connection_tokens:
+            if token.lower() == common.UPGRADE_CONNECTION_TYPE.lower():
+                connection_is_valid = True
+                break
+        if not connection_is_valid:
+            raise HandshakeException(
+                '%s header doesn\'t contain "%s"' %
+                (common.CONNECTION_HEADER, common.UPGRADE_CONNECTION_TYPE))
+
+    def do_handshake(self):
+        self._request.ws_close_code = None
+        self._request.ws_close_reason = None
+
+        # Parsing.
+
+        check_request_line(self._request)
+
+        validate_mandatory_header(self._request, common.UPGRADE_HEADER,
+                                  common.WEBSOCKET_UPGRADE_TYPE)
+
+        self._validate_connection_header()
+
+        self._request.ws_resource = self._request.uri
+
+        unused_host = get_mandatory_header(self._request, common.HOST_HEADER)
+
+        self._request.ws_version = self._check_version()
+
+        try:
+            self._get_origin()
+            self._set_protocol()
+            self._parse_extensions()
+
+            # Key validation, response generation.
+
+            key = self._get_key()
+            accept = compute_accept(key)
+            self._logger.debug('%s: %r (%s)',
+                               common.SEC_WEBSOCKET_ACCEPT_HEADER, accept,
+                               util.hexify(base64.b64decode(accept)))
+
+            self._logger.debug('Protocol version is RFC 6455')
+
+            # Setup extension processors.
+
+            processors = []
+            if self._request.ws_requested_extensions is not None:
+                for extension_request in self._request.ws_requested_extensions:
+                    processor = get_extension_processor(extension_request)
+                    # Unknown extension requests are just ignored.
+                    if processor is not None:
+                        processors.append(processor)
+            self._request.ws_extension_processors = processors
+
+            # List of extra headers. The extra handshake handler may add header
+            # data as name/value pairs to this list and pywebsocket appends
+            # them to the WebSocket handshake.
+            self._request.extra_headers = []
+
+            # Extra handshake handler may modify/remove processors.
+            self._dispatcher.do_extra_handshake(self._request)
+            processors = [
+                processor
+                for processor in self._request.ws_extension_processors
+                if processor is not None
+            ]
+
+            # Ask each processor if there are extensions on the request which
+            # cannot co-exist. When processor decided other processors cannot
+            # co-exist with it, the processor marks them (or itself) as
+            # "inactive". The first extension processor has the right to
+            # make the final call.
+            for processor in reversed(processors):
+                if processor.is_active():
+                    processor.check_consistency_with_other_processors(
+                        processors)
+            processors = [
+                processor for processor in processors if processor.is_active()
+            ]
+
+            accepted_extensions = []
+
+            stream_options = StreamOptions()
+
+            for index, processor in enumerate(processors):
+                if not processor.is_active():
+                    continue
+
+                extension_response = processor.get_extension_response()
+                if extension_response is None:
+                    # Rejected.
+                    continue
+
+                accepted_extensions.append(extension_response)
+
+                processor.setup_stream_options(stream_options)
+
+                # Inactivate all of the following compression extensions.
+                for j in range(index + 1, len(processors)):
+                    processors[j].set_active(False)
+
+            if len(accepted_extensions) > 0:
+                self._request.ws_extensions = accepted_extensions
+                self._logger.debug(
+                    'Extensions accepted: %r',
+                    list(
+                        map(common.ExtensionParameter.name,
+                            accepted_extensions)))
+            else:
+                self._request.ws_extensions = None
+
+            self._request.ws_stream = self._create_stream(stream_options)
+
+            if self._request.ws_requested_protocols is not None:
+                if self._request.ws_protocol is None:
+                    raise HandshakeException(
+                        'do_extra_handshake must choose one subprotocol from '
+                        'ws_requested_protocols and set it to ws_protocol')
+                validate_subprotocol(self._request.ws_protocol)
+
+                self._logger.debug('Subprotocol accepted: %r',
+                                   self._request.ws_protocol)
+            else:
+                if self._request.ws_protocol is not None:
+                    raise HandshakeException(
+                        'ws_protocol must be None when the client didn\'t '
+                        'request any subprotocol')
+
+            self._send_handshake(accept)
+        except HandshakeException as e:
+            if not e.status:
+                # Fallback to 400 bad request by default.
+                e.status = common.HTTP_STATUS_BAD_REQUEST
+            raise e
+
+    def _get_origin(self):
+        origin_header = common.ORIGIN_HEADER
+        origin = self._request.headers_in.get(origin_header)
+        if origin is None:
+            self._logger.debug('Client request does not have origin header')
+        self._request.ws_origin = origin
+
+    def _check_version(self):
+        version = get_mandatory_header(self._request,
+                                       common.SEC_WEBSOCKET_VERSION_HEADER)
+        if version == _VERSION_LATEST_STRING:
+            return _VERSION_LATEST
+
+        if version.find(',') >= 0:
+            raise HandshakeException(
+                'Multiple versions (%r) are not allowed for header %s' %
+                (version, common.SEC_WEBSOCKET_VERSION_HEADER),
+                status=common.HTTP_STATUS_BAD_REQUEST)
+        raise VersionException('Unsupported version %r for header %s' %
+                               (version, common.SEC_WEBSOCKET_VERSION_HEADER),
+                               supported_versions=', '.join(
+                                   map(str, _SUPPORTED_VERSIONS)))
+
+    def _set_protocol(self):
+        self._request.ws_protocol = None
+
+        protocol_header = self._request.headers_in.get(
+            common.SEC_WEBSOCKET_PROTOCOL_HEADER)
+
+        if protocol_header is None:
+            self._request.ws_requested_protocols = None
+            return
+
+        self._request.ws_requested_protocols = parse_token_list(
+            protocol_header)
+        self._logger.debug('Subprotocols requested: %r',
+                           self._request.ws_requested_protocols)
+
+    def _parse_extensions(self):
+        extensions_header = self._request.headers_in.get(
+            common.SEC_WEBSOCKET_EXTENSIONS_HEADER)
+        if not extensions_header:
+            self._request.ws_requested_extensions = None
+            return
+
+        try:
+            self._request.ws_requested_extensions = common.parse_extensions(
+                extensions_header)
+        except common.ExtensionParsingException as e:
+            raise HandshakeException(
+                'Failed to parse Sec-WebSocket-Extensions header: %r' % e)
+
+        self._logger.debug(
+            'Extensions requested: %r',
+            list(
+                map(common.ExtensionParameter.name,
+                    self._request.ws_requested_extensions)))
+
+    def _validate_key(self, key):
+        if key.find(',') >= 0:
+            raise HandshakeException('Request has multiple %s header lines or '
+                                     'contains illegal character \',\': %r' %
+                                     (common.SEC_WEBSOCKET_KEY_HEADER, key))
+
+        # Validate
+        key_is_valid = False
+        try:
+            # Validate key by quick regex match before parsing by base64
+            # module. Because base64 module skips invalid characters, we have
+            # to do this in advance to make this server strictly reject illegal
+            # keys.
+            if _SEC_WEBSOCKET_KEY_REGEX.match(key):
+                decoded_key = base64.b64decode(key)
+                if len(decoded_key) == 16:
+                    key_is_valid = True
+        except TypeError as e:
+            pass
+
+        if not key_is_valid:
+            raise HandshakeException('Illegal value for header %s: %r' %
+                                     (common.SEC_WEBSOCKET_KEY_HEADER, key))
+
+        return decoded_key
+
+    def _get_key(self):
+        key = get_mandatory_header(self._request,
+                                   common.SEC_WEBSOCKET_KEY_HEADER)
+
+        decoded_key = self._validate_key(key)
+
+        self._logger.debug('%s: %r (%s)', common.SEC_WEBSOCKET_KEY_HEADER, key,
+                           util.hexify(decoded_key))
+
+        return key.encode('UTF-8')
+
+    def _create_stream(self, stream_options):
+        return Stream(self._request, stream_options)
+
+    def _create_handshake_response(self, accept):
+        response = []
+
+        response.append(u'HTTP/1.1 101 Switching Protocols\r\n')
+
+        # WebSocket headers
+        response.append(
+            format_header(common.UPGRADE_HEADER,
+                          common.WEBSOCKET_UPGRADE_TYPE))
+        response.append(
+            format_header(common.CONNECTION_HEADER,
+                          common.UPGRADE_CONNECTION_TYPE))
+        response.append(
+            format_header(common.SEC_WEBSOCKET_ACCEPT_HEADER,
+                          accept.decode('UTF-8')))
+        if self._request.ws_protocol is not None:
+            response.append(
+                format_header(common.SEC_WEBSOCKET_PROTOCOL_HEADER,
+                              self._request.ws_protocol))
+        if (self._request.ws_extensions is not None
+                and len(self._request.ws_extensions) != 0):
+            response.append(
+                format_header(
+                    common.SEC_WEBSOCKET_EXTENSIONS_HEADER,
+                    common.format_extensions(self._request.ws_extensions)))
+
+        # Headers not specific for WebSocket
+        for name, value in self._request.extra_headers:
+            response.append(format_header(name, value))
+
+        response.append(u'\r\n')
+
+        return u''.join(response)
+
+    def _send_handshake(self, accept):
+        raw_response = self._create_handshake_response(accept)
+        self._request.connection.write(raw_response.encode('UTF-8'))
+        self._logger.debug('Sent server\'s opening handshake: %r',
+                           raw_response)
+
+
+# vi:sts=4 sw=4 et
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/http_header_util.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/http_header_util.py
new file mode 100644
index 0000000..21fde59
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/http_header_util.py
@@ -0,0 +1,254 @@
+# Copyright 2011, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""Utilities for parsing and formatting headers that follow the grammar defined
+in HTTP RFC http://www.ietf.org/rfc/rfc2616.txt.
+"""
+
+from __future__ import absolute_import
+import six.moves.urllib.parse
+
+_SEPARATORS = '()<>@,;:\\"/[]?={} \t'
+
+
+def _is_char(c):
+    """Returns true iff c is in CHAR as specified in HTTP RFC."""
+
+    return ord(c) <= 127
+
+
+def _is_ctl(c):
+    """Returns true iff c is in CTL as specified in HTTP RFC."""
+
+    return ord(c) <= 31 or ord(c) == 127
+
+
+class ParsingState(object):
+    def __init__(self, data):
+        self.data = data
+        self.head = 0
+
+
+def peek(state, pos=0):
+    """Peeks the character at pos from the head of data."""
+
+    if state.head + pos >= len(state.data):
+        return None
+
+    return state.data[state.head + pos]
+
+
+def consume(state, amount=1):
+    """Consumes specified amount of bytes from the head and returns the
+    consumed bytes. If there's not enough bytes to consume, returns None.
+    """
+
+    if state.head + amount > len(state.data):
+        return None
+
+    result = state.data[state.head:state.head + amount]
+    state.head = state.head + amount
+    return result
+
+
+def consume_string(state, expected):
+    """Given a parsing state and a expected string, consumes the string from
+    the head. Returns True if consumed successfully. Otherwise, returns
+    False.
+    """
+
+    pos = 0
+
+    for c in expected:
+        if c != peek(state, pos):
+            return False
+        pos += 1
+
+    consume(state, pos)
+    return True
+
+
+def consume_lws(state):
+    """Consumes a LWS from the head. Returns True if any LWS is consumed.
+    Otherwise, returns False.
+
+    LWS = [CRLF] 1*( SP | HT )
+    """
+
+    original_head = state.head
+
+    consume_string(state, '\r\n')
+
+    pos = 0
+
+    while True:
+        c = peek(state, pos)
+        if c == ' ' or c == '\t':
+            pos += 1
+        else:
+            if pos == 0:
+                state.head = original_head
+                return False
+            else:
+                consume(state, pos)
+                return True
+
+
+def consume_lwses(state):
+    r"""Consumes \*LWS from the head."""
+
+    while consume_lws(state):
+        pass
+
+
+def consume_token(state):
+    """Consumes a token from the head. Returns the token or None if no token
+    was found.
+    """
+
+    pos = 0
+
+    while True:
+        c = peek(state, pos)
+        if c is None or c in _SEPARATORS or _is_ctl(c) or not _is_char(c):
+            if pos == 0:
+                return None
+
+            return consume(state, pos)
+        else:
+            pos += 1
+
+
+def consume_token_or_quoted_string(state):
+    """Consumes a token or a quoted-string, and returns the token or unquoted
+    string. If no token or quoted-string was found, returns None.
+    """
+
+    original_head = state.head
+
+    if not consume_string(state, '"'):
+        return consume_token(state)
+
+    result = []
+
+    expect_quoted_pair = False
+
+    while True:
+        if not expect_quoted_pair and consume_lws(state):
+            result.append(' ')
+            continue
+
+        c = consume(state)
+        if c is None:
+            # quoted-string is not enclosed with double quotation
+            state.head = original_head
+            return None
+        elif expect_quoted_pair:
+            expect_quoted_pair = False
+            if _is_char(c):
+                result.append(c)
+            else:
+                # Non CHAR character found in quoted-pair
+                state.head = original_head
+                return None
+        elif c == '\\':
+            expect_quoted_pair = True
+        elif c == '"':
+            return ''.join(result)
+        elif _is_ctl(c):
+            # Invalid character %r found in qdtext
+            state.head = original_head
+            return None
+        else:
+            result.append(c)
+
+
+def quote_if_necessary(s):
+    """Quotes arbitrary string into quoted-string."""
+
+    quote = False
+    if s == '':
+        return '""'
+
+    result = []
+    for c in s:
+        if c == '"' or c in _SEPARATORS or _is_ctl(c) or not _is_char(c):
+            quote = True
+
+        if c == '"' or _is_ctl(c):
+            result.append('\\' + c)
+        else:
+            result.append(c)
+
+    if quote:
+        return '"' + ''.join(result) + '"'
+    else:
+        return ''.join(result)
+
+
+def parse_uri(uri):
+    """Parse absolute URI then return host, port and resource."""
+
+    parsed = six.moves.urllib.parse.urlsplit(uri)
+    if parsed.scheme != 'wss' and parsed.scheme != 'ws':
+        # |uri| must be a relative URI.
+        # TODO(toyoshim): Should validate |uri|.
+        return None, None, uri
+
+    if parsed.hostname is None:
+        return None, None, None
+
+    port = None
+    try:
+        port = parsed.port
+    except ValueError:
+        # The port property cause ValueError on invalid null port descriptions
+        # like 'ws://host:INVALID_PORT/path', where the assigned port is not
+        # *DIGIT. For python 3.6 and later, ValueError also raises when
+        # assigning invalid port numbers such as 'ws://host:-1/path'. Earlier
+        # versions simply return None and ignore invalid port attributes.
+        return None, None, None
+
+    if port is None:
+        if parsed.scheme == 'ws':
+            port = 80
+        else:
+            port = 443
+
+    path = parsed.path
+    if not path:
+        path += '/'
+    if parsed.query:
+        path += '?' + parsed.query
+    if parsed.fragment:
+        path += '#' + parsed.fragment
+
+    return parsed.hostname, port, path
+
+
+# vi:sts=4 sw=4 et
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/memorizingfile.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/memorizingfile.py
new file mode 100755
index 0000000..d353967
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/memorizingfile.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+#
+# Copyright 2011, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""Memorizing file.
+
+A memorizing file wraps a file and memorizes lines read by readline.
+"""
+
+from __future__ import absolute_import
+import sys
+
+
+class MemorizingFile(object):
+    """MemorizingFile wraps a file and memorizes lines read by readline.
+
+    Note that data read by other methods are not memorized. This behavior
+    is good enough for memorizing lines SimpleHTTPServer reads before
+    the control reaches WebSocketRequestHandler.
+    """
+    def __init__(self, file_, max_memorized_lines=sys.maxsize):
+        """Construct an instance.
+
+        Args:
+            file_: the file object to wrap.
+            max_memorized_lines: the maximum number of lines to memorize.
+                Only the first max_memorized_lines are memorized.
+                Default: sys.maxint.
+        """
+        self._file = file_
+        self._memorized_lines = []
+        self._max_memorized_lines = max_memorized_lines
+        self._buffered = False
+        self._buffered_line = None
+
+    def __getattribute__(self, name):
+        """Return a file attribute.
+        
+        Returns the value overridden by this class for some attributes,
+        and forwards the call to _file for the other attributes.
+        """
+        if name in ('_file', '_memorized_lines', '_max_memorized_lines',
+                    '_buffered', '_buffered_line', 'readline',
+                    'get_memorized_lines'):
+            return object.__getattribute__(self, name)
+        return self._file.__getattribute__(name)
+
+    def readline(self, size=-1):
+        """Override file.readline and memorize the line read.
+
+        Note that even if size is specified and smaller than actual size,
+        the whole line will be read out from underlying file object by
+        subsequent readline calls.
+        """
+        if self._buffered:
+            line = self._buffered_line
+            self._buffered = False
+        else:
+            line = self._file.readline()
+            if line and len(self._memorized_lines) < self._max_memorized_lines:
+                self._memorized_lines.append(line)
+        if size >= 0 and size < len(line):
+            self._buffered = True
+            self._buffered_line = line[size:]
+            return line[:size]
+        return line
+
+    def get_memorized_lines(self):
+        """Get lines memorized so far."""
+        return self._memorized_lines
+
+
+# vi:sts=4 sw=4 et
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/msgutil.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/msgutil.py
new file mode 100644
index 0000000..f58ca78
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/msgutil.py
@@ -0,0 +1,214 @@
+# Copyright 2011, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""Message related utilities.
+
+Note: request.connection.write/read are used in this module, even though
+mod_python document says that they should be used only in connection
+handlers. Unfortunately, we have no other options. For example,
+request.write/read are not suitable because they don't allow direct raw
+bytes writing/reading.
+"""
+
+from __future__ import absolute_import
+import six.moves.queue
+import threading
+
+# Export Exception symbols from msgutil for backward compatibility
+from mod_pywebsocket._stream_exceptions import ConnectionTerminatedException
+from mod_pywebsocket._stream_exceptions import InvalidFrameException
+from mod_pywebsocket._stream_exceptions import BadOperationException
+from mod_pywebsocket._stream_exceptions import UnsupportedFrameException
+
+
+# An API for handler to send/receive WebSocket messages.
+def close_connection(request):
+    """Close connection.
+
+    Args:
+        request: mod_python request.
+    """
+    request.ws_stream.close_connection()
+
+
+def send_message(request, payload_data, end=True, binary=False):
+    """Send a message (or part of a message).
+
+    Args:
+        request: mod_python request.
+        payload_data: unicode text or str binary to send.
+        end: True to terminate a message.
+             False to send payload_data as part of a message that is to be
+             terminated by next or later send_message call with end=True.
+        binary: send payload_data as binary frame(s).
+    Raises:
+        BadOperationException: when server already terminated.
+    """
+    request.ws_stream.send_message(payload_data, end, binary)
+
+
+def receive_message(request):
+    """Receive a WebSocket frame and return its payload as a text in
+    unicode or a binary in str.
+
+    Args:
+        request: mod_python request.
+    Raises:
+        InvalidFrameException:     when client send invalid frame.
+        UnsupportedFrameException: when client send unsupported frame e.g. some
+                                   of reserved bit is set but no extension can
+                                   recognize it.
+        InvalidUTF8Exception:      when client send a text frame containing any
+                                   invalid UTF-8 string.
+        ConnectionTerminatedException: when the connection is closed
+                                   unexpectedly.
+        BadOperationException:     when client already terminated.
+    """
+    return request.ws_stream.receive_message()
+
+
+def send_ping(request, body):
+    request.ws_stream.send_ping(body)
+
+
+class MessageReceiver(threading.Thread):
+    """This class receives messages from the client.
+
+    This class provides three ways to receive messages: blocking,
+    non-blocking, and via callback. Callback has the highest precedence.
+
+    Note: This class should not be used with the standalone server for wss
+    because pyOpenSSL used by the server raises a fatal error if the socket
+    is accessed from multiple threads.
+    """
+    def __init__(self, request, onmessage=None):
+        """Construct an instance.
+
+        Args:
+            request: mod_python request.
+            onmessage: a function to be called when a message is received.
+                       May be None. If not None, the function is called on
+                       another thread. In that case, MessageReceiver.receive
+                       and MessageReceiver.receive_nowait are useless
+                       because they will never return any messages.
+        """
+
+        threading.Thread.__init__(self)
+        self._request = request
+        self._queue = six.moves.queue.Queue()
+        self._onmessage = onmessage
+        self._stop_requested = False
+        self.setDaemon(True)
+        self.start()
+
+    def run(self):
+        try:
+            while not self._stop_requested:
+                message = receive_message(self._request)
+                if self._onmessage:
+                    self._onmessage(message)
+                else:
+                    self._queue.put(message)
+        finally:
+            close_connection(self._request)
+
+    def receive(self):
+        """ Receive a message from the channel, blocking.
+
+        Returns:
+            message as a unicode string.
+        """
+        return self._queue.get()
+
+    def receive_nowait(self):
+        """ Receive a message from the channel, non-blocking.
+
+        Returns:
+            message as a unicode string if available. None otherwise.
+        """
+        try:
+            message = self._queue.get_nowait()
+        except six.moves.queue.Empty:
+            message = None
+        return message
+
+    def stop(self):
+        """Request to stop this instance.
+
+        The instance will be stopped after receiving the next message.
+        This method may not be very useful, but there is no clean way
+        in Python to forcefully stop a running thread.
+        """
+        self._stop_requested = True
+
+
+class MessageSender(threading.Thread):
+    """This class sends messages to the client.
+
+    This class provides both synchronous and asynchronous ways to send
+    messages.
+
+    Note: This class should not be used with the standalone server for wss
+    because pyOpenSSL used by the server raises a fatal error if the socket
+    is accessed from multiple threads.
+    """
+    def __init__(self, request):
+        """Construct an instance.
+
+        Args:
+            request: mod_python request.
+        """
+        threading.Thread.__init__(self)
+        self._request = request
+        self._queue = six.moves.queue.Queue()
+        self.setDaemon(True)
+        self.start()
+
+    def run(self):
+        while True:
+            message, condition = self._queue.get()
+            condition.acquire()
+            send_message(self._request, message)
+            condition.notify()
+            condition.release()
+
+    def send(self, message):
+        """Send a message, blocking."""
+
+        condition = threading.Condition()
+        condition.acquire()
+        self._queue.put((message, condition))
+        condition.wait()
+
+    def send_nowait(self, message):
+        """Send a message, non-blocking."""
+
+        self._queue.put((message, threading.Condition()))
+
+
+# vi:sts=4 sw=4 et
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/request_handler.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/request_handler.py
new file mode 100644
index 0000000..5e9c875
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/request_handler.py
@@ -0,0 +1,319 @@
+# Copyright 2020, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""Request Handler and Request/Connection classes for standalone server.
+"""
+
+import os
+
+from six.moves import CGIHTTPServer
+from six.moves import http_client
+
+from mod_pywebsocket import common
+from mod_pywebsocket import dispatch
+from mod_pywebsocket import handshake
+from mod_pywebsocket import http_header_util
+from mod_pywebsocket import memorizingfile
+from mod_pywebsocket import util
+
+# 1024 is practically large enough to contain WebSocket handshake lines.
+_MAX_MEMORIZED_LINES = 1024
+
+
+class _StandaloneConnection(object):
+    """Mimic mod_python mp_conn."""
+    def __init__(self, request_handler):
+        """Construct an instance.
+
+        Args:
+            request_handler: A WebSocketRequestHandler instance.
+        """
+
+        self._request_handler = request_handler
+
+    def get_local_addr(self):
+        """Getter to mimic mp_conn.local_addr."""
+
+        return (self._request_handler.server.server_name,
+                self._request_handler.server.server_port)
+
+    local_addr = property(get_local_addr)
+
+    def get_remote_addr(self):
+        """Getter to mimic mp_conn.remote_addr.
+
+        Setting the property in __init__ won't work because the request
+        handler is not initialized yet there."""
+
+        return self._request_handler.client_address
+
+    remote_addr = property(get_remote_addr)
+
+    def write(self, data):
+        """Mimic mp_conn.write()."""
+
+        return self._request_handler.wfile.write(data)
+
+    def read(self, length):
+        """Mimic mp_conn.read()."""
+
+        return self._request_handler.rfile.read(length)
+
+    def get_memorized_lines(self):
+        """Get memorized lines."""
+
+        return self._request_handler.rfile.get_memorized_lines()
+
+
+class _StandaloneRequest(object):
+    """Mimic mod_python request."""
+    def __init__(self, request_handler, use_tls):
+        """Construct an instance.
+
+        Args:
+            request_handler: A WebSocketRequestHandler instance.
+        """
+
+        self._logger = util.get_class_logger(self)
+
+        self._request_handler = request_handler
+        self.connection = _StandaloneConnection(request_handler)
+        self._use_tls = use_tls
+        self.headers_in = request_handler.headers
+
+    def get_uri(self):
+        """Getter to mimic request.uri.
+
+        This method returns the raw data at the Request-URI part of the
+        Request-Line, while the uri method on the request object of mod_python
+        returns the path portion after parsing the raw data. This behavior is
+        kept for compatibility.
+        """
+
+        return self._request_handler.path
+
+    uri = property(get_uri)
+
+    def get_unparsed_uri(self):
+        """Getter to mimic request.unparsed_uri."""
+
+        return self._request_handler.path
+
+    unparsed_uri = property(get_unparsed_uri)
+
+    def get_method(self):
+        """Getter to mimic request.method."""
+
+        return self._request_handler.command
+
+    method = property(get_method)
+
+    def get_protocol(self):
+        """Getter to mimic request.protocol."""
+
+        return self._request_handler.request_version
+
+    protocol = property(get_protocol)
+
+    def is_https(self):
+        """Mimic request.is_https()."""
+
+        return self._use_tls
+
+
+class WebSocketRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
+    """CGIHTTPRequestHandler specialized for WebSocket."""
+
+    # Use httplib.HTTPMessage instead of mimetools.Message.
+    MessageClass = http_client.HTTPMessage
+
+    def setup(self):
+        """Override SocketServer.StreamRequestHandler.setup to wrap rfile
+        with MemorizingFile.
+
+        This method will be called by BaseRequestHandler's constructor
+        before calling BaseHTTPRequestHandler.handle.
+        BaseHTTPRequestHandler.handle will call
+        BaseHTTPRequestHandler.handle_one_request and it will call
+        WebSocketRequestHandler.parse_request.
+        """
+
+        # Call superclass's setup to prepare rfile, wfile, etc. See setup
+        # definition on the root class SocketServer.StreamRequestHandler to
+        # understand what this does.
+        CGIHTTPServer.CGIHTTPRequestHandler.setup(self)
+
+        self.rfile = memorizingfile.MemorizingFile(
+            self.rfile, max_memorized_lines=_MAX_MEMORIZED_LINES)
+
+    def __init__(self, request, client_address, server):
+        self._logger = util.get_class_logger(self)
+
+        self._options = server.websocket_server_options
+
+        # Overrides CGIHTTPServerRequestHandler.cgi_directories.
+        self.cgi_directories = self._options.cgi_directories
+        # Replace CGIHTTPRequestHandler.is_executable method.
+        if self._options.is_executable_method is not None:
+            self.is_executable = self._options.is_executable_method
+
+        # This actually calls BaseRequestHandler.__init__.
+        CGIHTTPServer.CGIHTTPRequestHandler.__init__(self, request,
+                                                     client_address, server)
+
+    def parse_request(self):
+        """Override BaseHTTPServer.BaseHTTPRequestHandler.parse_request.
+
+        Return True to continue processing for HTTP(S), False otherwise.
+
+        See BaseHTTPRequestHandler.handle_one_request method which calls
+        this method to understand how the return value will be handled.
+        """
+
+        # We hook parse_request method, but also call the original
+        # CGIHTTPRequestHandler.parse_request since when we return False,
+        # CGIHTTPRequestHandler.handle_one_request continues processing and
+        # it needs variables set by CGIHTTPRequestHandler.parse_request.
+        #
+        # Variables set by this method will be also used by WebSocket request
+        # handling (self.path, self.command, self.requestline, etc. See also
+        # how _StandaloneRequest's members are implemented using these
+        # attributes).
+        if not CGIHTTPServer.CGIHTTPRequestHandler.parse_request(self):
+            return False
+
+        if self._options.use_basic_auth:
+            auth = self.headers.get('Authorization')
+            if auth != self._options.basic_auth_credential:
+                self.send_response(401)
+                self.send_header('WWW-Authenticate',
+                                 'Basic realm="Pywebsocket"')
+                self.end_headers()
+                self._logger.info('Request basic authentication')
+                return False
+
+        host, port, resource = http_header_util.parse_uri(self.path)
+        if resource is None:
+            self._logger.info('Invalid URI: %r', self.path)
+            self._logger.info('Fallback to CGIHTTPRequestHandler')
+            return True
+        server_options = self.server.websocket_server_options
+        if host is not None:
+            validation_host = server_options.validation_host
+            if validation_host is not None and host != validation_host:
+                self._logger.info('Invalid host: %r (expected: %r)', host,
+                                  validation_host)
+                self._logger.info('Fallback to CGIHTTPRequestHandler')
+                return True
+        if port is not None:
+            validation_port = server_options.validation_port
+            if validation_port is not None and port != validation_port:
+                self._logger.info('Invalid port: %r (expected: %r)', port,
+                                  validation_port)
+                self._logger.info('Fallback to CGIHTTPRequestHandler')
+                return True
+        self.path = resource
+
+        request = _StandaloneRequest(self, self._options.use_tls)
+
+        try:
+            # Fallback to default http handler for request paths for which
+            # we don't have request handlers.
+            if not self._options.dispatcher.get_handler_suite(self.path):
+                self._logger.info('No handler for resource: %r', self.path)
+                self._logger.info('Fallback to CGIHTTPRequestHandler')
+                return True
+        except dispatch.DispatchException as e:
+            self._logger.info('Dispatch failed for error: %s', e)
+            self.send_error(e.status)
+            return False
+
+        # If any Exceptions without except clause setup (including
+        # DispatchException) is raised below this point, it will be caught
+        # and logged by WebSocketServer.
+
+        try:
+            try:
+                handshake.do_handshake(request, self._options.dispatcher)
+            except handshake.VersionException as e:
+                self._logger.info('Handshake failed for version error: %s', e)
+                self.send_response(common.HTTP_STATUS_BAD_REQUEST)
+                self.send_header(common.SEC_WEBSOCKET_VERSION_HEADER,
+                                 e.supported_versions)
+                self.end_headers()
+                return False
+            except handshake.HandshakeException as e:
+                # Handshake for ws(s) failed.
+                self._logger.info('Handshake failed for error: %s', e)
+                self.send_error(e.status)
+                return False
+
+            request._dispatcher = self._options.dispatcher
+            self._options.dispatcher.transfer_data(request)
+        except handshake.AbortedByUserException as e:
+            self._logger.info('Aborted: %s', e)
+        return False
+
+    def log_request(self, code='-', size='-'):
+        """Override BaseHTTPServer.log_request."""
+
+        self._logger.info('"%s" %s %s', self.requestline, str(code), str(size))
+
+    def log_error(self, *args):
+        """Override BaseHTTPServer.log_error."""
+
+        # Despite the name, this method is for warnings than for errors.
+        # For example, HTTP status code is logged by this method.
+        self._logger.warning('%s - %s', self.address_string(),
+                             args[0] % args[1:])
+
+    def is_cgi(self):
+        """Test whether self.path corresponds to a CGI script.
+
+        Add extra check that self.path doesn't contains ..
+        Also check if the file is a executable file or not.
+        If the file is not executable, it is handled as static file or dir
+        rather than a CGI script.
+        """
+
+        if CGIHTTPServer.CGIHTTPRequestHandler.is_cgi(self):
+            if '..' in self.path:
+                return False
+            # strip query parameter from request path
+            resource_name = self.path.split('?', 2)[0]
+            # convert resource_name into real path name in filesystem.
+            scriptfile = self.translate_path(resource_name)
+            if not os.path.isfile(scriptfile):
+                return False
+            if not self.is_executable(scriptfile):
+                return False
+            return True
+        return False
+
+
+# vi:sts=4 sw=4 et
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/server_util.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/server_util.py
new file mode 100644
index 0000000..8f9e273e
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/server_util.py
@@ -0,0 +1,87 @@
+# Copyright 2020, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""Server related utilities."""
+
+import logging
+import logging.handlers
+import threading
+import time
+
+from mod_pywebsocket import common
+from mod_pywebsocket import util
+
+
+def _get_logger_from_class(c):
+    return logging.getLogger('%s.%s' % (c.__module__, c.__name__))
+
+
+def configure_logging(options):
+    logging.addLevelName(common.LOGLEVEL_FINE, 'FINE')
+
+    logger = logging.getLogger()
+    logger.setLevel(logging.getLevelName(options.log_level.upper()))
+    if options.log_file:
+        handler = logging.handlers.RotatingFileHandler(options.log_file, 'a',
+                                                       options.log_max,
+                                                       options.log_count)
+    else:
+        handler = logging.StreamHandler()
+    formatter = logging.Formatter(
+        '[%(asctime)s] [%(levelname)s] %(name)s: %(message)s')
+    handler.setFormatter(formatter)
+    logger.addHandler(handler)
+
+    deflate_log_level_name = logging.getLevelName(
+        options.deflate_log_level.upper())
+    _get_logger_from_class(util._Deflater).setLevel(deflate_log_level_name)
+    _get_logger_from_class(util._Inflater).setLevel(deflate_log_level_name)
+
+
+class ThreadMonitor(threading.Thread):
+    daemon = True
+
+    def __init__(self, interval_in_sec):
+        threading.Thread.__init__(self, name='ThreadMonitor')
+
+        self._logger = util.get_class_logger(self)
+
+        self._interval_in_sec = interval_in_sec
+
+    def run(self):
+        while True:
+            thread_name_list = []
+            for thread in threading.enumerate():
+                thread_name_list.append(thread.name)
+            self._logger.info("%d active threads: %s",
+                              threading.active_count(),
+                              ', '.join(thread_name_list))
+            time.sleep(self._interval_in_sec)
+
+
+# vi:sts=4 sw=4 et
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/standalone.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/standalone.py
new file mode 100755
index 0000000..b075d98
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/standalone.py
@@ -0,0 +1,483 @@
+#!/usr/bin/env python
+#
+# Copyright 2012, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""Standalone WebSocket server.
+
+Use this file to launch pywebsocket as a standalone server.
+
+
+BASIC USAGE
+===========
+
+Go to the src directory and run
+
+  $ python mod_pywebsocket/standalone.py [-p <ws_port>]
+                                         [-w <websock_handlers>]
+                                         [-d <document_root>]
+
+<ws_port> is the port number to use for ws:// connection.
+
+<document_root> is the path to the root directory of HTML files.
+
+<websock_handlers> is the path to the root directory of WebSocket handlers.
+If not specified, <document_root> will be used. See __init__.py (or
+run $ pydoc mod_pywebsocket) for how to write WebSocket handlers.
+
+For more detail and other options, run
+
+  $ python mod_pywebsocket/standalone.py --help
+
+or see _build_option_parser method below.
+
+For trouble shooting, adding "--log_level debug" might help you.
+
+
+TRY DEMO
+========
+
+Go to the src directory and run standalone.py with -d option to set the
+document root to the directory containing example HTMLs and handlers like this:
+
+  $ cd src
+  $ PYTHONPATH=. python mod_pywebsocket/standalone.py -d example
+
+to launch pywebsocket with the sample handler and html on port 80. Open
+http://localhost/console.html, click the connect button, type something into
+the text box next to the send button and click the send button. If everything
+is working, you'll see the message you typed echoed by the server.
+
+
+USING TLS
+=========
+
+To run the standalone server with TLS support, run it with -t, -k, and -c
+options. When TLS is enabled, the standalone server accepts only TLS connection.
+
+Note that when ssl module is used and the key/cert location is incorrect,
+TLS connection silently fails while pyOpenSSL fails on startup.
+
+Example:
+
+  $ PYTHONPATH=. python mod_pywebsocket/standalone.py \
+        -d example \
+        -p 10443 \
+        -t \
+        -c ../test/cert/cert.pem \
+        -k ../test/cert/key.pem \
+
+Note that when passing a relative path to -c and -k option, it will be resolved
+using the document root directory as the base.
+
+
+USING CLIENT AUTHENTICATION
+===========================
+
+To run the standalone server with TLS client authentication support, run it with
+--tls-client-auth and --tls-client-ca options in addition to ones required for
+TLS support.
+
+Example:
+
+  $ PYTHONPATH=. python mod_pywebsocket/standalone.py -d example -p 10443 -t \
+        -c ../test/cert/cert.pem -k ../test/cert/key.pem \
+        --tls-client-auth \
+        --tls-client-ca=../test/cert/cacert.pem
+
+Note that when passing a relative path to --tls-client-ca option, it will be
+resolved using the document root directory as the base.
+
+
+CONFIGURATION FILE
+==================
+
+You can also write a configuration file and use it by specifying the path to
+the configuration file by --config option. Please write a configuration file
+following the documentation of the Python ConfigParser library. Name of each
+entry must be the long version argument name. E.g. to set log level to debug,
+add the following line:
+
+log_level=debug
+
+For options which doesn't take value, please add some fake value. E.g. for
+--tls option, add the following line:
+
+tls=True
+
+Note that tls will be enabled even if you write tls=False as the value part is
+fake.
+
+When both a command line argument and a configuration file entry are set for
+the same configuration item, the command line value will override one in the
+configuration file.
+
+
+THREADING
+=========
+
+This server is derived from SocketServer.ThreadingMixIn. Hence a thread is
+used for each request.
+
+
+SECURITY WARNING
+================
+
+This uses CGIHTTPServer and CGIHTTPServer is not secure.
+It may execute arbitrary Python code or external programs. It should not be
+used outside a firewall.
+"""
+
+from __future__ import absolute_import
+from six.moves import configparser
+import base64
+import logging
+import argparse
+import os
+import six
+import sys
+import traceback
+
+from mod_pywebsocket import common
+from mod_pywebsocket import util
+from mod_pywebsocket import server_util
+from mod_pywebsocket.websocket_server import WebSocketServer
+
+_DEFAULT_LOG_MAX_BYTES = 1024 * 256
+_DEFAULT_LOG_BACKUP_COUNT = 5
+
+_DEFAULT_REQUEST_QUEUE_SIZE = 128
+
+
+def _build_option_parser():
+    parser = argparse.ArgumentParser()
+
+    parser.add_argument(
+        '--config',
+        dest='config_file',
+        type=six.text_type,
+        default=None,
+        help=('Path to configuration file. See the file comment '
+              'at the top of this file for the configuration '
+              'file format'))
+    parser.add_argument('-H',
+                        '--server-host',
+                        '--server_host',
+                        dest='server_host',
+                        default='',
+                        help='server hostname to listen to')
+    parser.add_argument('-V',
+                        '--validation-host',
+                        '--validation_host',
+                        dest='validation_host',
+                        default=None,
+                        help='server hostname to validate in absolute path.')
+    parser.add_argument('-p',
+                        '--port',
+                        dest='port',
+                        type=int,
+                        default=common.DEFAULT_WEB_SOCKET_PORT,
+                        help='port to listen to')
+    parser.add_argument('-P',
+                        '--validation-port',
+                        '--validation_port',
+                        dest='validation_port',
+                        type=int,
+                        default=None,
+                        help='server port to validate in absolute path.')
+    parser.add_argument(
+        '-w',
+        '--websock-handlers',
+        '--websock_handlers',
+        dest='websock_handlers',
+        default='.',
+        help=('The root directory of WebSocket handler files. '
+              'If the path is relative, --document-root is used '
+              'as the base.'))
+    parser.add_argument('-m',
+                        '--websock-handlers-map-file',
+                        '--websock_handlers_map_file',
+                        dest='websock_handlers_map_file',
+                        default=None,
+                        help=('WebSocket handlers map file. '
+                              'Each line consists of alias_resource_path and '
+                              'existing_resource_path, separated by spaces.'))
+    parser.add_argument('-s',
+                        '--scan-dir',
+                        '--scan_dir',
+                        dest='scan_dir',
+                        default=None,
+                        help=('Must be a directory under --websock-handlers. '
+                              'Only handlers under this directory are scanned '
+                              'and registered to the server. '
+                              'Useful for saving scan time when the handler '
+                              'root directory contains lots of files that are '
+                              'not handler file or are handler files but you '
+                              'don\'t want them to be registered. '))
+    parser.add_argument(
+        '--allow-handlers-outside-root-dir',
+        '--allow_handlers_outside_root_dir',
+        dest='allow_handlers_outside_root_dir',
+        action='store_true',
+        default=False,
+        help=('Scans WebSocket handlers even if their canonical '
+              'path is not under --websock-handlers.'))
+    parser.add_argument('-d',
+                        '--document-root',
+                        '--document_root',
+                        dest='document_root',
+                        default='.',
+                        help='Document root directory.')
+    parser.add_argument('-x',
+                        '--cgi-paths',
+                        '--cgi_paths',
+                        dest='cgi_paths',
+                        default=None,
+                        help=('CGI paths relative to document_root.'
+                              'Comma-separated. (e.g -x /cgi,/htbin) '
+                              'Files under document_root/cgi_path are handled '
+                              'as CGI programs. Must be executable.'))
+    parser.add_argument('-t',
+                        '--tls',
+                        dest='use_tls',
+                        action='store_true',
+                        default=False,
+                        help='use TLS (wss://)')
+    parser.add_argument('-k',
+                        '--private-key',
+                        '--private_key',
+                        dest='private_key',
+                        default='',
+                        help='TLS private key file.')
+    parser.add_argument('-c',
+                        '--certificate',
+                        dest='certificate',
+                        default='',
+                        help='TLS certificate file.')
+    parser.add_argument('--tls-client-auth',
+                        dest='tls_client_auth',
+                        action='store_true',
+                        default=False,
+                        help='Requests TLS client auth on every connection.')
+    parser.add_argument('--tls-client-cert-optional',
+                        dest='tls_client_cert_optional',
+                        action='store_true',
+                        default=False,
+                        help=('Makes client certificate optional even though '
+                              'TLS client auth is enabled.'))
+    parser.add_argument('--tls-client-ca',
+                        dest='tls_client_ca',
+                        default='',
+                        help=('Specifies a pem file which contains a set of '
+                              'concatenated CA certificates which are used to '
+                              'validate certificates passed from clients'))
+    parser.add_argument('--basic-auth',
+                        dest='use_basic_auth',
+                        action='store_true',
+                        default=False,
+                        help='Requires Basic authentication.')
+    parser.add_argument(
+        '--basic-auth-credential',
+        dest='basic_auth_credential',
+        default='test:test',
+        help='Specifies the credential of basic authentication '
+        'by username:password pair (e.g. test:test).')
+    parser.add_argument('-l',
+                        '--log-file',
+                        '--log_file',
+                        dest='log_file',
+                        default='',
+                        help='Log file.')
+    # Custom log level:
+    # - FINE: Prints status of each frame processing step
+    parser.add_argument('--log-level',
+                        '--log_level',
+                        type=six.text_type,
+                        dest='log_level',
+                        default='warn',
+                        choices=[
+                            'fine', 'debug', 'info', 'warning', 'warn',
+                            'error', 'critical'
+                        ],
+                        help='Log level.')
+    parser.add_argument(
+        '--deflate-log-level',
+        '--deflate_log_level',
+        type=six.text_type,
+        dest='deflate_log_level',
+        default='warn',
+        choices=['debug', 'info', 'warning', 'warn', 'error', 'critical'],
+        help='Log level for _Deflater and _Inflater.')
+    parser.add_argument('--thread-monitor-interval-in-sec',
+                        '--thread_monitor_interval_in_sec',
+                        dest='thread_monitor_interval_in_sec',
+                        type=int,
+                        default=-1,
+                        help=('If positive integer is specified, run a thread '
+                              'monitor to show the status of server threads '
+                              'periodically in the specified inteval in '
+                              'second. If non-positive integer is specified, '
+                              'disable the thread monitor.'))
+    parser.add_argument('--log-max',
+                        '--log_max',
+                        dest='log_max',
+                        type=int,
+                        default=_DEFAULT_LOG_MAX_BYTES,
+                        help='Log maximum bytes')
+    parser.add_argument('--log-count',
+                        '--log_count',
+                        dest='log_count',
+                        type=int,
+                        default=_DEFAULT_LOG_BACKUP_COUNT,
+                        help='Log backup count')
+    parser.add_argument('-q',
+                        '--queue',
+                        dest='request_queue_size',
+                        type=int,
+                        default=_DEFAULT_REQUEST_QUEUE_SIZE,
+                        help='request queue size')
+
+    return parser
+
+
+def _parse_args_and_config(args):
+    parser = _build_option_parser()
+
+    # First, parse options without configuration file.
+    temporary_options, temporary_args = parser.parse_known_args(args=args)
+    if temporary_args:
+        logging.critical('Unrecognized positional arguments: %r',
+                         temporary_args)
+        sys.exit(1)
+
+    if temporary_options.config_file:
+        try:
+            config_fp = open(temporary_options.config_file, 'r')
+        except IOError as e:
+            logging.critical('Failed to open configuration file %r: %r',
+                             temporary_options.config_file, e)
+            sys.exit(1)
+
+        config_parser = configparser.SafeConfigParser()
+        config_parser.readfp(config_fp)
+        config_fp.close()
+
+        args_from_config = []
+        for name, value in config_parser.items('pywebsocket'):
+            args_from_config.append('--' + name)
+            args_from_config.append(value)
+        if args is None:
+            args = args_from_config
+        else:
+            args = args_from_config + args
+        return parser.parse_known_args(args=args)
+    else:
+        return temporary_options, temporary_args
+
+
+def _main(args=None):
+    """You can call this function from your own program, but please note that
+    this function has some side-effects that might affect your program. For
+    example, util.wrap_popen3_for_win use in this method replaces implementation
+    of os.popen3.
+    """
+
+    options, args = _parse_args_and_config(args=args)
+
+    os.chdir(options.document_root)
+
+    server_util.configure_logging(options)
+
+    # TODO(tyoshino): Clean up initialization of CGI related values. Move some
+    # of code here to WebSocketRequestHandler class if it's better.
+    options.cgi_directories = []
+    options.is_executable_method = None
+    if options.cgi_paths:
+        options.cgi_directories = options.cgi_paths.split(',')
+        if sys.platform in ('cygwin', 'win32'):
+            cygwin_path = None
+            # For Win32 Python, it is expected that CYGWIN_PATH
+            # is set to a directory of cygwin binaries.
+            # For example, websocket_server.py in Chromium sets CYGWIN_PATH to
+            # full path of third_party/cygwin/bin.
+            if 'CYGWIN_PATH' in os.environ:
+                cygwin_path = os.environ['CYGWIN_PATH']
+            util.wrap_popen3_for_win(cygwin_path)
+
+            def __check_script(scriptpath):
+                return util.get_script_interp(scriptpath, cygwin_path)
+
+            options.is_executable_method = __check_script
+
+    if options.use_tls:
+        logging.debug('Using ssl module')
+
+        if not options.private_key or not options.certificate:
+            logging.critical(
+                'To use TLS, specify private_key and certificate.')
+            sys.exit(1)
+
+        if (options.tls_client_cert_optional and not options.tls_client_auth):
+            logging.critical('Client authentication must be enabled to '
+                             'specify tls_client_cert_optional')
+            sys.exit(1)
+    else:
+        if options.tls_client_auth:
+            logging.critical('TLS must be enabled for client authentication.')
+            sys.exit(1)
+
+        if options.tls_client_cert_optional:
+            logging.critical('TLS must be enabled for client authentication.')
+            sys.exit(1)
+
+    if not options.scan_dir:
+        options.scan_dir = options.websock_handlers
+
+    if options.use_basic_auth:
+        options.basic_auth_credential = 'Basic ' + base64.b64encode(
+            options.basic_auth_credential.encode('UTF-8')).decode()
+
+    try:
+        if options.thread_monitor_interval_in_sec > 0:
+            # Run a thread monitor to show the status of server threads for
+            # debugging.
+            server_util.ThreadMonitor(
+                options.thread_monitor_interval_in_sec).start()
+
+        server = WebSocketServer(options)
+        server.serve_forever()
+    except Exception as e:
+        logging.critical('mod_pywebsocket: %s' % e)
+        logging.critical('mod_pywebsocket: %s' % traceback.format_exc())
+        sys.exit(1)
+
+
+if __name__ == '__main__':
+    _main(sys.argv[1:])
+
+# vi:sts=4 sw=4 et
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/stream.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/stream.py
new file mode 100644
index 0000000..82d1ea61
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/stream.py
@@ -0,0 +1,950 @@
+# Copyright 2011, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""This file provides classes and helper functions for parsing/building frames
+of the WebSocket protocol (RFC 6455).
+
+Specification:
+http://tools.ietf.org/html/rfc6455
+"""
+
+from collections import deque
+import logging
+import os
+import struct
+import time
+import socket
+import six
+
+from mod_pywebsocket import common
+from mod_pywebsocket import util
+from mod_pywebsocket._stream_exceptions import BadOperationException
+from mod_pywebsocket._stream_exceptions import ConnectionTerminatedException
+from mod_pywebsocket._stream_exceptions import InvalidFrameException
+from mod_pywebsocket._stream_exceptions import InvalidUTF8Exception
+from mod_pywebsocket._stream_exceptions import UnsupportedFrameException
+
+_NOOP_MASKER = util.NoopMasker()
+
+
+class Frame(object):
+    def __init__(self,
+                 fin=1,
+                 rsv1=0,
+                 rsv2=0,
+                 rsv3=0,
+                 opcode=None,
+                 payload=b''):
+        self.fin = fin
+        self.rsv1 = rsv1
+        self.rsv2 = rsv2
+        self.rsv3 = rsv3
+        self.opcode = opcode
+        self.payload = payload
+
+
+# Helper functions made public to be used for writing unittests for WebSocket
+# clients.
+
+
+def create_length_header(length, mask):
+    """Creates a length header.
+
+    Args:
+        length: Frame length. Must be less than 2^63.
+        mask: Mask bit. Must be boolean.
+
+    Raises:
+        ValueError: when bad data is given.
+    """
+
+    if mask:
+        mask_bit = 1 << 7
+    else:
+        mask_bit = 0
+
+    if length < 0:
+        raise ValueError('length must be non negative integer')
+    elif length <= 125:
+        return util.pack_byte(mask_bit | length)
+    elif length < (1 << 16):
+        return util.pack_byte(mask_bit | 126) + struct.pack('!H', length)
+    elif length < (1 << 63):
+        return util.pack_byte(mask_bit | 127) + struct.pack('!Q', length)
+    else:
+        raise ValueError('Payload is too big for one frame')
+
+
+def create_header(opcode, payload_length, fin, rsv1, rsv2, rsv3, mask):
+    """Creates a frame header.
+
+    Raises:
+        Exception: when bad data is given.
+    """
+
+    if opcode < 0 or 0xf < opcode:
+        raise ValueError('Opcode out of range')
+
+    if payload_length < 0 or (1 << 63) <= payload_length:
+        raise ValueError('payload_length out of range')
+
+    if (fin | rsv1 | rsv2 | rsv3) & ~1:
+        raise ValueError('FIN bit and Reserved bit parameter must be 0 or 1')
+
+    header = b''
+
+    first_byte = ((fin << 7)
+                  | (rsv1 << 6) | (rsv2 << 5) | (rsv3 << 4)
+                  | opcode)
+    header += util.pack_byte(first_byte)
+    header += create_length_header(payload_length, mask)
+
+    return header
+
+
+def _build_frame(header, body, mask):
+    if not mask:
+        return header + body
+
+    masking_nonce = os.urandom(4)
+    masker = util.RepeatedXorMasker(masking_nonce)
+
+    return header + masking_nonce + masker.mask(body)
+
+
+def _filter_and_format_frame_object(frame, mask, frame_filters):
+    for frame_filter in frame_filters:
+        frame_filter.filter(frame)
+
+    header = create_header(frame.opcode, len(frame.payload), frame.fin,
+                           frame.rsv1, frame.rsv2, frame.rsv3, mask)
+    return _build_frame(header, frame.payload, mask)
+
+
+def create_binary_frame(message,
+                        opcode=common.OPCODE_BINARY,
+                        fin=1,
+                        mask=False,
+                        frame_filters=[]):
+    """Creates a simple binary frame with no extension, reserved bit."""
+
+    frame = Frame(fin=fin, opcode=opcode, payload=message)
+    return _filter_and_format_frame_object(frame, mask, frame_filters)
+
+
+def create_text_frame(message,
+                      opcode=common.OPCODE_TEXT,
+                      fin=1,
+                      mask=False,
+                      frame_filters=[]):
+    """Creates a simple text frame with no extension, reserved bit."""
+
+    encoded_message = message.encode('utf-8')
+    return create_binary_frame(encoded_message, opcode, fin, mask,
+                               frame_filters)
+
+
+def parse_frame(receive_bytes,
+                logger=None,
+                ws_version=common.VERSION_HYBI_LATEST,
+                unmask_receive=True):
+    """Parses a frame. Returns a tuple containing each header field and
+    payload.
+
+    Args:
+        receive_bytes: a function that reads frame data from a stream or
+            something similar. The function takes length of the bytes to be
+            read. The function must raise ConnectionTerminatedException if
+            there is not enough data to be read.
+        logger: a logging object.
+        ws_version: the version of WebSocket protocol.
+        unmask_receive: unmask received frames. When received unmasked
+            frame, raises InvalidFrameException.
+
+    Raises:
+        ConnectionTerminatedException: when receive_bytes raises it.
+        InvalidFrameException: when the frame contains invalid data.
+    """
+
+    if not logger:
+        logger = logging.getLogger()
+
+    logger.log(common.LOGLEVEL_FINE, 'Receive the first 2 octets of a frame')
+
+    first_byte = ord(receive_bytes(1))
+    fin = (first_byte >> 7) & 1
+    rsv1 = (first_byte >> 6) & 1
+    rsv2 = (first_byte >> 5) & 1
+    rsv3 = (first_byte >> 4) & 1
+    opcode = first_byte & 0xf
+
+    second_byte = ord(receive_bytes(1))
+    mask = (second_byte >> 7) & 1
+    payload_length = second_byte & 0x7f
+
+    logger.log(
+        common.LOGLEVEL_FINE, 'FIN=%s, RSV1=%s, RSV2=%s, RSV3=%s, opcode=%s, '
+        'Mask=%s, Payload_length=%s', fin, rsv1, rsv2, rsv3, opcode, mask,
+        payload_length)
+
+    if (mask == 1) != unmask_receive:
+        raise InvalidFrameException(
+            'Mask bit on the received frame did\'nt match masking '
+            'configuration for received frames')
+
+    # The HyBi and later specs disallow putting a value in 0x0-0xFFFF
+    # into the 8-octet extended payload length field (or 0x0-0xFD in
+    # 2-octet field).
+    valid_length_encoding = True
+    length_encoding_bytes = 1
+    if payload_length == 127:
+        logger.log(common.LOGLEVEL_FINE,
+                   'Receive 8-octet extended payload length')
+
+        extended_payload_length = receive_bytes(8)
+        payload_length = struct.unpack('!Q', extended_payload_length)[0]
+        if payload_length > 0x7FFFFFFFFFFFFFFF:
+            raise InvalidFrameException('Extended payload length >= 2^63')
+        if ws_version >= 13 and payload_length < 0x10000:
+            valid_length_encoding = False
+            length_encoding_bytes = 8
+
+        logger.log(common.LOGLEVEL_FINE, 'Decoded_payload_length=%s',
+                   payload_length)
+    elif payload_length == 126:
+        logger.log(common.LOGLEVEL_FINE,
+                   'Receive 2-octet extended payload length')
+
+        extended_payload_length = receive_bytes(2)
+        payload_length = struct.unpack('!H', extended_payload_length)[0]
+        if ws_version >= 13 and payload_length < 126:
+            valid_length_encoding = False
+            length_encoding_bytes = 2
+
+        logger.log(common.LOGLEVEL_FINE, 'Decoded_payload_length=%s',
+                   payload_length)
+
+    if not valid_length_encoding:
+        logger.warning(
+            'Payload length is not encoded using the minimal number of '
+            'bytes (%d is encoded using %d bytes)', payload_length,
+            length_encoding_bytes)
+
+    if mask == 1:
+        logger.log(common.LOGLEVEL_FINE, 'Receive mask')
+
+        masking_nonce = receive_bytes(4)
+        masker = util.RepeatedXorMasker(masking_nonce)
+
+        logger.log(common.LOGLEVEL_FINE, 'Mask=%r', masking_nonce)
+    else:
+        masker = _NOOP_MASKER
+
+    logger.log(common.LOGLEVEL_FINE, 'Receive payload data')
+    if logger.isEnabledFor(common.LOGLEVEL_FINE):
+        receive_start = time.time()
+
+    raw_payload_bytes = receive_bytes(payload_length)
+
+    if logger.isEnabledFor(common.LOGLEVEL_FINE):
+        logger.log(
+            common.LOGLEVEL_FINE, 'Done receiving payload data at %s MB/s',
+            payload_length / (time.time() - receive_start) / 1000 / 1000)
+    logger.log(common.LOGLEVEL_FINE, 'Unmask payload data')
+
+    if logger.isEnabledFor(common.LOGLEVEL_FINE):
+        unmask_start = time.time()
+
+    unmasked_bytes = masker.mask(raw_payload_bytes)
+
+    if logger.isEnabledFor(common.LOGLEVEL_FINE):
+        logger.log(common.LOGLEVEL_FINE,
+                   'Done unmasking payload data at %s MB/s',
+                   payload_length / (time.time() - unmask_start) / 1000 / 1000)
+
+    return opcode, unmasked_bytes, fin, rsv1, rsv2, rsv3
+
+
+class FragmentedFrameBuilder(object):
+    """A stateful class to send a message as fragments."""
+    def __init__(self, mask, frame_filters=[], encode_utf8=True):
+        """Constructs an instance."""
+
+        self._mask = mask
+        self._frame_filters = frame_filters
+        # This is for skipping UTF-8 encoding when building text type frames
+        # from compressed data.
+        self._encode_utf8 = encode_utf8
+
+        self._started = False
+
+        # Hold opcode of the first frame in messages to verify types of other
+        # frames in the message are all the same.
+        self._opcode = common.OPCODE_TEXT
+
+    def build(self, payload_data, end, binary):
+        if binary:
+            frame_type = common.OPCODE_BINARY
+        else:
+            frame_type = common.OPCODE_TEXT
+        if self._started:
+            if self._opcode != frame_type:
+                raise ValueError('Message types are different in frames for '
+                                 'the same message')
+            opcode = common.OPCODE_CONTINUATION
+        else:
+            opcode = frame_type
+            self._opcode = frame_type
+
+        if end:
+            self._started = False
+            fin = 1
+        else:
+            self._started = True
+            fin = 0
+
+        if binary or not self._encode_utf8:
+            return create_binary_frame(payload_data, opcode, fin, self._mask,
+                                       self._frame_filters)
+        else:
+            return create_text_frame(payload_data, opcode, fin, self._mask,
+                                     self._frame_filters)
+
+
+def _create_control_frame(opcode, body, mask, frame_filters):
+    frame = Frame(opcode=opcode, payload=body)
+
+    for frame_filter in frame_filters:
+        frame_filter.filter(frame)
+
+    if len(frame.payload) > 125:
+        raise BadOperationException(
+            'Payload data size of control frames must be 125 bytes or less')
+
+    header = create_header(frame.opcode, len(frame.payload), frame.fin,
+                           frame.rsv1, frame.rsv2, frame.rsv3, mask)
+    return _build_frame(header, frame.payload, mask)
+
+
+def create_ping_frame(body, mask=False, frame_filters=[]):
+    return _create_control_frame(common.OPCODE_PING, body, mask, frame_filters)
+
+
+def create_pong_frame(body, mask=False, frame_filters=[]):
+    return _create_control_frame(common.OPCODE_PONG, body, mask, frame_filters)
+
+
+def create_close_frame(body, mask=False, frame_filters=[]):
+    return _create_control_frame(common.OPCODE_CLOSE, body, mask,
+                                 frame_filters)
+
+
+def create_closing_handshake_body(code, reason):
+    body = b''
+    if code is not None:
+        if (code > common.STATUS_USER_PRIVATE_MAX
+                or code < common.STATUS_NORMAL_CLOSURE):
+            raise BadOperationException('Status code is out of range')
+        if (code == common.STATUS_NO_STATUS_RECEIVED
+                or code == common.STATUS_ABNORMAL_CLOSURE
+                or code == common.STATUS_TLS_HANDSHAKE):
+            raise BadOperationException('Status code is reserved pseudo '
+                                        'code')
+        encoded_reason = reason.encode('utf-8')
+        body = struct.pack('!H', code) + encoded_reason
+    return body
+
+
+class StreamOptions(object):
+    """Holds option values to configure Stream objects."""
+    def __init__(self):
+        """Constructs StreamOptions."""
+
+        # Filters applied to frames.
+        self.outgoing_frame_filters = []
+        self.incoming_frame_filters = []
+
+        # Filters applied to messages. Control frames are not affected by them.
+        self.outgoing_message_filters = []
+        self.incoming_message_filters = []
+
+        self.encode_text_message_to_utf8 = True
+        self.mask_send = False
+        self.unmask_receive = True
+
+
+class Stream(object):
+    """A class for parsing/building frames of the WebSocket protocol
+    (RFC 6455).
+    """
+    def __init__(self, request, options):
+        """Constructs an instance.
+
+        Args:
+            request: mod_python request.
+        """
+
+        self._logger = util.get_class_logger(self)
+
+        self._options = options
+        self._request = request
+
+        self._request.client_terminated = False
+        self._request.server_terminated = False
+
+        # Holds body of received fragments.
+        self._received_fragments = []
+        # Holds the opcode of the first fragment.
+        self._original_opcode = None
+
+        self._writer = FragmentedFrameBuilder(
+            self._options.mask_send, self._options.outgoing_frame_filters,
+            self._options.encode_text_message_to_utf8)
+
+        self._ping_queue = deque()
+
+    def _read(self, length):
+        """Reads length bytes from connection. In case we catch any exception,
+        prepends remote address to the exception message and raise again.
+
+        Raises:
+            ConnectionTerminatedException: when read returns empty string.
+        """
+
+        try:
+            read_bytes = self._request.connection.read(length)
+            if not read_bytes:
+                raise ConnectionTerminatedException(
+                    'Receiving %d byte failed. Peer (%r) closed connection' %
+                    (length, (self._request.connection.remote_addr, )))
+            return read_bytes
+        except IOError as e:
+            # Also catch an IOError because mod_python throws it.
+            raise ConnectionTerminatedException(
+                'Receiving %d byte failed. IOError (%s) occurred' %
+                (length, e))
+
+    def _write(self, bytes_to_write):
+        """Writes given bytes to connection. In case we catch any exception,
+        prepends remote address to the exception message and raise again.
+        """
+
+        try:
+            self._request.connection.write(bytes_to_write)
+        except Exception as e:
+            util.prepend_message_to_exception(
+                'Failed to send message to %r: ' %
+                (self._request.connection.remote_addr, ), e)
+            raise
+
+    def receive_bytes(self, length):
+        """Receives multiple bytes. Retries read when we couldn't receive the
+        specified amount. This method returns byte strings.
+
+        Raises:
+            ConnectionTerminatedException: when read returns empty string.
+        """
+
+        read_bytes = []
+        while length > 0:
+            new_read_bytes = self._read(length)
+            read_bytes.append(new_read_bytes)
+            length -= len(new_read_bytes)
+        return b''.join(read_bytes)
+
+    def _read_until(self, delim_char):
+        """Reads bytes until we encounter delim_char. The result will not
+        contain delim_char.
+
+        Raises:
+            ConnectionTerminatedException: when read returns empty string.
+        """
+
+        read_bytes = []
+        while True:
+            ch = self._read(1)
+            if ch == delim_char:
+                break
+            read_bytes.append(ch)
+        return b''.join(read_bytes)
+
+    def _receive_frame(self):
+        """Receives a frame and return data in the frame as a tuple containing
+        each header field and payload separately.
+
+        Raises:
+            ConnectionTerminatedException: when read returns empty
+                string.
+            InvalidFrameException: when the frame contains invalid data.
+        """
+        def _receive_bytes(length):
+            return self.receive_bytes(length)
+
+        return parse_frame(receive_bytes=_receive_bytes,
+                           logger=self._logger,
+                           ws_version=self._request.ws_version,
+                           unmask_receive=self._options.unmask_receive)
+
+    def _receive_frame_as_frame_object(self):
+        opcode, unmasked_bytes, fin, rsv1, rsv2, rsv3 = self._receive_frame()
+
+        return Frame(fin=fin,
+                     rsv1=rsv1,
+                     rsv2=rsv2,
+                     rsv3=rsv3,
+                     opcode=opcode,
+                     payload=unmasked_bytes)
+
+    def receive_filtered_frame(self):
+        """Receives a frame and applies frame filters and message filters.
+        The frame to be received must satisfy following conditions:
+        - The frame is not fragmented.
+        - The opcode of the frame is TEXT or BINARY.
+
+        DO NOT USE this method except for testing purpose.
+        """
+
+        frame = self._receive_frame_as_frame_object()
+        if not frame.fin:
+            raise InvalidFrameException(
+                'Segmented frames must not be received via '
+                'receive_filtered_frame()')
+        if (frame.opcode != common.OPCODE_TEXT
+                and frame.opcode != common.OPCODE_BINARY):
+            raise InvalidFrameException(
+                'Control frames must not be received via '
+                'receive_filtered_frame()')
+
+        for frame_filter in self._options.incoming_frame_filters:
+            frame_filter.filter(frame)
+        for message_filter in self._options.incoming_message_filters:
+            frame.payload = message_filter.filter(frame.payload)
+        return frame
+
+    def send_message(self, message, end=True, binary=False):
+        """Send message.
+
+        Args:
+            message: text in unicode or binary in str to send.
+            binary: send message as binary frame.
+
+        Raises:
+            BadOperationException: when called on a server-terminated
+                connection or called with inconsistent message type or
+                binary parameter.
+        """
+
+        if self._request.server_terminated:
+            raise BadOperationException(
+                'Requested send_message after sending out a closing handshake')
+
+        if binary and isinstance(message, six.text_type):
+            raise BadOperationException(
+                'Message for binary frame must not be instance of Unicode')
+
+        for message_filter in self._options.outgoing_message_filters:
+            message = message_filter.filter(message, end, binary)
+
+        try:
+            # Set this to any positive integer to limit maximum size of data in
+            # payload data of each frame.
+            MAX_PAYLOAD_DATA_SIZE = -1
+
+            if MAX_PAYLOAD_DATA_SIZE <= 0:
+                self._write(self._writer.build(message, end, binary))
+                return
+
+            bytes_written = 0
+            while True:
+                end_for_this_frame = end
+                bytes_to_write = len(message) - bytes_written
+                if (MAX_PAYLOAD_DATA_SIZE > 0
+                        and bytes_to_write > MAX_PAYLOAD_DATA_SIZE):
+                    end_for_this_frame = False
+                    bytes_to_write = MAX_PAYLOAD_DATA_SIZE
+
+                frame = self._writer.build(
+                    message[bytes_written:bytes_written + bytes_to_write],
+                    end_for_this_frame, binary)
+                self._write(frame)
+
+                bytes_written += bytes_to_write
+
+                # This if must be placed here (the end of while block) so that
+                # at least one frame is sent.
+                if len(message) <= bytes_written:
+                    break
+        except ValueError as e:
+            raise BadOperationException(e)
+
+    def _get_message_from_frame(self, frame):
+        """Gets a message from frame. If the message is composed of fragmented
+        frames and the frame is not the last fragmented frame, this method
+        returns None. The whole message will be returned when the last
+        fragmented frame is passed to this method.
+
+        Raises:
+            InvalidFrameException: when the frame doesn't match defragmentation
+                context, or the frame contains invalid data.
+        """
+
+        if frame.opcode == common.OPCODE_CONTINUATION:
+            if not self._received_fragments:
+                if frame.fin:
+                    raise InvalidFrameException(
+                        'Received a termination frame but fragmentation '
+                        'not started')
+                else:
+                    raise InvalidFrameException(
+                        'Received an intermediate frame but '
+                        'fragmentation not started')
+
+            if frame.fin:
+                # End of fragmentation frame
+                self._received_fragments.append(frame.payload)
+                message = b''.join(self._received_fragments)
+                self._received_fragments = []
+                return message
+            else:
+                # Intermediate frame
+                self._received_fragments.append(frame.payload)
+                return None
+        else:
+            if self._received_fragments:
+                if frame.fin:
+                    raise InvalidFrameException(
+                        'Received an unfragmented frame without '
+                        'terminating existing fragmentation')
+                else:
+                    raise InvalidFrameException(
+                        'New fragmentation started without terminating '
+                        'existing fragmentation')
+
+            if frame.fin:
+                # Unfragmented frame
+
+                self._original_opcode = frame.opcode
+                return frame.payload
+            else:
+                # Start of fragmentation frame
+
+                if common.is_control_opcode(frame.opcode):
+                    raise InvalidFrameException(
+                        'Control frames must not be fragmented')
+
+                self._original_opcode = frame.opcode
+                self._received_fragments.append(frame.payload)
+                return None
+
+    def _process_close_message(self, message):
+        """Processes close message.
+
+        Args:
+            message: close message.
+
+        Raises:
+            InvalidFrameException: when the message is invalid.
+        """
+
+        self._request.client_terminated = True
+
+        # Status code is optional. We can have status reason only if we
+        # have status code. Status reason can be empty string. So,
+        # allowed cases are
+        # - no application data: no code no reason
+        # - 2 octet of application data: has code but no reason
+        # - 3 or more octet of application data: both code and reason
+        if len(message) == 0:
+            self._logger.debug('Received close frame (empty body)')
+            self._request.ws_close_code = common.STATUS_NO_STATUS_RECEIVED
+        elif len(message) == 1:
+            raise InvalidFrameException(
+                'If a close frame has status code, the length of '
+                'status code must be 2 octet')
+        elif len(message) >= 2:
+            self._request.ws_close_code = struct.unpack('!H', message[0:2])[0]
+            self._request.ws_close_reason = message[2:].decode(
+                'utf-8', 'replace')
+            self._logger.debug('Received close frame (code=%d, reason=%r)',
+                               self._request.ws_close_code,
+                               self._request.ws_close_reason)
+
+        # As we've received a close frame, no more data is coming over the
+        # socket. We can now safely close the socket without worrying about
+        # RST sending.
+
+        if self._request.server_terminated:
+            self._logger.debug(
+                'Received ack for server-initiated closing handshake')
+            return
+
+        self._logger.debug('Received client-initiated closing handshake')
+
+        code = common.STATUS_NORMAL_CLOSURE
+        reason = ''
+        if hasattr(self._request, '_dispatcher'):
+            dispatcher = self._request._dispatcher
+            code, reason = dispatcher.passive_closing_handshake(self._request)
+            if code is None and reason is not None and len(reason) > 0:
+                self._logger.warning(
+                    'Handler specified reason despite code being None')
+                reason = ''
+            if reason is None:
+                reason = ''
+        self._send_closing_handshake(code, reason)
+        self._logger.debug(
+            'Acknowledged closing handshake initiated by the peer '
+            '(code=%r, reason=%r)', code, reason)
+
+    def _process_ping_message(self, message):
+        """Processes ping message.
+
+        Args:
+            message: ping message.
+        """
+
+        try:
+            handler = self._request.on_ping_handler
+            if handler:
+                handler(self._request, message)
+                return
+        except AttributeError:
+            pass
+        self._send_pong(message)
+
+    def _process_pong_message(self, message):
+        """Processes pong message.
+
+        Args:
+            message: pong message.
+        """
+
+        # TODO(tyoshino): Add ping timeout handling.
+
+        inflight_pings = deque()
+
+        while True:
+            try:
+                expected_body = self._ping_queue.popleft()
+                if expected_body == message:
+                    # inflight_pings contains pings ignored by the
+                    # other peer. Just forget them.
+                    self._logger.debug(
+                        'Ping %r is acked (%d pings were ignored)',
+                        expected_body, len(inflight_pings))
+                    break
+                else:
+                    inflight_pings.append(expected_body)
+            except IndexError:
+                # The received pong was unsolicited pong. Keep the
+                # ping queue as is.
+                self._ping_queue = inflight_pings
+                self._logger.debug('Received a unsolicited pong')
+                break
+
+        try:
+            handler = self._request.on_pong_handler
+            if handler:
+                handler(self._request, message)
+        except AttributeError:
+            pass
+
+    def receive_message(self):
+        """Receive a WebSocket frame and return its payload as a text in
+        unicode or a binary in str.
+
+        Returns:
+            payload data of the frame
+            - as unicode instance if received text frame
+            - as str instance if received binary frame
+            or None iff received closing handshake.
+        Raises:
+            BadOperationException: when called on a client-terminated
+                connection.
+            ConnectionTerminatedException: when read returns empty
+                string.
+            InvalidFrameException: when the frame contains invalid
+                data.
+            UnsupportedFrameException: when the received frame has
+                flags, opcode we cannot handle. You can ignore this
+                exception and continue receiving the next frame.
+        """
+
+        if self._request.client_terminated:
+            raise BadOperationException(
+                'Requested receive_message after receiving a closing '
+                'handshake')
+
+        while True:
+            # mp_conn.read will block if no bytes are available.
+
+            frame = self._receive_frame_as_frame_object()
+
+            # Check the constraint on the payload size for control frames
+            # before extension processes the frame.
+            # See also http://tools.ietf.org/html/rfc6455#section-5.5
+            if (common.is_control_opcode(frame.opcode)
+                    and len(frame.payload) > 125):
+                raise InvalidFrameException(
+                    'Payload data size of control frames must be 125 bytes or '
+                    'less')
+
+            for frame_filter in self._options.incoming_frame_filters:
+                frame_filter.filter(frame)
+
+            if frame.rsv1 or frame.rsv2 or frame.rsv3:
+                raise UnsupportedFrameException(
+                    'Unsupported flag is set (rsv = %d%d%d)' %
+                    (frame.rsv1, frame.rsv2, frame.rsv3))
+
+            message = self._get_message_from_frame(frame)
+            if message is None:
+                continue
+
+            for message_filter in self._options.incoming_message_filters:
+                message = message_filter.filter(message)
+
+            if self._original_opcode == common.OPCODE_TEXT:
+                # The WebSocket protocol section 4.4 specifies that invalid
+                # characters must be replaced with U+fffd REPLACEMENT
+                # CHARACTER.
+                try:
+                    return message.decode('utf-8')
+                except UnicodeDecodeError as e:
+                    raise InvalidUTF8Exception(e)
+            elif self._original_opcode == common.OPCODE_BINARY:
+                return message
+            elif self._original_opcode == common.OPCODE_CLOSE:
+                self._process_close_message(message)
+                return None
+            elif self._original_opcode == common.OPCODE_PING:
+                self._process_ping_message(message)
+            elif self._original_opcode == common.OPCODE_PONG:
+                self._process_pong_message(message)
+            else:
+                raise UnsupportedFrameException('Opcode %d is not supported' %
+                                                self._original_opcode)
+
+    def _send_closing_handshake(self, code, reason):
+        body = create_closing_handshake_body(code, reason)
+        frame = create_close_frame(
+            body,
+            mask=self._options.mask_send,
+            frame_filters=self._options.outgoing_frame_filters)
+
+        self._request.server_terminated = True
+
+        self._write(frame)
+
+    def close_connection(self,
+                         code=common.STATUS_NORMAL_CLOSURE,
+                         reason='',
+                         wait_response=True):
+        """Closes a WebSocket connection. Note that this method blocks until
+        it receives acknowledgement to the closing handshake.
+
+        Args:
+            code: Status code for close frame. If code is None, a close
+                frame with empty body will be sent.
+            reason: string representing close reason.
+            wait_response: True when caller want to wait the response.
+        Raises:
+            BadOperationException: when reason is specified with code None
+                or reason is not an instance of both str and unicode.
+        """
+
+        if self._request.server_terminated:
+            self._logger.debug(
+                'Requested close_connection but server is already terminated')
+            return
+
+        # When we receive a close frame, we call _process_close_message().
+        # _process_close_message() immediately acknowledges to the
+        # server-initiated closing handshake and sets server_terminated to
+        # True. So, here we can assume that we haven't received any close
+        # frame. We're initiating a closing handshake.
+
+        if code is None:
+            if reason is not None and len(reason) > 0:
+                raise BadOperationException(
+                    'close reason must not be specified if code is None')
+            reason = ''
+        else:
+            if not isinstance(reason, bytes) and not isinstance(
+                    reason, six.text_type):
+                raise BadOperationException(
+                    'close reason must be an instance of bytes or unicode')
+
+        self._send_closing_handshake(code, reason)
+        self._logger.debug('Initiated closing handshake (code=%r, reason=%r)',
+                           code, reason)
+
+        if (code == common.STATUS_GOING_AWAY
+                or code == common.STATUS_PROTOCOL_ERROR) or not wait_response:
+            # It doesn't make sense to wait for a close frame if the reason is
+            # protocol error or that the server is going away. For some of
+            # other reasons, it might not make sense to wait for a close frame,
+            # but it's not clear, yet.
+            return
+
+        # TODO(ukai): 2. wait until the /client terminated/ flag has been set,
+        # or until a server-defined timeout expires.
+        #
+        # For now, we expect receiving closing handshake right after sending
+        # out closing handshake.
+        message = self.receive_message()
+        if message is not None:
+            raise ConnectionTerminatedException(
+                'Didn\'t receive valid ack for closing handshake')
+        # TODO: 3. close the WebSocket connection.
+        # note: mod_python Connection (mp_conn) doesn't have close method.
+
+    def send_ping(self, body, binary=False):
+        if not binary and isinstance(body, six.text_type):
+            body = body.encode('UTF-8')
+        frame = create_ping_frame(body, self._options.mask_send,
+                                  self._options.outgoing_frame_filters)
+        self._write(frame)
+
+        self._ping_queue.append(body)
+
+    def _send_pong(self, body):
+        frame = create_pong_frame(body, self._options.mask_send,
+                                  self._options.outgoing_frame_filters)
+        self._write(frame)
+
+    def get_last_received_opcode(self):
+        """Returns the opcode of the WebSocket message which the last received
+        frame belongs to. The return value is valid iff immediately after
+        receive_message call.
+        """
+
+        return self._original_opcode
+
+
+# vi:sts=4 sw=4 et
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/util.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/util.py
new file mode 100644
index 0000000..e164e6b8
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/util.py
@@ -0,0 +1,405 @@
+# Copyright 2011, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""WebSocket utilities."""
+
+from __future__ import absolute_import
+import array
+import errno
+import logging
+import os
+import re
+import six
+from six.moves import map
+from six.moves import range
+import socket
+import struct
+import zlib
+
+try:
+    from mod_pywebsocket import fast_masking
+except ImportError:
+    pass
+
+
+def prepend_message_to_exception(message, exc):
+    """Prepend message to the exception."""
+    exc.args = (message + str(exc), )
+    return
+
+
+def __translate_interp(interp, cygwin_path):
+    """Translate interp program path for Win32 python to run cygwin program
+    (e.g. perl).  Note that it doesn't support path that contains space,
+    which is typically true for Unix, where #!-script is written.
+    For Win32 python, cygwin_path is a directory of cygwin binaries.
+
+    Args:
+      interp: interp command line
+      cygwin_path: directory name of cygwin binary, or None
+    Returns:
+      translated interp command line.
+    """
+    if not cygwin_path:
+        return interp
+    m = re.match('^[^ ]*/([^ ]+)( .*)?', interp)
+    if m:
+        cmd = os.path.join(cygwin_path, m.group(1))
+        return cmd + m.group(2)
+    return interp
+
+
+def get_script_interp(script_path, cygwin_path=None):
+    r"""Get #!-interpreter command line from the script.
+
+    It also fixes command path.  When Cygwin Python is used, e.g. in WebKit,
+    it could run "/usr/bin/perl -wT hello.pl".
+    When Win32 Python is used, e.g. in Chromium, it couldn't.  So, fix
+    "/usr/bin/perl" to "<cygwin_path>\perl.exe".
+
+    Args:
+      script_path: pathname of the script
+      cygwin_path: directory name of cygwin binary, or None
+    Returns:
+      #!-interpreter command line, or None if it is not #!-script.
+    """
+    fp = open(script_path)
+    line = fp.readline()
+    fp.close()
+    m = re.match('^#!(.*)', line)
+    if m:
+        return __translate_interp(m.group(1), cygwin_path)
+    return None
+
+
+def wrap_popen3_for_win(cygwin_path):
+    """Wrap popen3 to support #!-script on Windows.
+
+    Args:
+      cygwin_path:  path for cygwin binary if command path is needed to be
+                    translated.  None if no translation required.
+    """
+    __orig_popen3 = os.popen3
+
+    def __wrap_popen3(cmd, mode='t', bufsize=-1):
+        cmdline = cmd.split(' ')
+        interp = get_script_interp(cmdline[0], cygwin_path)
+        if interp:
+            cmd = interp + ' ' + cmd
+        return __orig_popen3(cmd, mode, bufsize)
+
+    os.popen3 = __wrap_popen3
+
+
+def hexify(s):
+    return ' '.join(['%02x' % x for x in six.iterbytes(s)])
+
+
+def get_class_logger(o):
+    """Return the logging class information."""
+    return logging.getLogger('%s.%s' %
+                             (o.__class__.__module__, o.__class__.__name__))
+
+
+def pack_byte(b):
+    """Pack an integer to network-ordered byte"""
+    return struct.pack('!B', b)
+
+
+class NoopMasker(object):
+    """A NoOp masking object.
+
+    This has the same interface as RepeatedXorMasker but just returns
+    the string passed in without making any change.
+    """
+    def __init__(self):
+        """NoOp."""
+        pass
+
+    def mask(self, s):
+        """NoOp."""
+        return s
+
+
+class RepeatedXorMasker(object):
+    """A masking object that applies XOR on the string.
+
+    Applies XOR on the byte string given to mask method with the masking bytes
+    given to the constructor repeatedly. This object remembers the position
+    in the masking bytes the last mask method call ended and resumes from
+    that point on the next mask method call.
+    """
+    def __init__(self, masking_key):
+        self._masking_key = masking_key
+        self._masking_key_index = 0
+
+    def _mask_using_swig(self, s):
+        """Perform the mask via SWIG."""
+        masked_data = fast_masking.mask(s, self._masking_key,
+                                        self._masking_key_index)
+        self._masking_key_index = ((self._masking_key_index + len(s)) %
+                                   len(self._masking_key))
+        return masked_data
+
+    def _mask_using_array(self, s):
+        """Perform the mask via python."""
+        if isinstance(s, six.text_type):
+            raise Exception(
+                'Masking Operation should not process unicode strings')
+
+        result = bytearray(s)
+
+        # Use temporary local variables to eliminate the cost to access
+        # attributes
+        masking_key = [c for c in six.iterbytes(self._masking_key)]
+        masking_key_size = len(masking_key)
+        masking_key_index = self._masking_key_index
+
+        for i in range(len(result)):
+            result[i] ^= masking_key[masking_key_index]
+            masking_key_index = (masking_key_index + 1) % masking_key_size
+
+        self._masking_key_index = masking_key_index
+
+        return bytes(result)
+
+    if 'fast_masking' in globals():
+        mask = _mask_using_swig
+    else:
+        mask = _mask_using_array
+
+
+# By making wbits option negative, we can suppress CMF/FLG (2 octet) and
+# ADLER32 (4 octet) fields of zlib so that we can use zlib module just as
+# deflate library. DICTID won't be added as far as we don't set dictionary.
+# LZ77 window of 32K will be used for both compression and decompression.
+# For decompression, we can just use 32K to cover any windows size. For
+# compression, we use 32K so receivers must use 32K.
+#
+# Compression level is Z_DEFAULT_COMPRESSION. We don't have to match level
+# to decode.
+#
+# See zconf.h, deflate.cc, inflate.cc of zlib library, and zlibmodule.c of
+# Python. See also RFC1950 (ZLIB 3.3).
+
+
+class _Deflater(object):
+    def __init__(self, window_bits):
+        self._logger = get_class_logger(self)
+
+        # Using the smallest window bits of 9 for generating input frames.
+        # On WebSocket spec, the smallest window bit is 8. However, zlib does
+        # not accept window_bit = 8.
+        #
+        # Because of a zlib deflate quirk, back-references will not use the
+        # entire range of 1 << window_bits, but will instead use a restricted
+        # range of (1 << window_bits) - 262. With an increased window_bits = 9,
+        # back-references will be within a range of 250. These can still be
+        # decompressed with window_bits = 8 and the 256-byte window used there.
+        #
+        # Similar disscussions can be found in https://crbug.com/691074
+        window_bits = max(window_bits, 9)
+
+        self._compress = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
+                                          zlib.DEFLATED, -window_bits)
+
+    def compress(self, bytes):
+        compressed_bytes = self._compress.compress(bytes)
+        self._logger.debug('Compress input %r', bytes)
+        self._logger.debug('Compress result %r', compressed_bytes)
+        return compressed_bytes
+
+    def compress_and_flush(self, bytes):
+        compressed_bytes = self._compress.compress(bytes)
+        compressed_bytes += self._compress.flush(zlib.Z_SYNC_FLUSH)
+        self._logger.debug('Compress input %r', bytes)
+        self._logger.debug('Compress result %r', compressed_bytes)
+        return compressed_bytes
+
+    def compress_and_finish(self, bytes):
+        compressed_bytes = self._compress.compress(bytes)
+        compressed_bytes += self._compress.flush(zlib.Z_FINISH)
+        self._logger.debug('Compress input %r', bytes)
+        self._logger.debug('Compress result %r', compressed_bytes)
+        return compressed_bytes
+
+
+class _Inflater(object):
+    def __init__(self, window_bits):
+        self._logger = get_class_logger(self)
+        self._window_bits = window_bits
+
+        self._unconsumed = b''
+
+        self.reset()
+
+    def decompress(self, size):
+        if not (size == -1 or size > 0):
+            raise Exception('size must be -1 or positive')
+
+        data = b''
+
+        while True:
+            data += self._decompress.decompress(self._unconsumed,
+                                                max(0, size - len(data)))
+            self._unconsumed = self._decompress.unconsumed_tail
+            if self._decompress.unused_data:
+                # Encountered a last block (i.e. a block with BFINAL = 1) and
+                # found a new stream (unused_data). We cannot use the same
+                # zlib.Decompress object for the new stream. Create a new
+                # Decompress object to decompress the new one.
+                #
+                # It's fine to ignore unconsumed_tail if unused_data is not
+                # empty.
+                self._unconsumed = self._decompress.unused_data
+                self.reset()
+                if size >= 0 and len(data) == size:
+                    # data is filled. Don't call decompress again.
+                    break
+                else:
+                    # Re-invoke Decompress.decompress to try to decompress all
+                    # available bytes before invoking read which blocks until
+                    # any new byte is available.
+                    continue
+            else:
+                # Here, since unused_data is empty, even if unconsumed_tail is
+                # not empty, bytes of requested length are already in data. We
+                # don't have to "continue" here.
+                break
+
+        if data:
+            self._logger.debug('Decompressed %r', data)
+        return data
+
+    def append(self, data):
+        self._logger.debug('Appended %r', data)
+        self._unconsumed += data
+
+    def reset(self):
+        self._logger.debug('Reset')
+        self._decompress = zlib.decompressobj(-self._window_bits)
+
+
+# Compresses/decompresses given octets using the method introduced in RFC1979.
+
+
+class _RFC1979Deflater(object):
+    """A compressor class that applies DEFLATE to given byte sequence and
+    flushes using the algorithm described in the RFC1979 section 2.1.
+    """
+    def __init__(self, window_bits, no_context_takeover):
+        self._deflater = None
+        if window_bits is None:
+            window_bits = zlib.MAX_WBITS
+        self._window_bits = window_bits
+        self._no_context_takeover = no_context_takeover
+
+    def filter(self, bytes, end=True, bfinal=False):
+        if self._deflater is None:
+            self._deflater = _Deflater(self._window_bits)
+
+        if bfinal:
+            result = self._deflater.compress_and_finish(bytes)
+            # Add a padding block with BFINAL = 0 and BTYPE = 0.
+            result = result + pack_byte(0)
+            self._deflater = None
+            return result
+
+        result = self._deflater.compress_and_flush(bytes)
+        if end:
+            # Strip last 4 octets which is LEN and NLEN field of a
+            # non-compressed block added for Z_SYNC_FLUSH.
+            result = result[:-4]
+
+        if self._no_context_takeover and end:
+            self._deflater = None
+
+        return result
+
+
+class _RFC1979Inflater(object):
+    """A decompressor class a la RFC1979.
+
+    A decompressor class for byte sequence compressed and flushed following
+    the algorithm described in the RFC1979 section 2.1.
+    """
+    def __init__(self, window_bits=zlib.MAX_WBITS):
+        self._inflater = _Inflater(window_bits)
+
+    def filter(self, bytes):
+        # Restore stripped LEN and NLEN field of a non-compressed block added
+        # for Z_SYNC_FLUSH.
+        self._inflater.append(bytes + b'\x00\x00\xff\xff')
+        return self._inflater.decompress(-1)
+
+
+class DeflateSocket(object):
+    """A wrapper class for socket object to intercept send and recv to perform
+    deflate compression and decompression transparently.
+    """
+
+    # Size of the buffer passed to recv to receive compressed data.
+    _RECV_SIZE = 4096
+
+    def __init__(self, socket):
+        self._socket = socket
+
+        self._logger = get_class_logger(self)
+
+        self._deflater = _Deflater(zlib.MAX_WBITS)
+        self._inflater = _Inflater(zlib.MAX_WBITS)
+
+    def recv(self, size):
+        """Receives data from the socket specified on the construction up
+        to the specified size. Once any data is available, returns it even
+        if it's smaller than the specified size.
+        """
+
+        # TODO(tyoshino): Allow call with size=0. It should block until any
+        # decompressed data is available.
+        if size <= 0:
+            raise Exception('Non-positive size passed')
+        while True:
+            data = self._inflater.decompress(size)
+            if len(data) != 0:
+                return data
+
+            read_data = self._socket.recv(DeflateSocket._RECV_SIZE)
+            if not read_data:
+                return b''
+            self._inflater.append(read_data)
+
+    def sendall(self, bytes):
+        self.send(bytes)
+
+    def send(self, bytes):
+        self._socket.sendall(self._deflater.compress_and_flush(bytes))
+        return len(bytes)
+
+
+# vi:sts=4 sw=4 et
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/websocket_server.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/websocket_server.py
new file mode 100644
index 0000000..df8cd39
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/websocket_server.py
@@ -0,0 +1,285 @@
+# Copyright 2020, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""Standalone WebsocketServer
+
+This file deals with the main module of standalone server. Although it is fine
+to import this file directly to use WebSocketServer, it is strongly recommended
+to use standalone.py, since it is intended to act as a skeleton of this module.
+"""
+
+from __future__ import absolute_import
+from six.moves import BaseHTTPServer
+from six.moves import socketserver
+import logging
+import re
+import select
+import socket
+import ssl
+import threading
+import traceback
+
+from mod_pywebsocket import dispatch
+from mod_pywebsocket import util
+from mod_pywebsocket.request_handler import WebSocketRequestHandler
+
+
+def _alias_handlers(dispatcher, websock_handlers_map_file):
+    """Set aliases specified in websock_handler_map_file in dispatcher.
+
+    Args:
+        dispatcher: dispatch.Dispatcher instance
+        websock_handler_map_file: alias map file
+    """
+
+    with open(websock_handlers_map_file) as f:
+        for line in f:
+            if line[0] == '#' or line.isspace():
+                continue
+            m = re.match('(\S+)\s+(\S+)$', line)
+            if not m:
+                logging.warning('Wrong format in map file:' + line)
+                continue
+            try:
+                dispatcher.add_resource_path_alias(m.group(1), m.group(2))
+            except dispatch.DispatchException as e:
+                logging.error(str(e))
+
+
+class WebSocketServer(socketserver.ThreadingMixIn, BaseHTTPServer.HTTPServer):
+    """HTTPServer specialized for WebSocket."""
+
+    # Overrides SocketServer.ThreadingMixIn.daemon_threads
+    daemon_threads = True
+    # Overrides BaseHTTPServer.HTTPServer.allow_reuse_address
+    allow_reuse_address = True
+
+    def __init__(self, options):
+        """Override SocketServer.TCPServer.__init__ to set SSL enabled
+        socket object to self.socket before server_bind and server_activate,
+        if necessary.
+        """
+
+        # Share a Dispatcher among request handlers to save time for
+        # instantiation.  Dispatcher can be shared because it is thread-safe.
+        options.dispatcher = dispatch.Dispatcher(
+            options.websock_handlers, options.scan_dir,
+            options.allow_handlers_outside_root_dir)
+        if options.websock_handlers_map_file:
+            _alias_handlers(options.dispatcher,
+                            options.websock_handlers_map_file)
+        warnings = options.dispatcher.source_warnings()
+        if warnings:
+            for warning in warnings:
+                logging.warning('Warning in source loading: %s' % warning)
+
+        self._logger = util.get_class_logger(self)
+
+        self.request_queue_size = options.request_queue_size
+        self.__ws_is_shut_down = threading.Event()
+        self.__ws_serving = False
+
+        socketserver.BaseServer.__init__(self,
+                                         (options.server_host, options.port),
+                                         WebSocketRequestHandler)
+
+        # Expose the options object to allow handler objects access it. We name
+        # it with websocket_ prefix to avoid conflict.
+        self.websocket_server_options = options
+
+        self._create_sockets()
+        self.server_bind()
+        self.server_activate()
+
+    def _create_sockets(self):
+        self.server_name, self.server_port = self.server_address
+        self._sockets = []
+        if not self.server_name:
+            # On platforms that doesn't support IPv6, the first bind fails.
+            # On platforms that supports IPv6
+            # - If it binds both IPv4 and IPv6 on call with AF_INET6, the
+            #   first bind succeeds and the second fails (we'll see 'Address
+            #   already in use' error).
+            # - If it binds only IPv6 on call with AF_INET6, both call are
+            #   expected to succeed to listen both protocol.
+            addrinfo_array = [(socket.AF_INET6, socket.SOCK_STREAM, '', '',
+                               ''),
+                              (socket.AF_INET, socket.SOCK_STREAM, '', '', '')]
+        else:
+            addrinfo_array = socket.getaddrinfo(self.server_name,
+                                                self.server_port,
+                                                socket.AF_UNSPEC,
+                                                socket.SOCK_STREAM,
+                                                socket.IPPROTO_TCP)
+        for addrinfo in addrinfo_array:
+            self._logger.info('Create socket on: %r', addrinfo)
+            family, socktype, proto, canonname, sockaddr = addrinfo
+            try:
+                socket_ = socket.socket(family, socktype)
+            except Exception as e:
+                self._logger.info('Skip by failure: %r', e)
+                continue
+            server_options = self.websocket_server_options
+            if server_options.use_tls:
+                if server_options.tls_client_auth:
+                    if server_options.tls_client_cert_optional:
+                        client_cert_ = ssl.CERT_OPTIONAL
+                    else:
+                        client_cert_ = ssl.CERT_REQUIRED
+                else:
+                    client_cert_ = ssl.CERT_NONE
+                socket_ = ssl.wrap_socket(
+                    socket_,
+                    keyfile=server_options.private_key,
+                    certfile=server_options.certificate,
+                    ca_certs=server_options.tls_client_ca,
+                    cert_reqs=client_cert_)
+            self._sockets.append((socket_, addrinfo))
+
+    def server_bind(self):
+        """Override SocketServer.TCPServer.server_bind to enable multiple
+        sockets bind.
+        """
+
+        failed_sockets = []
+
+        for socketinfo in self._sockets:
+            socket_, addrinfo = socketinfo
+            self._logger.info('Bind on: %r', addrinfo)
+            if self.allow_reuse_address:
+                socket_.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+            try:
+                socket_.bind(self.server_address)
+            except Exception as e:
+                self._logger.info('Skip by failure: %r', e)
+                socket_.close()
+                failed_sockets.append(socketinfo)
+            if self.server_address[1] == 0:
+                # The operating system assigns the actual port number for port
+                # number 0. This case, the second and later sockets should use
+                # the same port number. Also self.server_port is rewritten
+                # because it is exported, and will be used by external code.
+                self.server_address = (self.server_name,
+                                       socket_.getsockname()[1])
+                self.server_port = self.server_address[1]
+                self._logger.info('Port %r is assigned', self.server_port)
+
+        for socketinfo in failed_sockets:
+            self._sockets.remove(socketinfo)
+
+    def server_activate(self):
+        """Override SocketServer.TCPServer.server_activate to enable multiple
+        sockets listen.
+        """
+
+        failed_sockets = []
+
+        for socketinfo in self._sockets:
+            socket_, addrinfo = socketinfo
+            self._logger.info('Listen on: %r', addrinfo)
+            try:
+                socket_.listen(self.request_queue_size)
+            except Exception as e:
+                self._logger.info('Skip by failure: %r', e)
+                socket_.close()
+                failed_sockets.append(socketinfo)
+
+        for socketinfo in failed_sockets:
+            self._sockets.remove(socketinfo)
+
+        if len(self._sockets) == 0:
+            self._logger.critical(
+                'No sockets activated. Use info log level to see the reason.')
+
+    def server_close(self):
+        """Override SocketServer.TCPServer.server_close to enable multiple
+        sockets close.
+        """
+
+        for socketinfo in self._sockets:
+            socket_, addrinfo = socketinfo
+            self._logger.info('Close on: %r', addrinfo)
+            socket_.close()
+
+    def fileno(self):
+        """Override SocketServer.TCPServer.fileno."""
+
+        self._logger.critical('Not supported: fileno')
+        return self._sockets[0][0].fileno()
+
+    def handle_error(self, request, client_address):
+        """Override SocketServer.handle_error."""
+
+        self._logger.error('Exception in processing request from: %r\n%s',
+                           client_address, traceback.format_exc())
+        # Note: client_address is a tuple.
+
+    def get_request(self):
+        """Override TCPServer.get_request."""
+
+        accepted_socket, client_address = self.socket.accept()
+
+        server_options = self.websocket_server_options
+        if server_options.use_tls:
+            # Print cipher in use. Handshake is done on accept.
+            self._logger.debug('Cipher: %s', accepted_socket.cipher())
+            self._logger.debug('Client cert: %r',
+                               accepted_socket.getpeercert())
+
+        return accepted_socket, client_address
+
+    def serve_forever(self, poll_interval=0.5):
+        """Override SocketServer.BaseServer.serve_forever."""
+
+        self.__ws_serving = True
+        self.__ws_is_shut_down.clear()
+        handle_request = self.handle_request
+        if hasattr(self, '_handle_request_noblock'):
+            handle_request = self._handle_request_noblock
+        else:
+            self._logger.warning('Fallback to blocking request handler')
+        try:
+            while self.__ws_serving:
+                r, w, e = select.select(
+                    [socket_[0] for socket_ in self._sockets], [], [],
+                    poll_interval)
+                for socket_ in r:
+                    self.socket = socket_
+                    handle_request()
+                self.socket = None
+        finally:
+            self.__ws_is_shut_down.set()
+
+    def shutdown(self):
+        """Override SocketServer.BaseServer.shutdown."""
+
+        self.__ws_serving = False
+        self.__ws_is_shut_down.wait()
+
+
+# vi:sts=4 sw=4 et
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/client.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/client.py
index 73fec5a8..fc4222a9 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/client.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/client.py
@@ -504,7 +504,7 @@
 
         try:
             self.send_command("DELETE", "session/%s" % self.session_id)
-        except error.InvalidSessionIdException:
+        except (OSError, error.InvalidSessionIdException):
             pass
         finally:
             self.session_id = None
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/transport.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/transport.py
index e836b19..33142d3 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/transport.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/transport.py
@@ -145,7 +145,12 @@
     def close(self):
         """Closes the current HTTP connection, if there is one."""
         if self._conn:
-            self._conn.close()
+            try:
+                self._conn.close()
+            except OSError:
+                # The remote closed the connection
+                pass
+        self._conn = None
 
     @property
     def connection(self):
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/server.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/server.py
index d6c6196..d447281 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/server.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/server.py
@@ -17,17 +17,24 @@
 from h2.config import H2Configuration
 from h2.connection import H2Connection
 from h2.events import RequestReceived, ConnectionTerminated, DataReceived, StreamReset, StreamEnded
+from h2.exceptions import StreamClosedError, ProtocolError
+from h2.settings import SettingCodes
+from h2.utilities import extract_method_header
 
 from six.moves.urllib.parse import urlsplit, urlunsplit
 
+from mod_pywebsocket import dispatch
+from mod_pywebsocket.handshake import HandshakeException
+
 from . import routes as default_routes
 from .config import ConfigBuilder
 from .logger import get_logger
 from .request import Server, Request, H2Request
 from .response import Response, H2Response
 from .router import Router
-from .utils import HTTPException, isomorphic_decode
+from .utils import HTTPException, isomorphic_decode, isomorphic_encode
 from .constants import h2_headers
+from .ws_h2_handshake import WsH2Handshaker
 
 # We need to stress test that browsers can send/receive many headers (there is
 # no specified limit), but the Python stdlib has an arbitrary limit of 100
@@ -131,7 +138,7 @@
     daemon_threads = True
 
     def __init__(self, server_address, request_handler_cls,
-                 router, rewriter, bind_address,
+                 router, rewriter, bind_address, ws_doc_root=None,
                  config=None, use_ssl=False, key_file=None, certificate=None,
                  encrypt_after_connect=False, latency=None, http2=False, **kwargs):
         """Server for HTTP(s) Requests
@@ -156,6 +163,8 @@
 
         :param certificate: Path to certificate to use if SSL is enabled.
 
+        :param ws_doc_root: Document root for websockets
+
         :param encrypt_after_connect: For each connection, don't start encryption
                                       until a CONNECT message has been received.
                                       This enables the server to act as a
@@ -195,6 +204,7 @@
 
 
 
+        self.ws_doc_root = ws_doc_root
         self.key_file = key_file
         self.certificate = certificate
         self.encrypt_after_connect = use_ssl and encrypt_after_connect
@@ -353,6 +363,14 @@
         self.logger.debug('(%s) Initiating h2 Connection' % self.uid)
 
         with self.conn as connection:
+            # Bootstrapping WebSockets with HTTP/2 specification requires
+            # ENABLE_CONNECT_PROTOCOL to be set in order to enable WebSocket
+            # over HTTP/2
+            new_settings = dict(connection.local_settings)
+            new_settings[SettingCodes.ENABLE_CONNECT_PROTOCOL] = 1
+            connection.local_settings.update(new_settings)
+            connection.local_settings.acknowledge()
+
             connection.initiate_connection()
             data = connection.data_to_send()
             window_size = connection.remote_settings.initial_window_size
@@ -406,6 +424,24 @@
             for stream_id, (thread, queue) in stream_queues.items():
                 thread.join()
 
+    def _is_extended_connect_frame(self, frame):
+        if not isinstance(frame, RequestReceived):
+            return False
+
+        method = extract_method_header(frame.headers)
+        if method != "CONNECT":
+            return False
+
+        protocol = ""
+        for key, value in frame.headers:
+            if key in (b':protocol', u':protocol'):
+                protocol = isomorphic_encode(value)
+                break
+        if protocol != "websocket":
+            raise ProtocolError("Invalid protocol %s with CONNECT METHOD" % (protocol,))
+
+        return True
+
     def start_stream_thread(self, frame, queue):
         """
         This starts a new thread to handle frames for a specific stream.
@@ -413,13 +449,91 @@
         :param queue: A queue object that the thread will use to check for new frames
         :return: The thread object that has already been started
         """
+        if self._is_extended_connect_frame(frame):
+            target = Http2WebTestRequestHandler._stream_ws_thread
+        else:
+            target = Http2WebTestRequestHandler._stream_thread
         t = threading.Thread(
-            target=Http2WebTestRequestHandler._stream_thread,
+            target=target,
             args=(self, frame.stream_id, queue)
         )
         t.start()
         return t
 
+    def _stream_ws_thread(self, stream_id, queue):
+        frame = queue.get(True, None)
+
+        rfile, wfile = os.pipe()
+        rfile, wfile = os.fdopen(rfile, 'rb'), os.fdopen(wfile, 'wb', 0)  # needs to be unbuffer for websockets
+        stream_handler = H2HandlerCopy(self, frame, rfile)
+
+        h2request = H2Request(stream_handler)
+        h2response = H2Response(stream_handler, h2request)
+
+        dispatcher = dispatch.Dispatcher(self.server.ws_doc_root, None, False)
+        if not dispatcher.get_handler_suite(stream_handler.path):
+            h2response.set_error(404)
+            h2response.write()
+            return
+
+        request_wrapper = _WebSocketRequest(stream_handler, h2response)
+
+        handshaker = WsH2Handshaker(request_wrapper, dispatcher)
+        try:
+            handshaker.do_handshake()
+        except HandshakeException as e:
+            self.logger.info('Handshake failed for error: %s', e)
+            h2response.set_error(e.status)
+            h2response.write()
+            return
+
+        # h2 Handshaker prepares the headers but does not send them down the
+        # wire. Flush the headers here.
+        h2response.write_status_headers()
+
+        request_wrapper._dispatcher = dispatcher
+
+        # we need two threads:
+        # - one to handle the frame queue
+        # - one to handle the request (dispatcher.transfer_data is blocking)
+        # the alternative is to have only one (blocking) thread. That thread
+        # will call transfer_data. That would require a special case in
+        # handle_one_request, to bypass the queue and write data to wfile
+        # directly.
+        t = threading.Thread(
+            target=Http2WebTestRequestHandler._stream_ws_sub_thread,
+            args=(self, request_wrapper, stream_handler, queue)
+        )
+        t.start()
+
+        while not self.close_connection:
+            frame = queue.get(True, None)
+
+            if isinstance(frame, DataReceived):
+                wfile.write(frame.data)
+                if frame.stream_ended:
+                    raise NotImplementedError("frame.stream_ended")
+                    wfile.close()
+            elif frame is None or isinstance(frame, (StreamReset, StreamEnded, ConnectionTerminated)):
+                self.logger.debug('(%s - %s) Stream Reset, Thread Closing' % (self.uid, stream_id))
+                break
+
+        t.join()
+
+    def _stream_ws_sub_thread(self, request, stream_handler, queue):
+        dispatcher = request._dispatcher
+        dispatcher.transfer_data(request)
+
+        stream_id = stream_handler.h2_stream_id
+        with stream_handler.conn as connection:
+            try:
+                connection.end_stream(stream_id)
+                data = connection.data_to_send()
+                stream_handler.request.sendall(data)
+            except StreamClosedError:  # maybe the stream has already been closed
+                pass
+        queue.put(None)
+
     def _stream_thread(self, stream_id, queue):
         """
         This thread processes frames for a specific stream. It waits for frames to be placed
@@ -599,6 +713,7 @@
                                   self-proxy.
     :param router_cls: Router class to use when matching URLs to handlers
     :param doc_root: Document root for serving files
+    :param ws_doc_root: Document root for websockets
     :param routes: List of routes with which to initialize the router
     :param rewriter_cls: Class to use for request rewriter
     :param rewrites: List of rewrites with which to initialize the rewriter_cls
@@ -641,7 +756,7 @@
     def __init__(self, host="127.0.0.1", port=8000,
                  server_cls=None, handler_cls=Http1WebTestRequestHandler,
                  use_ssl=False, key_file=None, certificate=None, encrypt_after_connect=False,
-                 router_cls=Router, doc_root=os.curdir, routes=None,
+                 router_cls=Router, doc_root=os.curdir, ws_doc_root=None, routes=None,
                  rewriter_cls=RequestRewriter, bind_address=True, rewrites=None,
                  latency=None, config=None, http2=False):
 
@@ -673,6 +788,7 @@
                                     self.rewriter,
                                     config=config,
                                     bind_address=bind_address,
+                                    ws_doc_root=ws_doc_root,
                                     use_ssl=use_ssl,
                                     key_file=key_file,
                                     certificate=certificate,
@@ -727,3 +843,54 @@
         return urlunsplit(("http" if not self.use_ssl else "https",
                            "%s:%s" % (self.host, self.port),
                            path, query, fragment))
+
+
+class _WebSocketConnection(object):
+    def __init__(self, request_handler, response):
+        """Mimic mod_python mp_conn.
+
+        :param request_handler: A H2HandlerCopy instance.
+
+        :param response: A H2Response instance.
+        """
+
+        self._request_handler = request_handler
+        self._response = response
+
+        self.remote_addr = self._request_handler.client_address
+
+    def write(self, data):
+        self._response.writer.write_data(data, False)
+
+    def read(self, length):
+        return self._request_handler.rfile.read(length)
+
+
+class _WebSocketRequest(object):
+    def __init__(self, request_handler, response):
+        """Mimic mod_python request.
+
+        :param request_handler: A H2HandlerCopy instance.
+
+        :param response: A H2Response instance.
+        """
+
+        self.connection = _WebSocketConnection(request_handler, response)
+        self._response = response
+
+        self.uri = request_handler.path
+        self.unparsed_uri = request_handler.path
+        self.method = request_handler.command
+        # read headers from request_handler
+        self.headers_in = request_handler.headers
+        # write headers directly into H2Response
+        self.headers_out = response.headers
+
+    # proxies status to H2Response
+    @property
+    def status(self):
+        return self._response.status
+
+    @status.setter
+    def status(self, status):
+        self._response.status = status
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/stash.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/stash.py
index 6b351847..535355a 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/stash.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/stash.py
@@ -1,8 +1,10 @@
 import base64
 import json
 import os
-import uuid
+import six
 import threading
+import uuid
+
 from multiprocessing.managers import AcquirerProxy, BaseManager, DictProxy
 from six import text_type, binary_type
 
@@ -32,13 +34,16 @@
 
 
 class StashServer(object):
-    def __init__(self, address=None, authkey=None):
+    def __init__(self, address=None, authkey=None, mp_context=None):
         self.address = address
         self.authkey = authkey
         self.manager = None
+        self.mp_context = mp_context
 
     def __enter__(self):
-        self.manager, self.address, self.authkey = start_server(self.address, self.authkey)
+        self.manager, self.address, self.authkey = start_server(self.address,
+                                                                self.authkey,
+                                                                self.mp_context)
         store_env_config(self.address, self.authkey)
 
     def __exit__(self, *args, **kwargs):
@@ -61,10 +66,13 @@
     os.environ["WPT_STASH_CONFIG"] = json.dumps((address, authkey.decode("ascii")))
 
 
-def start_server(address=None, authkey=None):
+def start_server(address=None, authkey=None, mp_context=None):
     if isinstance(authkey, text_type):
         authkey = authkey.encode("ascii")
-    manager = ServerDictManager(address, authkey)
+    kwargs = {}
+    if six.PY3 and mp_context is not None:
+        kwargs["ctx"] = mp_context
+    manager = ServerDictManager(address, authkey, **kwargs)
     manager.start()
 
     return (manager, manager._address, manager._authkey)
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/ws_h2_handshake.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/ws_h2_handshake.py
new file mode 100644
index 0000000..98796c0
--- /dev/null
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/ws_h2_handshake.py
@@ -0,0 +1,247 @@
+"""This file provides the opening handshake processor for the Bootstrapping
+WebSockets with HTTP/2 protocol (RFC 8441).
+
+Specification:
+https://tools.ietf.org/html/rfc8441
+"""
+
+from __future__ import absolute_import
+
+from mod_pywebsocket import common
+from mod_pywebsocket.stream import Stream
+from mod_pywebsocket.stream import StreamOptions
+from mod_pywebsocket import util
+from six.moves import map
+from six.moves import range
+
+# TODO: We are using "private" methods of pywebsocket. We might want to
+# refactor pywebsocket to expose those methods publicly. Also, _get_origin
+# _check_version _set_protocol _parse_extensions and a large part of do_handshake
+# are identical with hybi handshake. We need some refactoring to get remove that
+# code duplication.
+from mod_pywebsocket.extensions import get_extension_processor
+from mod_pywebsocket.handshake._base import get_mandatory_header
+from mod_pywebsocket.handshake._base import HandshakeException
+from mod_pywebsocket.handshake._base import parse_token_list
+from mod_pywebsocket.handshake._base import validate_mandatory_header
+from mod_pywebsocket.handshake._base import validate_subprotocol
+from mod_pywebsocket.handshake._base import VersionException
+
+# Defining aliases for values used frequently.
+_VERSION_LATEST = common.VERSION_HYBI_LATEST
+_VERSION_LATEST_STRING = str(_VERSION_LATEST)
+_SUPPORTED_VERSIONS = [
+    _VERSION_LATEST,
+]
+
+
+def check_connect_method(request):
+    if request.method != u'CONNECT':
+        raise HandshakeException('Method is not CONNECT: %r' % request.method)
+
+
+class WsH2Handshaker(object):
+    def __init__(self, request, dispatcher):
+        """Opening handshake processor for the WebSocket protocol (RFC 6455).
+
+        :param request: mod_python request.
+
+        :param dispatcher: Dispatcher (dispatch.Dispatcher).
+
+        WsH2Handshaker will add attributes such as ws_resource during handshake.
+        """
+
+        self._logger = util.get_class_logger(self)
+
+        self._request = request
+        self._dispatcher = dispatcher
+
+    def _get_extension_processors_requested(self):
+        processors = []
+        if self._request.ws_requested_extensions is not None:
+            for extension_request in self._request.ws_requested_extensions:
+                processor = get_extension_processor(extension_request)
+                # Unknown extension requests are just ignored.
+                if processor is not None:
+                    processors.append(processor)
+        return processors
+
+    def do_handshake(self):
+        self._request.ws_close_code = None
+        self._request.ws_close_reason = None
+
+        # Parsing.
+
+        check_connect_method(self._request)
+
+        validate_mandatory_header(self._request, ':protocol', 'websocket')
+
+        self._request.ws_resource = self._request.uri
+
+        get_mandatory_header(self._request, 'authority')
+
+        self._request.ws_version = self._check_version()
+
+        try:
+            self._get_origin()
+            self._set_protocol()
+            self._parse_extensions()
+
+            # Setup extension processors.
+            self._request.ws_extension_processors = self._get_extension_processors_requested()
+
+            # List of extra headers. The extra handshake handler may add header
+            # data as name/value pairs to this list and pywebsocket appends
+            # them to the WebSocket handshake.
+            self._request.extra_headers = []
+
+            # Extra handshake handler may modify/remove processors.
+            self._dispatcher.do_extra_handshake(self._request)
+            processors = [
+                processor
+                for processor in self._request.ws_extension_processors
+                if processor is not None
+            ]
+
+            # Ask each processor if there are extensions on the request which
+            # cannot co-exist. When processor decided other processors cannot
+            # co-exist with it, the processor marks them (or itself) as
+            # "inactive". The first extension processor has the right to
+            # make the final call.
+            for processor in reversed(processors):
+                if processor.is_active():
+                    processor.check_consistency_with_other_processors(
+                        processors)
+            processors = [
+                processor for processor in processors if processor.is_active()
+            ]
+
+            accepted_extensions = []
+
+            stream_options = StreamOptions()
+
+            for index, processor in enumerate(processors):
+                if not processor.is_active():
+                    continue
+
+                extension_response = processor.get_extension_response()
+                if extension_response is None:
+                    # Rejected.
+                    continue
+
+                accepted_extensions.append(extension_response)
+
+                processor.setup_stream_options(stream_options)
+
+                # Inactivate all of the following compression extensions.
+                for j in range(index + 1, len(processors)):
+                    processors[j].set_active(False)
+
+            if len(accepted_extensions) > 0:
+                self._request.ws_extensions = accepted_extensions
+                self._logger.debug(
+                    'Extensions accepted: %r',
+                    list(
+                        map(common.ExtensionParameter.name,
+                            accepted_extensions)))
+            else:
+                self._request.ws_extensions = None
+
+            self._request.ws_stream = self._create_stream(stream_options)
+
+            if self._request.ws_requested_protocols is not None:
+                if self._request.ws_protocol is None:
+                    raise HandshakeException(
+                        'do_extra_handshake must choose one subprotocol from '
+                        'ws_requested_protocols and set it to ws_protocol')
+                validate_subprotocol(self._request.ws_protocol)
+
+                self._logger.debug('Subprotocol accepted: %r',
+                                   self._request.ws_protocol)
+            else:
+                if self._request.ws_protocol is not None:
+                    raise HandshakeException(
+                        'ws_protocol must be None when the client didn\'t '
+                        'request any subprotocol')
+
+            self._prepare_handshake_response()
+        except HandshakeException as e:
+            if not e.status:
+                # Fallback to 400 bad request by default.
+                e.status = common.HTTP_STATUS_BAD_REQUEST
+            raise e
+
+    def _get_origin(self):
+        origin = self._request.headers_in.get('origin')
+        if origin is None:
+            self._logger.debug('Client request does not have origin header')
+        self._request.ws_origin = origin
+
+    def _check_version(self):
+        sec_websocket_version_header = 'sec-websocket-version'
+        version = get_mandatory_header(self._request, sec_websocket_version_header)
+        if version == _VERSION_LATEST_STRING:
+            return _VERSION_LATEST
+
+        if version.find(',') >= 0:
+            raise HandshakeException(
+                'Multiple versions (%r) are not allowed for header %s' %
+                (version, sec_websocket_version_header),
+                status=common.HTTP_STATUS_BAD_REQUEST)
+        raise VersionException('Unsupported version %r for header %s' %
+                               (version, sec_websocket_version_header),
+                               supported_versions=', '.join(
+                                   map(str, _SUPPORTED_VERSIONS)))
+
+    def _set_protocol(self):
+        self._request.ws_protocol = None
+
+        protocol_header = self._request.headers_in.get('sec-websocket-protocol')
+
+        if protocol_header is None:
+            self._request.ws_requested_protocols = None
+            return
+
+        self._request.ws_requested_protocols = parse_token_list(
+            protocol_header)
+        self._logger.debug('Subprotocols requested: %r',
+                           self._request.ws_requested_protocols)
+
+    def _parse_extensions(self):
+        extensions_header = self._request.headers_in.get('sec-websocket-extensions')
+        if not extensions_header:
+            self._request.ws_requested_extensions = None
+            return
+
+        try:
+            self._request.ws_requested_extensions = common.parse_extensions(
+                extensions_header)
+        except common.ExtensionParsingException as e:
+            raise HandshakeException(
+                'Failed to parse sec-websocket-extensions header: %r' % e)
+
+        self._logger.debug(
+            'Extensions requested: %r',
+            list(
+                map(common.ExtensionParameter.name,
+                    self._request.ws_requested_extensions)))
+
+    def _create_stream(self, stream_options):
+        return Stream(self._request, stream_options)
+
+    def _prepare_handshake_response(self):
+        self._request.status = 200
+
+        self._request.headers_out['upgrade'] = common.WEBSOCKET_UPGRADE_TYPE
+        self._request.headers_out['connection'] = common.UPGRADE_CONNECTION_TYPE
+
+        if self._request.ws_protocol is not None:
+            self._request.headers_out['sec-websocket-protocol'] = self._request.ws_protocol
+
+        if (self._request.ws_extensions is not None and
+                len(self._request.ws_extensions) != 0):
+            self._request.headers_out['sec-websocket-extensions'] = common.format_extensions(self._request.ws_extensions)
+
+        # Headers not specific for WebSocket
+        for name, value in self._request.extra_headers:
+            self._request.headers_out[name] = value
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index e8f6164..2b22196 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -4080,6 +4080,8 @@
 crbug.com/681468 [ Win ] virtual/scalefactor200withzoom/fast/hidpi/static/data-suggestion-picker-appearance.html [ Failure Pass Timeout ]
 crbug.com/681468 [ Win ] virtual/scalefactor200/fast/hidpi/static/data-suggestion-picker-appearance.html [ Failure Pass Timeout ]
 
+crbug.com/1157857 [ Mac10.14 ] virtual/percent-based-scrolling/max-percent-delta-cross-origin-iframes.html [ Pass Timeout ]
+
 crbug.com/683800 [ Win7 Debug ] external/wpt/selection/* [ Failure Pass ]
 
 # Importing 'fetch' tests from WPT.
@@ -5773,7 +5775,6 @@
 crbug.com/1123116 external/wpt/feature-policy/reporting/xr-reporting.https.html [ Timeout ]
 
 crbug.com/1159445 [ Mac ] paint/invalidation/repaint-overlay/layers-overlay.html [ Failure ]
-crbug.com/1159446 [ Mac ] virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-basic-006.xht [ Failure ]
 
 crbug.com/1140329 http/tests/devtools/network/network-filter-service-worker.js [ Pass Timeout Failure ]
 crbug.com/1140329 virtual/threaded/external/wpt/web-animations/timing-model/animations/updating-the-finished-state.html [ Pass Failure Timeout ]
@@ -5900,7 +5901,6 @@
 # Sheriff 2020-12-11
 # Flaking on Linux Trusty
 crbug.com/1157849 [ Linux Release ] external/wpt/webrtc/RTCPeerConnection-iceConnectionState.https.html [ Pass Timeout ]
-crbug.com/1157857 [ Mac10.14 ] virtual/compositor-threaded-percent-based-scrolling-dsf-2/virtual/percent-based-scrolling/max-percent-delta-cross-origin-iframes.html [ Pass Timeout ]
 crbug.com/1157861 http/tests/devtools/a11y-axe-core/sources/javascript-breakpoints-a11y-test.js [ Pass Failure ]
 crbug.com/1157861 http/tests/devtools/extensions/extensions-resources.js [ Pass Failure ]
 crbug.com/1157861 http/tests/devtools/console/paintworklet-console-selector.js [ Pass Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/sandboxing/sandbox-inherited-from-required-csp-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/sandboxing/sandbox-inherited-from-required-csp-expected.txt
new file mode 100644
index 0000000..9e875fecf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/sandboxing/sandbox-inherited-from-required-csp-expected.txt
@@ -0,0 +1,10 @@
+This is a testharness.js-based test.
+FAIL initial empty document assert_equals: expected "document-domain-is-not-allowed" but got "document-domain-is-allowed"
+FAIL about:blank assert_equals: expected "document-domain-is-not-allowed" but got "document-domain-is-allowed"
+PASS data-url
+FAIL srcdoc assert_equals: expected "document-domain-is-not-allowed" but got "document-domain-is-allowed"
+PASS blob URL
+PASS same-origin
+PASS cross-origin
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/sandboxing/sandbox-inherited-from-required-csp.html b/third_party/blink/web_tests/external/wpt/html/browsers/sandboxing/sandbox-inherited-from-required-csp.html
new file mode 100644
index 0000000..d1bc4d1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/sandboxing/sandbox-inherited-from-required-csp.html
@@ -0,0 +1,141 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Inherit sandbox from CSP embedded enforcement</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<body>
+<script>
+// Check sandbox flags are properly defined when its parent requires them and
+// the child allows it.
+
+const same_origin = get_host_info().HTTPS_ORIGIN;
+const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+const check_sandbox_url =
+  "/html/browsers/sandboxing/resources/check-sandbox-flags.html?pipe=";
+const allow_csp_from_star = "|header(Allow-CSP-From,*)";
+
+// Return a promise, resolving when |element| triggers |event_name| event.
+const future = (element, event_name) => {
+  return new Promise(resolve => {
+    element.addEventListener(event_name, event => resolve(event))
+  });
+};
+
+const check_sandbox_script = `
+  try {
+    document.domain = document.domain;
+    parent.postMessage("document-domain-is-allowed", "*");
+  } catch (exception) {
+    parent.postMessage("document-domain-is-disallowed", "*");
+  }
+`;
+
+const sandbox_policy = "sandbox allow-scripts allow-same-origin";
+
+promise_test(async test => {
+  const iframe = document.createElement("iframe");
+  iframe.csp = sandbox_policy;
+
+  // The <iframe> immediately hosts the initial empty document after being
+  // appended into the DOM. It will, as long as its 'src' isn't loaded. That's
+  // why a page do not load is being used.
+  iframe.src = "/fetch/api/resources/infinite-slow-response.py";
+  document.body.appendChild(iframe);
+
+  const iframe_reply = future(window, "message");
+  iframe.contentWindow.location =
+    `javascript:${encodeURI(check_sandbox_script)}`;
+  const result = await iframe_reply;
+  iframe.remove();
+
+  assert_equals(result.data, "document-domain-is-not-allowed");
+}, "initial empty document");
+
+promise_test(async test => {
+  const iframe = document.createElement("iframe");
+  iframe.src = "data:text/html,dummy";
+
+  const iframe_load_1 = future(iframe, "load");
+  document.body.appendChild(iframe);
+  await iframe_load_1;
+
+  const iframe_load_2 = future(iframe, "load");
+  iframe.csp = sandbox_policy;
+  iframe.src = "about:blank";
+  await iframe_load_2;
+
+  const iframe_reply = future(window, "message");
+  iframe.contentWindow.location =
+    `javascript:${encodeURI(check_sandbox_script)}`;
+  const result = await iframe_reply;
+
+  assert_equals(result.data, "document-domain-is-not-allowed");
+}, "about:blank");
+
+promise_test(async test => {
+  const iframe = document.createElement("iframe");
+  iframe.csp = sandbox_policy;
+  iframe.src =
+    `data:text/html,<script>${encodeURI(check_sandbox_script)}</scr`+`ipt>`;
+
+  const iframe_reply = future(window, "message");
+  document.body.appendChild(iframe);
+  const result = await iframe_reply;
+
+  assert_equals(result.data, "document-domain-is-disallowed");
+}, "data-url");
+
+promise_test(async test => {
+  const iframe = document.createElement("iframe");
+  iframe.csp = sandbox_policy;
+  iframe.srcdoc = `<script>${check_sandbox_script}</scr`+`ipt>`;
+
+  const iframe_reply = future(window, "message");
+  document.body.appendChild(iframe);
+  const result = await iframe_reply;
+
+  assert_equals(result.data, "document-domain-is-not-allowed");
+}, "srcdoc");
+
+promise_test(async test => {
+  const iframe = document.createElement("iframe");
+  iframe.csp = sandbox_policy;
+
+  const blob = new Blob(
+    [ `<script>${check_sandbox_script}</scr`+`ipt>` ], { type: "text/html" });
+
+  iframe.src = URL.createObjectURL(blob);
+
+  const iframe_reply = future(window, "message");
+  document.body.appendChild(iframe);
+  const result = await iframe_reply;
+
+  assert_equals(result.data, "document-domain-is-disallowed");
+}, "blob URL");
+
+promise_test(async test => {
+  const iframe = document.createElement("iframe");
+  iframe.csp = sandbox_policy;
+  iframe.src = same_origin + check_sandbox_url + allow_csp_from_star;
+
+  const iframe_reply = future(window, "message");
+  document.body.appendChild(iframe);
+  const result = await iframe_reply;
+
+  assert_equals(result.data, "document-domain-is-disallowed");
+}, "same-origin");
+
+promise_test(async test => {
+  const iframe = document.createElement("iframe");
+  iframe.csp = sandbox_policy;
+  iframe.src = cross_origin + check_sandbox_url + allow_csp_from_star;
+
+  const iframe_reply = future(window, "message");
+  document.body.appendChild(iframe);
+  const result = await iframe_reply;
+
+  assert_equals(result.data, "document-domain-is-disallowed");
+}, "cross-origin");
+
+</script>
diff --git a/third_party/blink/web_tests/http/tests/devtools/profiler/agents-disabled-check-expected.txt b/third_party/blink/web_tests/http/tests/devtools/profiler/agents-disabled-check-expected.txt
index cd58c9a..ef01736 100644
--- a/third_party/blink/web_tests/http/tests/devtools/profiler/agents-disabled-check-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/profiler/agents-disabled-check-expected.txt
@@ -6,6 +6,7 @@
 frontend: {"id":<number>,"method":"Debugger.setAsyncCallStackDepth","params":{"maxDepth":0}}
 frontend: {"id":<number>,"method":"Overlay.disable","params":{}}
 frontend: {"id":<number>,"method":"Target.setAutoAttach","params":{"autoAttach":true,"waitForDebuggerOnStart":false,"flatten":true}}
+frontend: {"id":<number>,"method":"Overlay.setShowGridOverlays","params":{"gridNodeHighlightConfigs":[]}}
 frontend: {"id":<number>,"method":"Debugger.disable","params":{}}
 
 --> SDK.targetManager.resumeAllTargets();
diff --git a/third_party/blink/web_tests/http/tests/devtools/profiler/agents-disabled-check.js b/third_party/blink/web_tests/http/tests/devtools/profiler/agents-disabled-check.js
index 0ec600b8..c02ff48 100644
--- a/third_party/blink/web_tests/http/tests/devtools/profiler/agents-disabled-check.js
+++ b/third_party/blink/web_tests/http/tests/devtools/profiler/agents-disabled-check.js
@@ -20,12 +20,7 @@
   ProtocolClient.test.dumpProtocol = null;
   for (var i = 0; i < messages.length; ++i) {
     var message = messages[i];
-    if (message.startsWith('backend'))
-      continue;
-    // Manually remove "Grid" because CSS Grid is still experimental but enabled by default
-    // see: https://crrev.com/c/2416525
-    // TODO: remove this and update test expectations once CSS Grid is non-experimental
-    if (message.includes('setShowGridOverlays')) {
+    if (message.startsWith('backend')) {
       continue;
     }
     message = message.replace(/"id":\d+,/, '"id":<number>,');
diff --git a/third_party/blink/web_tests/http/tests/devtools/quick-open/command-menu-expected.txt b/third_party/blink/web_tests/http/tests/devtools/quick-open/command-menu-expected.txt
index ae77112..41bb6a47 100644
--- a/third_party/blink/web_tests/http/tests/devtools/quick-open/command-menu-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/quick-open/command-menu-expected.txt
@@ -7,6 +7,7 @@
 Has category: Drawer
 Has category: Elements
 Has category: Global
+Has category: Grid
 Has category: Mobile
 Has category: Network
 Has category: Panel
diff --git a/third_party/blink/web_tests/http/tests/devtools/quick-open/command-menu.js b/third_party/blink/web_tests/http/tests/devtools/quick-open/command-menu.js
index 982af2f..83265778 100644
--- a/third_party/blink/web_tests/http/tests/devtools/quick-open/command-menu.js
+++ b/third_party/blink/web_tests/http/tests/devtools/quick-open/command-menu.js
@@ -13,11 +13,6 @@
       commands.set(command.category() + ': ' + command.title(), command);
     });
 
-    // Manually remove "Grid" because CSS Grid is still experimental but enabled by default
-    // see: https://crrev.com/c/2416525
-    // TODO: remove this and update test expectations once CSS Grid is non-experimental
-    categories.delete('Grid');
-
     TestRunner.addResult('Categories active:');
     Array.from(categories).sort().forEach(category => TestRunner.addResult('Has category: ' + category));
 
diff --git a/third_party/blink/web_tests/inspector-protocol/performance-timeline/largest-contentful-paint-expected.txt b/third_party/blink/web_tests/inspector-protocol/performance-timeline/largest-contentful-paint-expected.txt
new file mode 100644
index 0000000..0a92b513
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/performance-timeline/largest-contentful-paint-expected.txt
@@ -0,0 +1,31 @@
+Basic test for LargestContentfulPaint support in PerformanceTimeline
+[
+    [0] : {
+        frameId : <string>
+        lcpDetails : {
+            elementId : text
+            loadTime : <number>
+            nodeId : <div#text>
+            renderTime : <number>
+            size : 48000
+        }
+        name : 
+        time : <number>
+        type : largest-contentful-paint
+    }
+    [1] : {
+        frameId : <string>
+        lcpDetails : {
+            elementId : image
+            loadTime : <number>
+            nodeId : <img#image>
+            renderTime : <number>
+            size : 65536
+            url : .../images/resources/green-256x256.jpg
+        }
+        name : 
+        time : <number>
+        type : largest-contentful-paint
+    }
+]
+
diff --git a/third_party/blink/web_tests/inspector-protocol/performance-timeline/largest-contentful-paint.js b/third_party/blink/web_tests/inspector-protocol/performance-timeline/largest-contentful-paint.js
new file mode 100644
index 0000000..cc7fe53
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/performance-timeline/largest-contentful-paint.js
@@ -0,0 +1,53 @@
+(async function(testRunner) {
+  const {page, session, dp} = await testRunner.startBlank('Basic test for LargestContentfulPaint support in PerformanceTimeline');
+  const unstableFields = ['time', 'renderTime', 'loadTime', 'frameId'];
+
+  const events = [];
+  const startTime = Date.now();
+  await dp.PerformanceTimeline.enable({eventTypes: ['largest-contentful-paint']});
+
+  dp.PerformanceTimeline.onTimelineEventAdded(event => events.push(event.params.event));
+  session.navigate(testRunner.url('resources/lcp.html'));
+  await dp.PerformanceTimeline.onceTimelineEventAdded();
+
+  session.evaluate(`
+    const img = document.createElement("img");
+    img.id = "image";
+    img.src = "${testRunner.url('../../images/resources/green-256x256.jpg')}";
+    document.body.appendChild(img);
+  `);
+  await dp.PerformanceTimeline.onceTimelineEventAdded();
+
+  const endTime = Date.now();
+
+  for (const event of events) {
+    checkTime(event.time);
+    if (event.lcpDetails.renderTime)
+      checkTime(event.lcpDetails.renderTime);
+    if (event.lcpDetails.loadTime)
+      checkTime(event.lcpDetails.loadTime);
+    await patchFields(event.lcpDetails);
+  }
+
+  testRunner.log(events, null, unstableFields);
+  testRunner.completeTest();
+
+  function checkTime(time) {
+    const timeInMs = time * 1000;
+    if (timeInMs < startTime || timeInMs > endTime)
+      testRunner.log(`FAIL: event time out of bounds, expect ${startTime} <= ${timeInMs} <= ${endTime}`);
+  }
+
+  async function patchFields(object) {
+    if (object.url)
+      object.url = testRunner.trimURL(object.url);
+    if (object.nodeId)
+      object.nodeId = await describeNode(object.nodeId);
+  }
+
+  async function describeNode(nodeId) {
+    const response = await dp.DOM.resolveNode({backendNodeId: nodeId});
+    return response.result && response.result.object.description ?
+        `<${response.result.object.description}>` : '<invalid id>';
+  }
+})
diff --git a/third_party/blink/web_tests/inspector-protocol/performance-timeline/resources/lcp.html b/third_party/blink/web_tests/inspector-protocol/performance-timeline/resources/lcp.html
new file mode 100644
index 0000000..20bf829c
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/performance-timeline/resources/lcp.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>LCP Test Page</title>
+<style>
+  body {
+    font: 10px Ahem;
+  }
+</style>
+<body>
+<script src="/resources/ahem.js"></script>
+<div id="text" style="width: 400px;">
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+</div>
+</body>
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-basic-006-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-basic-006-expected.txt
deleted file mode 100644
index 4859b71..0000000
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-basic-006-expected.txt
+++ /dev/null
Binary files differ
diff --git a/third_party/closure_compiler/compiler.py b/third_party/closure_compiler/compiler.py
index 68fdefe..e36f24f 100755
--- a/third_party/closure_compiler/compiler.py
+++ b/third_party/closure_compiler/compiler.py
@@ -6,6 +6,8 @@
 """Runs Closure compiler on JavaScript files to check for errors and produce
 minified output."""
 
+from __future__ import print_function
+
 import os
 import subprocess
 
@@ -43,7 +45,7 @@
       msg: A debug message to log.
     """
     if self._verbose:
-      print "(INFO) %s" % msg
+      print("(INFO) %s" % msg)
 
   def run_jar(self, jar, args):
     """Runs a .jar from the command line with arguments.
diff --git a/third_party/closure_compiler/js_binary.py b/third_party/closure_compiler/js_binary.py
index 9b84fb52..e490fd9 100644
--- a/third_party/closure_compiler/js_binary.py
+++ b/third_party/closure_compiler/js_binary.py
@@ -11,6 +11,8 @@
 extern files can also be passed in using the --extern flag.
 """
 
+from __future__ import print_function
+
 import argparse
 import os
 import sys
@@ -123,8 +125,8 @@
 
   returncode, errors = compiler.Compiler().run_jar(args.compiler, compiler_args)
   if returncode != 0:
-    print args.compiler, ' '.join(compiler_args)
-    print errors
+    print(args.compiler, ' '.join(compiler_args))
+    print(errors)
 
   return returncode
 
diff --git a/third_party/node/linux/node-linux-x64.tar.gz.sha1 b/third_party/node/linux/node-linux-x64.tar.gz.sha1
index 1f8f8f6..e99bd50 100644
--- a/third_party/node/linux/node-linux-x64.tar.gz.sha1
+++ b/third_party/node/linux/node-linux-x64.tar.gz.sha1
@@ -1 +1 @@
-4572d3801500bcbebafadf203056d6263c840cda
+b2e40ddbac04d05baafbb007f203c6663c9d4ca9
diff --git a/third_party/node/mac/node-darwin-x64.tar.gz.sha1 b/third_party/node/mac/node-darwin-x64.tar.gz.sha1
index 61480b4..aa467ef 100644
--- a/third_party/node/mac/node-darwin-x64.tar.gz.sha1
+++ b/third_party/node/mac/node-darwin-x64.tar.gz.sha1
@@ -1 +1 @@
-6b9eefd982e255d639234acfa1d772c34a2529cb
+17ba7216e09de1bffb9dc80b7ec617a1cee40330
diff --git a/third_party/node/update_node_binaries b/third_party/node/update_node_binaries
index fa55b471..8762b28a 100755
--- a/third_party/node/update_node_binaries
+++ b/third_party/node/update_node_binaries
@@ -15,7 +15,7 @@
 cd "$(dirname "$0")"
 
 BASE_URL="https://nodejs.org/dist"
-NODE_VERSION="v12.14.1"
+NODE_VERSION="v14.15.4"
 
 update_unix() {
   local SUFFIX="$1"
diff --git a/third_party/node/win/node.exe.sha1 b/third_party/node/win/node.exe.sha1
index 7c1d133..90d3903 100644
--- a/third_party/node/win/node.exe.sha1
+++ b/third_party/node/win/node.exe.sha1
@@ -1 +1 @@
-a25b445d6e02de0fdbf426d5cfd193702351989e
+58bca4fea5196d856e41f928c02f6d6af2421865
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index 0712027b..f53dd8a1 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -238,7 +238,8 @@
     "META": {"sizes": {"includes": [10],}},
     "includes": [2080],
   },
-  "chrome/browser/resources/invalidations/invalidations_resources.grd": {
+  "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/invalidations/resources.grd": {
+    "META": {"sizes": {"includes": [10],}},
     "includes": [2090],
   },
   "chrome/browser/resources/media/webrtc_logs_resources.grd": {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 926dd33..316b845 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -77717,6 +77717,9 @@
 </enum>
 
 <enum name="WebpDecodedFormat">
+  <obsolete>
+    Removed in M89.
+  </obsolete>
   <int value="1" label="JPEG"/>
   <int value="2" label="PNG"/>
   <int value="3" label="TIFF"/>
diff --git a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
index d4dd494..b9628ce 100644
--- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -12973,7 +12973,11 @@
 <histogram_suffixes name="PageLoadMetricsClientsServiceWorkerSpecialApps"
     separator=".">
   <suffix name="docs" label="Custom histogram for the Google Docs page"/>
-  <suffix name="inbox" label="Custom histogram for Inbox"/>
+  <suffix name="inbox" label="Custom histogram for Inbox">
+    <obsolete>
+      Removed December 2020.
+    </obsolete>
+  </suffix>
   <suffix name="search"
       label="Custom histogram for the Google Search results page"/>
   <affected-histogram
diff --git a/tools/metrics/histograms/histograms_xml/memory/histograms.xml b/tools/metrics/histograms/histograms_xml/memory/histograms.xml
index 3a38ed46..4ab40643 100644
--- a/tools/metrics/histograms/histograms_xml/memory/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/memory/histograms.xml
@@ -283,7 +283,7 @@
 </histogram>
 
 <histogram name="Memory.Browser.MemoryFootprint.NumLiveOverscroll" units="tabs"
-    expires_after="M88">
+    expires_after="M91">
   <owner>rkgibson@google.com</owner>
   <owner>eugenebut@chromium.org</owner>
   <summary>
@@ -298,7 +298,7 @@
 </histogram>
 
 <histogram name="Memory.Browser.MemoryFootprint.NumOpenTabs" units="tabs"
-    expires_after="M88">
+    expires_after="M91">
   <owner>rkgibson@google.com</owner>
   <owner>eugenebut@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml
index 20826ac..a554251 100644
--- a/tools/metrics/histograms/histograms_xml/others/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -18157,6 +18157,9 @@
 
 <histogram name="WebP.DecodedImageFormat" enum="WebpDecodedFormat"
     expires_after="2020-12-13">
+  <obsolete>
+    No longer recorded in M89.
+  </obsolete>
   <owner>droger@chromium.org</owner>
   <summary>
     Histogram for the format of decoded WebP images on iOS, as Chrome re-encodes
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 60fdfa9..3955257 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -1,16 +1,16 @@
 {
     "trace_processor_shell": {
         "win": {
-            "hash": "9598a575e79cfb70611008e247f2af28f5473d4a",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/f9a1b53d2809ce2f710e66b06f69449b8242ee8b/trace_processor_shell.exe"
+            "hash": "55e3995717f28e7c5096709cf8bcc916674bd052",
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/4dde23fea5996c50208504f79c85264f27e21aea/trace_processor_shell.exe"
         },
         "mac": {
-            "hash": "c85853e98da47864d7161c57b4de7de265e7d1e2",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/f9a1b53d2809ce2f710e66b06f69449b8242ee8b/trace_processor_shell"
+            "hash": "e1c9721f43a06fd1c7f30ff819236d0124a2eed3",
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/4dde23fea5996c50208504f79c85264f27e21aea/trace_processor_shell"
         },
         "linux": {
-            "hash": "9197f51579704b8d777dd2307a3eb695eef62d50",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/f9a1b53d2809ce2f710e66b06f69449b8242ee8b/trace_processor_shell"
+            "hash": "4daecf1a4d9ee3fb10a7bb4b26fb330cf1b3f928",
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/4dde23fea5996c50208504f79c85264f27e21aea/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/perf/cross_device_test_config.py b/tools/perf/cross_device_test_config.py
new file mode 100644
index 0000000..d1a469e
--- /dev/null
+++ b/tools/perf/cross_device_test_config.py
@@ -0,0 +1,28 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Dictionary for the repeat config.
+# E.g.:
+# {
+#   'builder-1':
+#   {
+#     'benchmark-1':
+#     {
+#       'story-1': 4,
+#     }
+#   'builder-2':
+#     'benchmark-2':
+#     {
+#       'story-1': 10,
+#       'story-2': 10,
+#     }
+# }
+
+TARGET_DEVICES = {
+    'android-pixel2-perf-fyi': {
+        'speedometer2': {
+            'Speedometer2': 3
+        }
+    }
+}
diff --git a/ui/aura/native_window_occlusion_tracker_unittest.cc b/ui/aura/native_window_occlusion_tracker_unittest.cc
index da4af6c..ed94675d 100644
--- a/ui/aura/native_window_occlusion_tracker_unittest.cc
+++ b/ui/aura/native_window_occlusion_tracker_unittest.cc
@@ -52,9 +52,10 @@
 
   TestNativeWindow* native_win() { return native_win_.get(); }
 
-  HWND CreateNativeWindow(DWORD ex_style) {
+  HWND CreateNativeWindow(DWORD style, DWORD ex_style) {
     native_win_ = std::make_unique<TestNativeWindow>();
-    native_win_->set_window_style(WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN);
+    native_win_->set_window_style(WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN |
+                                  style);
     native_win_->set_window_ex_style(ex_style);
     gfx::Rect bounds(0, 0, 100, 100);
     native_win_->Init(nullptr, bounds);
@@ -94,7 +95,7 @@
 };
 
 TEST_F(NativeWindowOcclusionTrackerTest, VisibleOpaqueWindow) {
-  HWND hwnd = CreateNativeWindow(/*ex_style=*/0);
+  HWND hwnd = CreateNativeWindow(/*style=*/0, /*ex_style=*/0);
   gfx::Rect returned_rect;
   // Normal windows should be visible.
   EXPECT_TRUE(CheckWindowVisibleAndFullyOpaque(hwnd, &returned_rect));
@@ -106,7 +107,7 @@
 }
 
 TEST_F(NativeWindowOcclusionTrackerTest, MinimizedWindow) {
-  HWND hwnd = CreateNativeWindow(/*ex_style=*/0);
+  HWND hwnd = CreateNativeWindow(/*style=*/0, /*ex_style=*/0);
   gfx::Rect win_rect;
   ShowWindow(hwnd, SW_MINIMIZE);
   // Minimized windows are not considered visible.
@@ -114,21 +115,21 @@
 }
 
 TEST_F(NativeWindowOcclusionTrackerTest, TransparentWindow) {
-  HWND hwnd = CreateNativeWindow(WS_EX_TRANSPARENT);
+  HWND hwnd = CreateNativeWindow(/*style=*/0, WS_EX_TRANSPARENT);
   gfx::Rect win_rect;
   // Transparent windows are not considered visible and opaque.
   EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &win_rect));
 }
 
 TEST_F(NativeWindowOcclusionTrackerTest, ToolWindow) {
-  HWND hwnd = CreateNativeWindow(WS_EX_TOOLWINDOW);
+  HWND hwnd = CreateNativeWindow(/*style=*/0, WS_EX_TOOLWINDOW);
   gfx::Rect win_rect;
   // Tool windows are not considered visible and opaque.
   EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &win_rect));
 }
 
 TEST_F(NativeWindowOcclusionTrackerTest, LayeredAlphaWindow) {
-  HWND hwnd = CreateNativeWindow(WS_EX_LAYERED);
+  HWND hwnd = CreateNativeWindow(/*style=*/0, WS_EX_LAYERED);
   gfx::Rect win_rect;
   BYTE alpha = 1;
   DWORD flags = LWA_ALPHA;
@@ -139,7 +140,7 @@
 }
 
 TEST_F(NativeWindowOcclusionTrackerTest, UpdatedLayeredAlphaWindow) {
-  HWND hwnd = CreateNativeWindow(WS_EX_LAYERED);
+  HWND hwnd = CreateNativeWindow(/*style=*/0, WS_EX_LAYERED);
   gfx::Rect win_rect;
   base::win::ScopedCreateDC hdc(::CreateCompatibleDC(nullptr));
   BLENDFUNCTION blend = {AC_SRC_OVER, 0x00, 0xFF, AC_SRC_ALPHA};
@@ -152,7 +153,7 @@
 }
 
 TEST_F(NativeWindowOcclusionTrackerTest, LayeredNonAlphaWindow) {
-  HWND hwnd = CreateNativeWindow(WS_EX_LAYERED);
+  HWND hwnd = CreateNativeWindow(/*style=*/0, WS_EX_LAYERED);
   gfx::Rect win_rect;
   BYTE alpha = 1;
   DWORD flags = 0;
@@ -163,7 +164,7 @@
 }
 
 TEST_F(NativeWindowOcclusionTrackerTest, ComplexRegionWindow) {
-  HWND hwnd = CreateNativeWindow(/*ex_style=*/0);
+  HWND hwnd = CreateNativeWindow(/*style=*/0, /*ex_style=*/0);
   gfx::Rect win_rect;
   // Create a region with rounded corners, which should be a complex region.
   base::win::ScopedRegion region(CreateRoundRectRgn(1, 1, 100, 100, 5, 5));
@@ -172,11 +173,18 @@
   EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &win_rect));
 }
 
+TEST_F(NativeWindowOcclusionTrackerTest, PopupWindow) {
+  HWND hwnd = CreateNativeWindow(WS_POPUP, /*ex_style=*/0);
+  gfx::Rect win_rect;
+  // Popup Windows are not considered visible.
+  EXPECT_FALSE(CheckWindowVisibleAndFullyOpaque(hwnd, &win_rect));
+}
+
 TEST_F(NativeWindowOcclusionTrackerTest, CloakedWindow) {
   // Cloaking is only supported in Windows 8 and above.
   if (base::win::GetVersion() < base::win::Version::WIN8)
     return;
-  HWND hwnd = CreateNativeWindow(/*ex_style=*/0);
+  HWND hwnd = CreateNativeWindow(/*style=*/0, /*ex_style=*/0);
   gfx::Rect win_rect;
   BOOL cloak = TRUE;
   DwmSetWindowAttribute(hwnd, DWMWA_CLOAK, &cloak, sizeof(cloak));
diff --git a/ui/aura/native_window_occlusion_tracker_win.cc b/ui/aura/native_window_occlusion_tracker_win.cc
index f96e592..746cb68 100644
--- a/ui/aura/native_window_occlusion_tracker_win.cc
+++ b/ui/aura/native_window_occlusion_tracker_win.cc
@@ -167,7 +167,12 @@
   if (IsIconic(hwnd))
     return false;
 
-  LONG ex_styles = GetWindowLong(hwnd, GWL_EXSTYLE);
+  LONG styles = ::GetWindowLong(hwnd, GWL_STYLE);
+  // Ignore popup windows since they're transient.
+  if (styles & WS_POPUP)
+    return false;
+
+  LONG ex_styles = ::GetWindowLong(hwnd, GWL_EXSTYLE);
   // Filter out "transparent" windows, windows where the mouse clicks fall
   // through them.
   if (ex_styles & WS_EX_TRANSPARENT)
@@ -663,6 +668,10 @@
   if (id_object != OBJID_WINDOW)
     return;
 
+  // We generally ignore events for poup windows, except for when the taskbar
+  // is hidden, in which case we recalculate occlusion.
+  bool calculate_occlusion = !(::GetWindowLong(hwnd, GWL_STYLE) & WS_POPUP);
+
   // Detect if either the alt tab view or the task list thumbnail is being
   // shown. If so, mark all non-hidden windows as occluded, and remember that
   // we're in the showing_thumbnails state. This lasts until we get told that
@@ -691,7 +700,9 @@
     if (hwnd_class_name == "MultitaskingViewFrame" ||
         hwnd_class_name == "TaskListThumbnailWnd") {
       showing_thumbnails_ = false;
-      // Let occlusion calculation fix occlusion state.
+      // Let occlusion calculation fix occlusion state, even though hwnd might
+      // be a popup window.
+      calculate_occlusion = true;
     }
   }
   // Don't continually calculate occlusion while a window is moving (unless it's
@@ -721,6 +732,9 @@
     }
   }
 
+  if (!calculate_occlusion)
+    return;
+
   // ProcessEventHookCallback is called from the task_runner's PeekMessage
   // call, on the task runner's thread, but before the task_tracker thread sets
   // up the thread sequence. In order to prevent DCHECK failures with the
diff --git a/ui/aura/native_window_occlusion_tracker_win.h b/ui/aura/native_window_occlusion_tracker_win.h
index 443089e..4934e8b 100644
--- a/ui/aura/native_window_occlusion_tracker_win.h
+++ b/ui/aura/native_window_occlusion_tracker_win.h
@@ -259,8 +259,8 @@
 
   // Returns true if we are interested in |hwnd| for purposes of occlusion
   // calculation. We are interested in |hwnd| if it is a window that is
-  // visible, opaque, and bounded. If we are interested in |hwnd|, stores the
-  // window rectangle in |window_rect|.
+  // visible, opaque, bounded, and not a popup or floating window. If we are
+  // interested in |hwnd|, stores the window rectangle in |window_rect|.
   static bool IsWindowVisibleAndFullyOpaque(HWND hwnd, gfx::Rect* window_rect);
 
   // Updates root windows occclusion state. If |show_all_windows| is true,
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 5b143cb..24ab739 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -1033,6 +1033,7 @@
         "ime/chromeos/extension_ime_util_unittest.cc",
         "ime/chromeos/ime_keyboard_unittest.cc",
         "ime/chromeos/input_method_chromeos_unittest.cc",
+        "ime/chromeos/input_method_descriptor_unittest.cc",
         "ime/chromeos/input_method_util_unittest.cc",
       ]
       deps += [ "//ui/base/ime/chromeos" ]
diff --git a/ui/base/ime/chromeos/input_method_descriptor.cc b/ui/base/ime/chromeos/input_method_descriptor.cc
index 54b57dbf..8a257096 100644
--- a/ui/base/ime/chromeos/input_method_descriptor.cc
+++ b/ui/base/ime/chromeos/input_method_descriptor.cc
@@ -9,6 +9,7 @@
 #include "base/check.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "url/gurl.h"
 
@@ -36,21 +37,23 @@
 InputMethodDescriptor::InputMethodDescriptor(
     const InputMethodDescriptor& other) = default;
 
-std::string InputMethodDescriptor::GetIndicator() const {
+base::string16 InputMethodDescriptor::GetIndicator() const {
   // Return the empty string for ARC IMEs.
   if (extension_ime_util::IsArcIME(id_))
-    return std::string();
+    return base::string16();
 
   // If indicator is empty, use the first two character in its keyboard layout
   // or language code.
   if (indicator_.empty()) {
     if (extension_ime_util::IsKeyboardLayoutExtension(id_)) {
-      return base::ToUpperASCII(keyboard_layout_.substr(0, 2));
+      return base::UTF8ToUTF16(
+          base::ToUpperASCII(keyboard_layout_.substr(0, 2)));
     }
     DCHECK(language_codes_.size() > 0);
-    return base::ToUpperASCII(language_codes_[0].substr(0, 2));
+    return base::UTF8ToUTF16(
+        base::ToUpperASCII(language_codes_[0].substr(0, 2)));
   }
-  return indicator_;
+  return base::UTF8ToUTF16(indicator_);
 }
 
 InputMethodDescriptor::InputMethodDescriptor() = default;
diff --git a/ui/base/ime/chromeos/input_method_descriptor.h b/ui/base/ime/chromeos/input_method_descriptor.h
index da922ef3..28832828 100644
--- a/ui/base/ime/chromeos/input_method_descriptor.h
+++ b/ui/base/ime/chromeos/input_method_descriptor.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/component_export.h"
+#include "base/strings/string16.h"
 #include "url/gurl.h"
 
 namespace chromeos {
@@ -39,11 +40,9 @@
   const GURL& options_page_url() const { return options_page_url_; }
   const GURL& input_view_url() const { return input_view_url_; }
   const std::string& keyboard_layout() const { return keyboard_layout_; }
-
   bool is_login_keyboard() const { return is_login_keyboard_; }
 
-  // Returns the indicator text of this input method.
-  std::string GetIndicator() const;
+  base::string16 GetIndicator() const;
 
  private:
   // An ID that identifies an input method engine (e.g., "t:latn-post",
diff --git a/ui/base/ime/chromeos/input_method_descriptor_unittest.cc b/ui/base/ime/chromeos/input_method_descriptor_unittest.cc
new file mode 100644
index 0000000..7db28d0
--- /dev/null
+++ b/ui/base/ime/chromeos/input_method_descriptor_unittest.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 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/base/ime/chromeos/input_method_descriptor.h"
+
+#include <stddef.h>
+#include <string>
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ime/chromeos/extension_ime_util.h"
+
+using base::ASCIIToUTF16;
+
+namespace chromeos {
+namespace input_method {
+namespace {
+
+InputMethodDescriptor CreateDesc(const std::string& id,
+                                 const std::string& layout,
+                                 const std::vector<std::string>& language_codes,
+                                 const std::string& indicator,
+                                 bool is_login_keyboard) {
+  return InputMethodDescriptor(
+      extension_ime_util::GetInputMethodIDByEngineID(id), /* name= */ "",
+      indicator, layout, language_codes, /* is_login_keyboard= */ true,
+      /* options_page_url= */ GURL(), /* input_view_url= */ GURL());
+}
+
+TEST(InputMethodDescriptorTest, GetIndicatorTest) {
+  // Test invalid cases. Two-letter language code should be returned.
+  {
+    InputMethodDescriptor desc =
+        CreateDesc("invalid-id", "us", {"xx"}, "", true);
+    // Upper-case string of the unknown language code, "xx", should be returned.
+    EXPECT_EQ(ASCIIToUTF16("XX"), desc.GetIndicator());
+  }
+
+  // Test special cases.
+  {
+    InputMethodDescriptor desc =
+        CreateDesc("xkb:us:dvorak:eng", "us", {"en-US"}, "DV", true);
+    EXPECT_EQ(ASCIIToUTF16("DV"), desc.GetIndicator());
+  }
+  {
+    InputMethodDescriptor desc =
+        CreateDesc("xkb:us:colemak:eng", "us", {"en-US"}, "CO", true);
+    EXPECT_EQ(ASCIIToUTF16("CO"), desc.GetIndicator());
+  }
+  {
+    InputMethodDescriptor desc =
+        CreateDesc("xkb:us:altgr-intl:eng", "us", {"en-US"}, "EXTD", true);
+    EXPECT_EQ(ASCIIToUTF16("EXTD"), desc.GetIndicator());
+  }
+  {
+    InputMethodDescriptor desc =
+        CreateDesc("xkb:us:intl:eng", "us", {"en-US"}, "INTL", true);
+    EXPECT_EQ(ASCIIToUTF16("INTL"), desc.GetIndicator());
+  }
+  {
+    InputMethodDescriptor desc =
+        CreateDesc("xkb:de:neo:ger", "de(neo)", {"de"}, "NEO", true);
+    EXPECT_EQ(ASCIIToUTF16("NEO"), desc.GetIndicator());
+  }
+  {
+    InputMethodDescriptor desc =
+        CreateDesc("xkb:es:cat:cat", "es(cat)", {"ca"}, "CAT", true);
+    EXPECT_EQ(ASCIIToUTF16("CAT"), desc.GetIndicator());
+  }
+  {
+    InputMethodDescriptor desc =
+        CreateDesc("zh-t-i0-pinyin", "us", {"zh-CN"}, "拼", true);
+    EXPECT_EQ(base::UTF8ToUTF16("拼"), desc.GetIndicator());
+  }
+  {
+    InputMethodDescriptor desc =
+        CreateDesc("zh-hant-t-i0-und", "us", {"zh-TW"}, "注", true);
+    EXPECT_EQ(base::UTF8ToUTF16("注"), desc.GetIndicator());
+  }
+}
+
+}  // namespace
+}  // namespace input_method
+}  // namespace chromeos
diff --git a/ui/base/ime/chromeos/input_method_util.cc b/ui/base/ime/chromeos/input_method_util.cc
index e5e6c53b..30cab16 100644
--- a/ui/base/ime/chromeos/input_method_util.cc
+++ b/ui/base/ime/chromeos/input_method_util.cc
@@ -482,13 +482,6 @@
          extension_ime_util::IsKeyboardLayoutExtension(input_method_id);
 }
 
-base::string16 InputMethodUtil::GetInputMethodShortName(
-    const InputMethodDescriptor& input_method) const {
-  // TODO(shuchen): remove this method, as the client can directly use
-  // input_method.GetIndicator().
-  return base::UTF8ToUTF16(input_method.GetIndicator());
-}
-
 base::string16 InputMethodUtil::GetInputMethodMediumName(
     const InputMethodDescriptor& input_method) const {
   // For the "Your input method has changed to..." bubble. In most cases
@@ -500,7 +493,7 @@
       return delegate_->GetLocalizedString(i.resource_id);
     }
   }
-  return GetInputMethodShortName(input_method);
+  return input_method.GetIndicator();
 }
 
 base::string16 InputMethodUtil::GetInputMethodLongNameInternal(
diff --git a/ui/base/ime/chromeos/input_method_util.h b/ui/base/ime/chromeos/input_method_util.h
index 4f5330b..07d0201 100644
--- a/ui/base/ime/chromeos/input_method_util.h
+++ b/ui/base/ime/chromeos/input_method_util.h
@@ -40,8 +40,6 @@
   std::string GetInputMethodDisplayNameFromId(
       const std::string& input_method_id) const;
 
-  base::string16 GetInputMethodShortName(
-      const InputMethodDescriptor& input_method) const;
   base::string16 GetInputMethodMediumName(
       const InputMethodDescriptor& input_method) const;
   base::string16 GetInputMethodLongNameStripped(
diff --git a/ui/base/ime/chromeos/input_method_util_unittest.cc b/ui/base/ime/chromeos/input_method_util_unittest.cc
index 3f780ff4..5de424f 100644
--- a/ui/base/ime/chromeos/input_method_util_unittest.cc
+++ b/ui/base/ime/chromeos/input_method_util_unittest.cc
@@ -98,60 +98,6 @@
   InputMethodDescriptors non_xkb_input_method_descriptors_;
 };
 
-TEST_F(InputMethodUtilTest, GetInputMethodShortNameTest) {
-  // Test invalid cases. Two-letter language code should be returned.
-  {
-    InputMethodDescriptor desc =
-        GetDesc("invalid-id", "", "us", {"xx"}, "", true);
-    // Upper-case string of the unknown language code, "xx", should be returned.
-    EXPECT_EQ(ASCIIToUTF16("XX"), util_.GetInputMethodShortName(desc));
-  }
-
-  // Test special cases.
-  {
-    InputMethodDescriptor desc =
-        GetDesc("xkb:us:dvorak:eng", "", "us", {"en-US"}, "DV", true);
-    EXPECT_EQ(ASCIIToUTF16("DV"), util_.GetInputMethodShortName(desc));
-  }
-  {
-    InputMethodDescriptor desc =
-        GetDesc("xkb:us:colemak:eng", "", "us", {"en-US"}, "CO", true);
-    EXPECT_EQ(ASCIIToUTF16("CO"), util_.GetInputMethodShortName(desc));
-  }
-  {
-    InputMethodDescriptor desc =
-        GetDesc("xkb:us:altgr-intl:eng", "", "us", {"en-US"}, "EXTD", true);
-    EXPECT_EQ(ASCIIToUTF16("EXTD"), util_.GetInputMethodShortName(desc));
-  }
-  {
-    InputMethodDescriptor desc =
-        GetDesc("xkb:us:intl:eng", "", "us", {"en-US"}, "INTL", true);
-    EXPECT_EQ(ASCIIToUTF16("INTL"), util_.GetInputMethodShortName(desc));
-  }
-  {
-    InputMethodDescriptor desc =
-        GetDesc("xkb:de:neo:ger", "", "de(neo)", {"de"}, "NEO", true);
-    EXPECT_EQ(ASCIIToUTF16("NEO"), util_.GetInputMethodShortName(desc));
-  }
-  {
-    InputMethodDescriptor desc =
-        GetDesc("xkb:es:cat:cat", "", "es(cat)", {"ca"}, "CAT", true);
-    EXPECT_EQ(ASCIIToUTF16("CAT"), util_.GetInputMethodShortName(desc));
-  }
-  {
-    InputMethodDescriptor desc =
-        GetDesc(pinyin_ime_id, "", "us", {"zh-CN"}, "\xe6\x8b\xbc", true);
-    EXPECT_EQ(base::UTF8ToUTF16("\xe6\x8b\xbc"),
-              util_.GetInputMethodShortName(desc));
-  }
-  {
-    InputMethodDescriptor desc =
-        GetDesc(zhuyin_ime_id, "", "us", {"zh-TW"}, "\xE6\xB3\xA8", true);
-    EXPECT_EQ(base::UTF8ToUTF16("\xE6\xB3\xA8"),
-              util_.GetInputMethodShortName(desc));
-  }
-}
-
 TEST_F(InputMethodUtilTest, GetInputMethodMediumNameTest) {
   {
     // input methods with medium name equal to short name
@@ -163,8 +109,7 @@
     for (const char* id : input_method_ids) {
       InputMethodDescriptor desc = GetDesc(id, "", "", {""}, "", true);
       base::string16 medium_name = util_.GetInputMethodMediumName(desc);
-      base::string16 short_name = util_.GetInputMethodShortName(desc);
-      EXPECT_EQ(medium_name, short_name);
+      EXPECT_EQ(medium_name, desc.GetIndicator());
     }
   }
   {
@@ -176,8 +121,7 @@
     for (const char* id : input_method_ids) {
       InputMethodDescriptor desc = GetDesc(id, "", "", {""}, "", true);
       base::string16 medium_name = util_.GetInputMethodMediumName(desc);
-      base::string16 short_name = util_.GetInputMethodShortName(desc);
-      EXPECT_NE(medium_name, short_name);
+      EXPECT_NE(medium_name, desc.GetIndicator());
     }
   }
 }
diff --git a/ui/file_manager/BUILD.gn b/ui/file_manager/BUILD.gn
index 597f0ec..d5d612d0 100644
--- a/ui/file_manager/BUILD.gn
+++ b/ui/file_manager/BUILD.gn
@@ -58,7 +58,6 @@
   testonly = true
   deps = [
     "base/js:js_test_gen_html",
-    "file_manager/background/js:js_test_gen_html",
     "file_manager/background/js:js_test_gen_html_modules",
     "file_manager/common/js:js_test_gen_html_modules",
     "file_manager/foreground/elements:js_test_gen_html_modules",
@@ -66,6 +65,7 @@
     "file_manager/foreground/js:js_test_gen_html_modules",
     "file_manager/foreground/js/metadata:js_test_gen_html_modules",
     "file_manager/foreground/js/ui:js_test_gen_html",
+    "file_manager/foreground/js/ui:js_test_gen_html_modules",
     "gallery/js:js_test_gen_html",
     "gallery/js/image_editor:js_test_gen_html",
     "gallery/js/image_editor:js_test_gen_html_modules",
diff --git a/ui/file_manager/audio_player/js/BUILD.gn b/ui/file_manager/audio_player/js/BUILD.gn
index cfbcae88..12f47fe 100644
--- a/ui/file_manager/audio_player/js/BUILD.gn
+++ b/ui/file_manager/audio_player/js/BUILD.gn
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//chrome/browser/resources/optimize_webui.gni")
+import("//chrome/browser/resources/tools/optimize_webui.gni")
 import("//third_party/closure_compiler/compile_js.gni")
 import("//ui/webui/resources/tools/js_modulizer.gni")
 
diff --git a/ui/file_manager/externs/BUILD.gn b/ui/file_manager/externs/BUILD.gn
index 76f78b77..96956fb 100644
--- a/ui/file_manager/externs/BUILD.gn
+++ b/ui/file_manager/externs/BUILD.gn
@@ -26,6 +26,15 @@
   extra_deps = [ ":modulize" ]
 }
 
+js_library("entries_changed_event.m") {
+  sources =
+      [ "$root_gen_dir/ui/file_manager/externs/entries_changed_event.m.js" ]
+
+  deps = [ "//ui/file_manager/file_manager/common/js:util.m" ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("entry_location.m") {
   sources = [ "$root_gen_dir/ui/file_manager/externs/entry_location.m.js" ]
 
@@ -122,6 +131,7 @@
 js_modulizer("modulize") {
   input_files = [
     "background_window.js",
+    "entries_changed_event.js",
     "entry_location.js",
     "exif_entry.js",
     "files_app_entry_interfaces.js",
diff --git a/ui/file_manager/externs/entries_changed_event.js b/ui/file_manager/externs/entries_changed_event.js
index 88cfe07..e2274a4 100644
--- a/ui/file_manager/externs/entries_changed_event.js
+++ b/ui/file_manager/externs/entries_changed_event.js
@@ -2,8 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-class EntriesChangedEvent extends Event {
-  constructor() {
+/**
+ * @fileoverview
+ * @suppress {externsValidation} this file is used as externs and also
+ * as JS module, Closure fails to compile as JS module.
+ */
+
+// clang-format off
+// #import {util} from '../file_manager/common/js/util.m.js';
+// clang-format on
+
+/* #export */ class EntriesChangedEvent extends Event {
+  /** @param {string} eventName */
+  constructor(eventName) {
+    super(eventName);
+
     /** @type {util.EntryChangedKind} */
     this.kind;
 
diff --git a/ui/file_manager/file_manager/background/js/BUILD.gn b/ui/file_manager/file_manager/background/js/BUILD.gn
index 4dfc030..ad64fa34 100644
--- a/ui/file_manager/file_manager/background/js/BUILD.gn
+++ b/ui/file_manager/file_manager/background/js/BUILD.gn
@@ -27,7 +27,6 @@
     ":closure_compile_jsmodules",
     ":closure_compile_module",
     ":js_test_gen_html_modules_type_check_auto",
-    ":js_test_gen_html_type_check_auto",
     ":test_support_modules_type_check",
     ":test_support_type_check",
   ]
@@ -77,6 +76,7 @@
     ":app_windows.m",
     ":background_base.m",
     ":crostini.m",
+    ":device_handler.m",
     ":drive_sync_handler.m",
     ":duplicate_finder.m",
     ":entry_location_impl.m",
@@ -84,6 +84,8 @@
     ":file_operation_manager.m",
     ":file_operation_util.m",
     ":import_history.m",
+    ":launcher.m",
+    ":launcher_search.m",
     ":media_import_handler.m",
     ":media_scanner.m",
     ":metadata_proxy.m",
@@ -91,6 +93,7 @@
     ":mock_file_operation_manager.m",
     ":mock_progress_center.m",
     ":mount_metrics.m",
+    ":progress_center.m",
     ":task_queue.m",
     ":test_util_base.m",
     ":trash.m",
@@ -316,14 +319,38 @@
   ]
 }
 
-js_unittest("device_handler_unittest") {
+js_library("device_handler.m") {
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/device_handler.m.js" ]
   deps = [
-    ":device_handler",
-    ":mock_progress_center",
-    ":mock_volume_manager",
-    "//ui/file_manager/base/js:mock_chrome",
-    "//ui/file_manager/base/js:test_error_reporting",
-    "//ui/file_manager/file_manager/common/js:test_importer_common",
+    ":volume_manager_factory.m",
+    "//ui/file_manager/externs:volume_info.m",
+    "//ui/file_manager/externs:volume_manager.m",
+    "//ui/file_manager/externs/background:progress_center.m",
+    "//ui/file_manager/file_manager/common/js:async_util.m",
+    "//ui/file_manager/file_manager/common/js:importer_common.m",
+    "//ui/file_manager/file_manager/common/js:metrics.m",
+    "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+    "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/webui/resources/js/cr:event_target.m",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
+js_unittest("device_handler_unittest.m") {
+  deps = [
+    ":device_handler.m",
+    ":mock_progress_center.m",
+    ":mock_volume_manager.m",
+    "//chrome/test/data/webui:chai_assert",
+    "//ui/file_manager/base/js:mock_chrome.m",
+    "//ui/file_manager/base/js:test_error_reporting.m",
+    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/externs:volume_info.m",
+    "//ui/file_manager/file_manager/common/js:importer_common.m",
+    "//ui/file_manager/file_manager/common/js:metrics.m",
+    "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/webui/resources/js:load_time_data.m",
   ]
 }
 
@@ -637,6 +664,18 @@
   ]
 }
 
+js_library("launcher.m") {
+  sources = [
+    "$root_gen_dir/ui/file_manager/file_manager/background/js/launcher.m.js",
+  ]
+  deps = [
+    ":app_window_wrapper.m",
+    "//ui/file_manager/file_manager/common/js:util.m",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("launcher_search") {
   deps = [
     ":launcher",
@@ -646,6 +685,20 @@
   ]
 }
 
+js_library("launcher_search.m") {
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/launcher_search.m.js" ]
+  deps = [
+    ":launcher.m",
+    ":volume_manager_factory.m",
+    "//ui/file_manager/file_manager/common/js:file_type.m",
+    "//ui/file_manager/file_manager/common/js:util.m",
+  ]
+
+  externs_list = [ "//ui/file_manager/externs/launcher_search_provider.js" ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("media_import_handler") {
   deps = [
     ":drive_sync_handler",
@@ -834,6 +887,19 @@
   ]
 }
 
+js_library("progress_center.m") {
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/progress_center.m.js" ]
+  deps = [
+    "//ui/file_manager/externs:progress_center_panel.m",
+    "//ui/file_manager/externs/background:progress_center.m",
+    "//ui/file_manager/file_manager/common/js:async_util.m",
+    "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+    "//ui/file_manager/file_manager/common/js:util.m",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("runtime_loaded_test_util") {
   # TODO(tapted): Move this target to //ui/file_manager/base. It is used in the
   # background page of all |related_apps|, but loaded at runtime by
@@ -889,6 +955,7 @@
     "//ui/file_manager/file_manager/common/js:util.m",
     "//ui/webui/resources/js:assert.m",
   ]
+  visibility += [ "//ui/file_manager/file_manager/foreground/js:navigation_list_model_unittest.m" ]
 
   extra_deps = [ ":modulize" ]
 }
@@ -1070,12 +1137,18 @@
   extra_deps = [ ":modulize" ]
 }
 
-js_unittest("volume_manager_unittest") {
+js_unittest("volume_manager_unittest.m") {
   deps = [
-    ":volume_manager_factory",
-    "//ui/file_manager/base/js:mock_chrome",
-    "//ui/file_manager/base/js:test_error_reporting",
-    "//ui/file_manager/file_manager/common/js:mock_entry",
+    ":volume_info_impl.m",
+    ":volume_manager_factory.m",
+    ":volume_manager_impl.m",
+    ":volume_manager_util.m",
+    "//chrome/test/data/webui:chai_assert",
+    "//ui/file_manager/base/js:mock_chrome.m",
+    "//ui/file_manager/base/js:test_error_reporting.m",
+    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/webui/resources/js:load_time_data.m",
   ]
 }
 
@@ -1103,6 +1176,7 @@
 js_test_gen_html("js_test_gen_html_modules") {
   deps = [
     ":crostini_unittest.m",
+    ":device_handler_unittest.m",
     ":drive_sync_handler_unittest.m",
     ":duplicate_finder_unittest.m",
     ":file_operation_handler_unittest.m",
@@ -1114,6 +1188,7 @@
     ":mount_metrics_unittest.m",
     ":task_queue_unittest.m",
     ":trash_unittest.m",
+    ":volume_manager_unittest.m",
   ]
   js_module = true
 
@@ -1126,13 +1201,6 @@
       ]
 }
 
-js_test_gen_html("js_test_gen_html") {
-  deps = [
-    ":device_handler_unittest",
-    ":volume_manager_unittest",
-  ]
-}
-
 js_modulizer("modulize") {
   input_files = [
     "metadata_proxy.js",
@@ -1165,6 +1233,10 @@
     "file_operation_handler.js",
     "file_operation_manager.js",
     "trash.js",
+    "progress_center.js",
+    "device_handler.js",
+    "launcher.js",
+    "launcher_search.js",
   ]
 
   namespace_rewrites = cr_namespace_rewrites
diff --git a/ui/file_manager/file_manager/background/js/device_handler.js b/ui/file_manager/file_manager/background/js/device_handler.js
index 778e55f..6d389a1d 100644
--- a/ui/file_manager/file_manager/background/js/device_handler.js
+++ b/ui/file_manager/file_manager/background/js/device_handler.js
@@ -2,8 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// clang-format off
+// #import {metrics} from '../../common/js/metrics.m.js';
+// #import {AsyncUtil} from '../../common/js/async_util.m.js';
+// #import {importer} from '../../common/js/importer_common.m.js';
+// #import {volumeManagerFactory} from './volume_manager_factory.m.js';
+// #import {ProgressCenterItem, ProgressItemType, ProgressItemState} from '../../common/js/progress_center_common.m.js';
+// #import {util, strf, str} from '../../common/js/util.m.js';
+// #import {VolumeInfo} from '../../../externs/volume_info.m.js';
+// #import {VolumeManager} from '../../../externs/volume_manager.m.js';
+// #import {ProgressCenter} from '../../../externs/background/progress_center.m.js';
+// #import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
+// clang-format on
+
 /** Handler of device event. */
-class DeviceHandler extends cr.EventTarget {
+/* #export */ class DeviceHandler extends cr.EventTarget {
   /** @param {!ProgressCenter} progressCenter */
   constructor(progressCenter) {
     super();
diff --git a/ui/file_manager/file_manager/background/js/device_handler_unittest.js b/ui/file_manager/file_manager/background/js/device_handler_unittest.m.js
similarity index 90%
rename from ui/file_manager/file_manager/background/js/device_handler_unittest.js
rename to ui/file_manager/file_manager/background/js/device_handler_unittest.m.js
index 5a3dd57..0596b731 100644
--- a/ui/file_manager/file_manager/background/js/device_handler_unittest.js
+++ b/ui/file_manager/file_manager/background/js/device_handler_unittest.m.js
@@ -1,7 +1,21 @@
 // Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-'use strict';
+
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
+
+import {installMockChrome, MockChromeStorageAPI} from '../../../base/js/mock_chrome.m.js';
+import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
+import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+import {VolumeInfo} from '../../../externs/volume_info.m.js';
+import {importer} from '../../common/js/importer_common.m.js';
+import {metrics} from '../../common/js/metrics.m.js';
+import {MockFileSystem} from '../../common/js/mock_entry.m.js';
+
+import {DeviceHandler} from './device_handler.m.js';
+import {MockProgressCenter} from './mock_progress_center.m.js';
+import {MockVolumeManager} from './mock_volume_manager.m.js';
 
 /** @type {!MockVolumeManager} */
 let volumeManager;
@@ -17,16 +31,16 @@
 
 /**
  * Mock metrics.
- * @type {!Object}
+ * @param {string} name
+ * @param {*} value
+ * @param {Array<*>|number=} opt_validValues
  */
-window.metrics = {
-  recordEnum: function() {},
-};
+metrics.recordEnum = function(name, value, opt_validValues) {};
 
 // Set up the test components.
-function setUp() {
+export function setUp() {
   // Set up string assets.
-  window.loadTimeData.data = {
+  loadTimeData.data = {
     DEVICE_UNSUPPORTED_MESSAGE: 'DEVICE_UNSUPPORTED: $1',
     DEVICE_UNKNOWN_MESSAGE: 'DEVICE_UNKNOWN: $1',
     MULTIPART_DEVICE_UNSUPPORTED_MESSAGE: 'MULTIPART_DEVICE_UNSUPPORTED: $1',
@@ -34,13 +48,13 @@
     FORMAT_SUCCESS_MESSAGE: 'FORMAT_SUCCESS_MESSAGE: $1',
     FORMAT_FAILURE_MESSAGE: 'FORMAT_FAILURE_MESSAGE: $1',
   };
-  window.loadTimeData.getString = id => {
-    return window.loadTimeData.data_[id] || id;
+  loadTimeData.getString = id => {
+    return loadTimeData.data_[id] || id;
   };
-  window.loadTimeData.getBoolean = id => {
+  loadTimeData.getBoolean = id => {
     return id === 'ARC_USB_STORAGE_UI_ENABLED' ? true : false;
   };
-  window.loadTimeData.valueExists = id => {
+  loadTimeData.valueExists = id => {
     return id === 'ARC_USB_STORAGE_UI_ENABLED';
   };
 
@@ -57,7 +71,7 @@
   mockChrome.extension.inIncognitoContext = true;
 }
 
-function testGoodDevice(callback) {
+export function testGoodDevice(callback) {
   // Turn off ARC so that the notification won't show the "OPEN SETTINGS"
   // button.
   mockChrome.fileManagerPrivate.arcEnabledPref = false;
@@ -85,7 +99,7 @@
       callback);
 }
 
-function testGoodDeviceWithAllowPlayStoreMessage(callback) {
+export function testGoodDeviceWithAllowPlayStoreMessage(callback) {
   // Turn on ARC so that the notification shows the "OPEN SETTINGS" button.
   mockChrome.fileManagerPrivate.arcEnabledPref = true;
   // Turn off the ARC pref so that the notification shows the "Allow Play Store
@@ -117,7 +131,7 @@
       callback);
 }
 
-function testGoodDeviceWithPlayStoreAppsHaveAccessMessage(callback) {
+export function testGoodDeviceWithPlayStoreAppsHaveAccessMessage(callback) {
   // Turn on ARC so that the notification shows the "OPEN SETTINGS" button.
   mockChrome.fileManagerPrivate.arcEnabledPref = true;
   // Turn on the ARC pref so that the notification shows the "Play Store apps
@@ -152,7 +166,7 @@
       callback);
 }
 
-function testRemovableMediaDeviceWithImportEnabled(callback) {
+export function testRemovableMediaDeviceWithImportEnabled(callback) {
   const storage = new MockChromeStorageAPI();
 
   setupFileSystem(VolumeManagerCommon.VolumeType.REMOVABLE, 'blabbity', [
@@ -182,7 +196,7 @@
       callback);
 }
 
-function testMtpMediaDeviceWithImportEnabled(callback) {
+export function testMtpMediaDeviceWithImportEnabled(callback) {
   const storage = new MockChromeStorageAPI();
 
   setupFileSystem(VolumeManagerCommon.VolumeType.MTP, 'blabbity', [
@@ -212,7 +226,7 @@
       callback);
 }
 
-function testGoodDeviceNotNavigated() {
+export function testGoodDeviceNotNavigated() {
   mockChrome.fileManagerPrivate.onMountCompleted.dispatch({
     eventType: 'mount',
     status: 'success',
@@ -229,7 +243,7 @@
   assertFalse(mockChrome.notifications.resolver.settled);
 }
 
-function testGoodDeviceWithBadParent(callback) {
+export function testGoodDeviceWithBadParent(callback) {
   mockChrome.fileManagerPrivate.onMountCompleted.dispatch({
     eventType: 'mount',
     status: 'error_internal',
@@ -252,7 +266,7 @@
       callback);
 }
 
-function testGoodDeviceWithBadParent_DuplicateMount(callback) {
+export function testGoodDeviceWithBadParent_DuplicateMount(callback) {
   mockChrome.fileManagerPrivate.onMountCompleted.dispatch({
     eventType: 'mount',
     status: 'success',
@@ -289,7 +303,7 @@
       callback);
 }
 
-function testUnsupportedDevice(callback) {
+export function testUnsupportedDevice(callback) {
   mockChrome.fileManagerPrivate.onMountCompleted.dispatch({
     eventType: 'mount',
     status: 'error_unsupported_filesystem',
@@ -312,7 +326,7 @@
       callback);
 }
 
-function testUnknownDevice(callback) {
+export function testUnknownDevice(callback) {
   // Emulate adding a device which has unknown filesystem.
   mockChrome.fileManagerPrivate.onMountCompleted.dispatch({
     eventType: 'mount',
@@ -337,7 +351,7 @@
       callback);
 }
 
-function testUnknownReadonlyDevice(callback) {
+export function testUnknownReadonlyDevice(callback) {
   // Emulate adding a device which has unknown filesystem but is read-only.
   mockChrome.fileManagerPrivate.onMountCompleted.dispatch({
     eventType: 'mount',
@@ -362,7 +376,7 @@
       callback);
 }
 
-function testUnsupportedWithUnknownParentReplacesNotification() {
+export function testUnsupportedWithUnknownParentReplacesNotification() {
   mockChrome.fileManagerPrivate.onMountCompleted.dispatch({
     eventType: 'mount',
     status: 'error_internal',
@@ -397,7 +411,7 @@
       mockChrome.notifications.items['deviceFail:/device/path'].message);
 }
 
-function testMountPartialSuccess(callback) {
+export function testMountPartialSuccess(callback) {
   mockChrome.fileManagerPrivate.onMountCompleted.dispatch({
     eventType: 'mount',
     status: 'success',
@@ -441,7 +455,7 @@
       callback);
 }
 
-function testUnknown(callback) {
+export function testUnknown(callback) {
   mockChrome.fileManagerPrivate.onMountCompleted.dispatch({
     eventType: 'mount',
     status: 'error_unknown',
@@ -464,7 +478,7 @@
       callback);
 }
 
-function testNonASCIILabel(callback) {
+export function testNonASCIILabel(callback) {
   mockChrome.fileManagerPrivate.onMountCompleted.dispatch({
     eventType: 'mount',
     status: 'error_internal',
@@ -488,7 +502,7 @@
       callback);
 }
 
-function testMulitpleFail() {
+export function testMulitpleFail() {
   // The first parent error.
   mockChrome.fileManagerPrivate.onMountCompleted.dispatch({
     eventType: 'mount',
@@ -559,7 +573,7 @@
       mockChrome.notifications.items['deviceFail:/device/path'].message);
 }
 
-function testDisabledDevice() {
+export function testDisabledDevice() {
   mockChrome.fileManagerPrivate.onDeviceChanged.dispatch(
       {type: 'disabled', devicePath: '/device/path'});
   assertEquals(1, Object.keys(mockChrome.notifications.items).length);
@@ -572,7 +586,7 @@
   assertEquals(0, Object.keys(mockChrome.notifications.items).length);
 }
 
-function testFormatSucceeded() {
+export function testFormatSucceeded() {
   mockChrome.fileManagerPrivate.onDeviceChanged.dispatch(
       {type: 'format_start', devicePath: '/device/path', deviceLabel: 'label'});
   assertEquals(1, progressCenter.getItemCount());
@@ -591,7 +605,7 @@
       progressCenter.getItemById('format:/device/path').message);
 }
 
-function testFormatFailed() {
+export function testFormatFailed() {
   mockChrome.fileManagerPrivate.onDeviceChanged.dispatch(
       {type: 'format_start', devicePath: '/device/path', deviceLabel: 'label'});
   assertEquals(1, progressCenter.getItemCount());
@@ -607,7 +621,7 @@
       progressCenter.getItemById('format:/device/path').message);
 }
 
-function testPartitionSucceeded() {
+export function testPartitionSucceeded() {
   mockChrome.fileManagerPrivate.onDeviceChanged.dispatch({
     type: 'partition_start',
     devicePath: '/device/path',
@@ -623,7 +637,7 @@
   assertEquals(0, progressCenter.getItemCount());
 }
 
-function testPartitionFailed() {
+export function testPartitionFailed() {
   mockChrome.fileManagerPrivate.onDeviceChanged.dispatch({
     type: 'partition_start',
     devicePath: '/device/path',
@@ -642,7 +656,7 @@
       progressCenter.getItemById('partition:/device/path').message);
 }
 
-function testRenameSucceeded() {
+export function testRenameSucceeded() {
   mockChrome.fileManagerPrivate.onDeviceChanged.dispatch(
       {type: 'rename_start', devicePath: '/device/path'});
   assertEquals(0, Object.keys(mockChrome.notifications.items).length);
@@ -652,7 +666,7 @@
   assertEquals(0, Object.keys(mockChrome.notifications.items).length);
 }
 
-function testRenameFailed() {
+export function testRenameFailed() {
   mockChrome.fileManagerPrivate.onDeviceChanged.dispatch(
       {type: 'rename_start', devicePath: '/device/path'});
   assertEquals(0, Object.keys(mockChrome.notifications.items).length);
@@ -665,7 +679,7 @@
       mockChrome.notifications.items['renameFail:/device/path'].message);
 }
 
-function testDeviceHardUnplugged() {
+export function testDeviceHardUnplugged() {
   mockChrome.fileManagerPrivate.onDeviceChanged.dispatch(
       {type: 'hard_unplugged', devicePath: '/device/path'});
   assertEquals(1, Object.keys(mockChrome.notifications.items).length);
@@ -674,7 +688,7 @@
       mockChrome.notifications.items['hardUnplugged:/device/path'].message);
 }
 
-function testNotificationClicked(callback) {
+export function testNotificationClicked(callback) {
   const devicePath = '/device/path';
   const notificationId = 'deviceNavigation:' + devicePath;
 
@@ -697,7 +711,7 @@
       callback);
 }
 
-function testMiscMessagesInIncognito() {
+export function testMiscMessagesInIncognito() {
   setUpInIncognitoContext();
   mockChrome.fileManagerPrivate.onDeviceChanged.dispatch(
       {type: 'format_start', devicePath: '/device/path', deviceLabel: 'label'});
@@ -705,7 +719,7 @@
   assertEquals(0, progressCenter.getItemCount());
 }
 
-function testMountCompleteInIncognito() {
+export function testMountCompleteInIncognito() {
   setUpInIncognitoContext();
   mockChrome.fileManagerPrivate.onMountCompleted.dispatch({
     eventType: 'mount',
diff --git a/ui/file_manager/file_manager/background/js/launcher.js b/ui/file_manager/file_manager/background/js/launcher.js
index 3acd1f0..301192cb 100644
--- a/ui/file_manager/file_manager/background/js/launcher.js
+++ b/ui/file_manager/file_manager/background/js/launcher.js
@@ -3,6 +3,14 @@
 // found in the LICENSE file.
 
 /**
+ * @fileoverview
+ * @suppress {uselessCode} Temporary suppress because of the line exporting.
+ */
+
+// #import {AppWindowWrapper} from './app_window_wrapper.m.js';
+// #import {util} from '../../common/js/util.m.js';
+
+/**
  * @type {!Object}
  */
 // eslint-disable-next-line no-var
@@ -12,7 +20,7 @@
  * Type of a Files app's instance launch.
  * @enum {number}
  */
-const LaunchType = {
+/* #export */ const LaunchType = {
   ALWAYS_CREATE: 0,
   FOCUS_ANY_OR_CREATE: 1,
   FOCUS_SAME_OR_CREATE: 2
@@ -174,3 +182,6 @@
   appWindow.rawAppWindow.focus();
   return appId;
 };
+
+// eslint-disable-next-line semi,no-extra-semi
+/* #export */ {launcher};
diff --git a/ui/file_manager/file_manager/background/js/launcher_search.js b/ui/file_manager/file_manager/background/js/launcher_search.js
index ed06659..a87059c 100644
--- a/ui/file_manager/file_manager/background/js/launcher_search.js
+++ b/ui/file_manager/file_manager/background/js/launcher_search.js
@@ -2,10 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// #import {FileType} from '../../common/js/file_type.m.js';
+// #import {launcher, LaunchType} from './launcher.m.js';
+// #import {util} from '../../common/js/util.m.js';
+// #import {volumeManagerFactory} from './volume_manager_factory.m.js';
+
 /**
  * Provides drive search results to chrome launcher.
  */
-class LauncherSearch {
+/* #export */ class LauncherSearch {
   constructor() {
     // Launcher search provider is restricted to dev channel at now.
     if (!chrome.launcherSearchProvider) {
diff --git a/ui/file_manager/file_manager/background/js/progress_center.js b/ui/file_manager/file_manager/background/js/progress_center.js
index 555441f2..450999e 100644
--- a/ui/file_manager/file_manager/background/js/progress_center.js
+++ b/ui/file_manager/file_manager/background/js/progress_center.js
@@ -2,12 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// clang-format off
+// #import {ProgressCenterPanelInterface} from '../../../externs/progress_center_panel.m.js';
+// #import {ProgressCenter} from '../../../externs/background/progress_center.m.js';
+// #import {str} from '../../common/js/util.m.js';
+// #import {AsyncUtil} from '../../common/js/async_util.m.js';
+// #import {ProgressItemState, ProgressCenterItem} from '../../common/js/progress_center_common.m.js';
+// clang-format on
+
 /**
  * Implementation of {ProgressCenter} at the background page.
  * @implements {ProgressCenter}
  * @final
  */
-class ProgressCenterImpl {
+/* #export */ class ProgressCenterImpl {
   constructor() {
     /**
      * Current items managed by the progress center.
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_unittest.js b/ui/file_manager/file_manager/background/js/volume_manager_unittest.m.js
similarity index 93%
rename from ui/file_manager/file_manager/background/js/volume_manager_unittest.js
rename to ui/file_manager/file_manager/background/js/volume_manager_unittest.m.js
index 71d25b5..36b4dd7 100644
--- a/ui/file_manager/file_manager/background/js/volume_manager_unittest.js
+++ b/ui/file_manager/file_manager/background/js/volume_manager_unittest.m.js
@@ -2,12 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
+
+import {installMockChrome, MockCommandLinePrivate} from '../../../base/js/mock_chrome.m.js';
+import {assertRejected, reportPromise} from '../../../base/js/test_error_reporting.m.js';
+import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+import {MockDirectoryEntry, MockFileEntry, MockFileSystem} from '../../common/js/mock_entry.m.js';
+
+import {VolumeInfoImpl} from './volume_info_impl.m.js';
+import {volumeManagerFactory} from './volume_manager_factory.m.js';
+import {VolumeManagerImpl} from './volume_manager_impl.m.js';
+import {volumeManagerUtil} from './volume_manager_util.m.js';
+
 let mockChrome;
 let createVolumeInfoOriginal;
 
-function setUp() {
-  window.loadTimeData.getString = id => id;
-  window.loadTimeData.data = {};
+export function setUp() {
+  loadTimeData.getString = id => id;
+  loadTimeData.data = {};
 
   // Set up mock of chrome.fileManagerPrivate APIs.
   mockChrome = {
@@ -133,7 +146,7 @@
   createVolumeInfoOriginal = volumeManagerUtil.createVolumeInfo;
 }
 
-function tearDown() {
+export function tearDown() {
   volumeManagerFactory.revokeInstanceForTesting();
   // To avoid a closure warning assigning to |chrome|, tearDown() does not
   // balance the call to installMockChrome() here.
@@ -156,7 +169,7 @@
   };
 }
 
-function testGetVolumeInfo(callback) {
+export function testGetVolumeInfo(callback) {
   reportPromise(
       volumeManagerFactory.getInstance().then(volumeManager => {
         const entry = MockFileEntry.create(
@@ -170,7 +183,7 @@
       callback);
 }
 
-function testGetDriveConnectionState(callback) {
+export function testGetDriveConnectionState(callback) {
   reportPromise(
       volumeManagerFactory.getInstance().then(volumeManager => {
         // Default connection state is online
@@ -195,7 +208,7 @@
       callback);
 }
 
-function testMountArchiveAndUnmount(callback) {
+export function testMountArchiveAndUnmount(callback) {
   const test = async () => {
     // Set states of mock fileManagerPrivate APIs.
     const mountSourcePath = '/usr/local/home/test/Downloads/foobar.zip';
@@ -246,7 +259,7 @@
   reportPromise(test(), callback);
 }
 
-function testGetCurrentProfileVolumeInfo(callback) {
+export function testGetCurrentProfileVolumeInfo(callback) {
   reportPromise(
       volumeManagerFactory.getInstance().then(volumeManager => {
         const volumeInfo = volumeManager.getCurrentProfileVolumeInfo(
@@ -260,7 +273,7 @@
       callback);
 }
 
-function testGetLocationInfo(callback) {
+export function testGetLocationInfo(callback) {
   reportPromise(
       volumeManagerFactory.getInstance().then(volumeManager => {
         const downloadEntry = MockFileEntry.create(
@@ -398,7 +411,7 @@
       callback);
 }
 
-function testWhenReady(callback) {
+export function testWhenReady(callback) {
   volumeManagerFactory.getInstance().then((volumeManager) => {
     const promiseBeforeAdd = volumeManager.whenVolumeInfoReady('volumeId');
     const volumeInfo = new VolumeInfoImpl(
@@ -432,7 +445,7 @@
   });
 }
 
-function testDriveMountedDuringInitialization(callback) {
+export function testDriveMountedDuringInitialization(callback) {
   const test = async () => {
     const sendVolumeMetadataListPromise = new Promise(resolve => {
       chrome.fileManagerPrivate.getVolumeMetadataList = resolve;
@@ -471,7 +484,7 @@
   reportPromise(test(), callback);
 }
 
-function testErrorPropagatedDuringInitialization(done) {
+export function testErrorPropagatedDuringInitialization(done) {
   chrome.fileManagerPrivate.getVolumeMetadataList = () => {
     throw new Error('Dummy error for test purpose');
   };
@@ -483,7 +496,7 @@
  * Tests that an error initializing one volume doesn't stop other volumes to be
  * initialized. crbug.com/1041340
  */
-async function testErrorInitializingVolume(done) {
+export async function testErrorInitializingVolume(done) {
   // Confirm that a Drive volume is on faked getVolumeMetadataList().
   assertTrue(
       chrome.fileManagerPrivate.volumeMetadataList_.some(volumeMetadata => {
@@ -522,7 +535,7 @@
  * Tests VolumeInfoImpl doesn't raise exception if null is passed for
  * filesystem. crbug.com/1041340
  */
-async function testDriveWithNullFilesystem(done) {
+export async function testDriveWithNullFilesystem(done) {
   // Get Drive volume metadata from faked getVolumeMetadataList().
   const driveVolumeMetadata =
       chrome.fileManagerPrivate.volumeMetadataList_.find(volumeMetadata => {
diff --git a/ui/file_manager/file_manager/foreground/js/BUILD.gn b/ui/file_manager/file_manager/foreground/js/BUILD.gn
index 5233d72..2b086d9 100644
--- a/ui/file_manager/file_manager/foreground/js/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/BUILD.gn
@@ -29,6 +29,17 @@
   uses_js_modules = true
   deps = [
     ":android_app_list_model.m",
+    ":constants.m",
+    ":crossover_search_utils.m",
+    ":directory_contents.m",
+    ":directory_model.m",
+    ":fake_android_app_list_model.m",
+    ":file_list_model.m",
+    ":file_watcher.m",
+    ":folder_shortcuts_data_model.m",
+    ":mock_directory_model.m",
+    ":mock_folder_shortcut_data_model.m",
+    ":navigation_list_model.m",
     ":thumbnail_loader.m",
   ]
 }
@@ -194,6 +205,16 @@
   deps = [ ":android_app_list_model" ]
 }
 
+js_library("fake_android_app_list_model.m") {
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/fake_android_app_list_model.m.js" ]
+  deps = [
+    ":android_app_list_model.m",
+    "//ui/webui/resources/js/cr:event_target.m",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("mock_directory_model") {
   testonly = true
   deps = [
@@ -204,6 +225,18 @@
   ]
 }
 
+js_library("mock_directory_model.m") {
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/mock_directory_model.m.js" ]
+  deps = [
+    ":directory_contents.m",
+    ":directory_model.m",
+    "//ui/file_manager/externs:files_app_entry_interfaces.m",
+    "//ui/webui/resources/js/cr:event_target.m",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("mock_folder_shortcut_data_model") {
   testonly = true
   deps = [
@@ -213,6 +246,17 @@
   ]
 }
 
+js_library("mock_folder_shortcut_data_model.m") {
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/mock_folder_shortcut_data_model.m.js" ]
+  deps = [
+    ":folder_shortcuts_data_model.m",
+    "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/webui/resources/js/cr/ui:array_data_model.m",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("mock_navigation_list_model") {
   testonly = true
   deps = [ ":navigation_list_model" ]
@@ -254,9 +298,27 @@
 js_library("constants") {
 }
 
+js_library("constants.m") {
+  sources = [
+    "$root_gen_dir/ui/file_manager/file_manager/foreground/js/constants.m.js",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("crossover_search_utils") {
 }
 
+js_library("crossover_search_utils.m") {
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/crossover_search_utils.m.js" ]
+  deps = [
+    ":directory_model.m",
+    ":navigation_list_model.m",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("crostini_controller") {
   deps = [
     ":directory_model",
@@ -299,13 +361,33 @@
   ]
 }
 
-js_unittest("directory_contents_unittest") {
+js_library("directory_contents.m") {
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/directory_contents.m.js" ]
   deps = [
-    ":directory_contents",
-    ":directory_model",
-    "//ui/file_manager/base/js:test_error_reporting",
-    "//ui/file_manager/base/js:volume_manager_types",
-    "//ui/file_manager/externs:volume_manager",
+    ":constants.m",
+    ":file_list_model.m",
+    "metadata:metadata_model.m",
+    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/externs:files_app_entry_interfaces.m",
+    "//ui/file_manager/externs:volume_manager.m",
+    "//ui/file_manager/file_manager/common/js:async_util.m",
+    "//ui/file_manager/file_manager/common/js:metrics.m",
+    "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/webui/resources/js:assert.m",
+    "//ui/webui/resources/js:cr.m",
+    "//ui/webui/resources/js/cr:event_target.m",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
+js_unittest("directory_contents_unittest.m") {
+  deps = [
+    ":directory_contents.m",
+    "//chrome/test/data/webui:chai_assert",
+    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/externs:entry_location.m",
+    "//ui/file_manager/externs:volume_manager.m",
   ]
 }
 
@@ -322,6 +404,34 @@
   ]
 }
 
+js_library("directory_model.m") {
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/directory_model.m.js" ]
+  deps = [
+    ":constants.m",
+    ":directory_contents.m",
+    ":file_list_model.m",
+    ":file_watcher.m",
+    "metadata:metadata_model.m",
+    "ui:file_list_selection_model.m",
+    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/externs:entries_changed_event.m",
+    "//ui/file_manager/externs:files_app_entry_interfaces.m",
+    "//ui/file_manager/externs:volume_info.m",
+    "//ui/file_manager/externs:volume_manager.m",
+    "//ui/file_manager/externs/background:file_operation_manager.m",
+    "//ui/file_manager/file_manager/common/js:async_util.m",
+    "//ui/file_manager/file_manager/common/js:metrics.m",
+    "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/webui/resources/js:assert.m",
+    "//ui/webui/resources/js:cr.m",
+    "//ui/webui/resources/js/cr:event_target.m",
+    "//ui/webui/resources/js/cr/ui:list_selection_model.m",
+    "//ui/webui/resources/js/cr/ui:list_single_selection_model.m",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("navigation_uma") {
   deps = [
     ":dialog_type",
@@ -361,10 +471,25 @@
   ]
 }
 
-js_unittest("file_list_model_unittest") {
+js_library("file_list_model.m") {
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/file_list_model.m.js" ]
   deps = [
-    ":file_list_model",
-    "//ui/webui/resources/js:webui_resource_test",
+    "metadata:metadata_model.m",
+    "//ui/file_manager/externs:entry_location.m",
+    "//ui/file_manager/externs:volume_manager.m",
+    "//ui/file_manager/file_manager/common/js:file_type.m",
+    "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/webui/resources/js/cr/ui:array_data_model.m",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
+js_unittest("file_list_model_unittest.m") {
+  deps = [
+    ":file_list_model.m",
+    "metadata:metadata_model.m",
+    "//chrome/test/data/webui:chai_assert",
   ]
 }
 
@@ -539,6 +664,19 @@
   ]
 }
 
+js_library("file_watcher.m") {
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/file_watcher.m.js" ]
+  deps = [
+    "//ui/file_manager/externs:files_app_entry_interfaces.m",
+    "//ui/file_manager/file_manager/common/js:async_util.m",
+    "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/webui/resources/js:assert.m",
+    "//ui/webui/resources/js/cr:event_target.m",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("folder_shortcuts_data_model") {
   deps = [
     "//ui/file_manager/base/js:filtered_volume_manager",
@@ -550,6 +688,20 @@
   ]
 }
 
+js_library("folder_shortcuts_data_model.m") {
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.m.js" ]
+  deps = [
+    "//ui/file_manager/base/js:filtered_volume_manager.m",
+    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:async_util.m",
+    "//ui/file_manager/file_manager/common/js:metrics.m",
+    "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/webui/resources/js/cr:event_target.m",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("gear_menu_controller") {
   deps = [
     ":directory_model",
@@ -692,15 +844,45 @@
   ]
 }
 
-js_unittest("navigation_list_model_unittest") {
+js_library("navigation_list_model.m") {
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/navigation_list_model.m.js" ]
   deps = [
-    ":fake_android_app_list_model",
-    ":mock_directory_model",
-    ":mock_folder_shortcut_data_model",
-    ":navigation_list_model",
-    "//ui/file_manager/base/js:mock_chrome",
-    "//ui/file_manager/base/js:test_error_reporting",
-    "//ui/file_manager/file_manager/background/js:mock_volume_manager",
+    ":android_app_list_model.m",
+    ":directory_model.m",
+    ":folder_shortcuts_data_model.m",
+    "//chrome/test/data/webui:chai_assert",
+    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/externs:files_app_entry_interfaces.m",
+    "//ui/file_manager/externs:volume_info.m",
+    "//ui/file_manager/externs:volume_manager.m",
+    "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+    "//ui/file_manager/file_manager/common/js:trash.m",
+    "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/webui/resources/js:load_time_data.m",
+    "//ui/webui/resources/js/cr:event_target.m",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
+js_unittest("navigation_list_model_unittest.m") {
+  deps = [
+    ":android_app_list_model.m",
+    ":directory_model.m",
+    ":fake_android_app_list_model.m",
+    ":mock_directory_model.m",
+    ":mock_folder_shortcut_data_model.m",
+    ":navigation_list_model.m",
+    "//chrome/test/data/webui:chai_assert",
+    "//ui/file_manager/base/js:mock_chrome.m",
+    "//ui/file_manager/base/js:test_error_reporting.m",
+    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/externs:files_app_entry_interfaces.m",
+    "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
+    "//ui/file_manager/file_manager/background/js:volume_info_impl.m",
+    "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+    "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:util.m",
   ]
 }
 
@@ -884,7 +1066,12 @@
 }
 
 js_test_gen_html("js_test_gen_html_modules") {
-  deps = [ ":thumbnail_loader_unittest.m" ]
+  deps = [
+    ":directory_contents_unittest.m",
+    ":file_list_model_unittest.m",
+    ":navigation_list_model_unittest.m",
+    ":thumbnail_loader_unittest.m",
+  ]
   js_module = true
 
   closure_flags =
@@ -899,15 +1086,12 @@
 js_test_gen_html("js_test_gen_html") {
   deps = [
     ":actions_model_unittest",
-    ":directory_contents_unittest",
-    ":file_list_model_unittest",
     ":file_manager_commands_unittest",
     ":file_tasks_unittest",
     ":file_transfer_controller_unittest",
     ":file_type_filters_controller_unittest",
     ":import_controller_unittest",
     ":list_thumbnail_loader_unittest",
-    ":navigation_list_model_unittest",
     ":providers_model_unittest",
     ":spinner_controller_unittest",
     ":task_controller_unittest",
@@ -919,6 +1103,17 @@
   input_files = [
     "android_app_list_model.js",
     "thumbnail_loader.js",
+    "constants.js",
+    "directory_model.js",
+    "directory_contents.js",
+    "file_list_model.js",
+    "file_watcher.js",
+    "crossover_search_utils.js",
+    "navigation_list_model.js",
+    "folder_shortcuts_data_model.js",
+    "mock_directory_model.js",
+    "fake_android_app_list_model.js",
+    "mock_folder_shortcut_data_model.js",
   ]
 
   namespace_rewrites = cr_namespace_rewrites
diff --git a/ui/file_manager/file_manager/foreground/js/constants.js b/ui/file_manager/file_manager/foreground/js/constants.js
index c72ddcd3..459b199 100644
--- a/ui/file_manager/file_manager/foreground/js/constants.js
+++ b/ui/file_manager/file_manager/foreground/js/constants.js
@@ -3,6 +3,11 @@
 // found in the LICENSE file.
 
 /**
+ * @fileoverview
+ * @suppress {uselessCode} Temporary suppress because of the line exporting.
+ */
+
+/**
  * Namespace for common constnats used in Files app.
  * @namespace
  */
@@ -97,3 +102,12 @@
  * @const
  */
 constants.PLUGIN_VM = 'PvmDefault';
+
+/**
+ * DOMError type for crostini connection failure.
+ * @const {string}
+ */
+constants.CROSTINI_CONNECT_ERR = 'CrostiniConnectErr';
+
+// eslint-disable-next-line semi,no-extra-semi
+/* #export */ {constants};
diff --git a/ui/file_manager/file_manager/foreground/js/crossover_search_utils.js b/ui/file_manager/file_manager/foreground/js/crossover_search_utils.js
index 41c68d3..369a1ed 100644
--- a/ui/file_manager/file_manager/foreground/js/crossover_search_utils.js
+++ b/ui/file_manager/file_manager/foreground/js/crossover_search_utils.js
@@ -3,6 +3,16 @@
 // found in the LICENSE file.
 
 /**
+ * @fileoverview
+ * @suppress {uselessCode} Temporary suppress because of the line exporting.
+ */
+
+// clang-format off
+// #import {DirectoryModel} from './directory_model.m.js';
+// #import {NavigationModelItemType, NavigationListModel, NavigationModelFakeItem, NavigationModelVolumeItem} from './navigation_list_model.m.js';
+// clang-format on
+
+/**
  * Namespace for crossover search utility functions.
  * @namespace
  */
@@ -58,3 +68,6 @@
   }
   return null;
 };
+
+// eslint-disable-next-line semi,no-extra-semi
+/* #export */ {crossoverSearchUtils};
diff --git a/ui/file_manager/file_manager/foreground/js/directory_contents.js b/ui/file_manager/file_manager/foreground/js/directory_contents.js
index 5ac452d..8cb9940 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_contents.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_contents.js
@@ -2,10 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// clang-format off
+// #import {MetadataModel} from './metadata/metadata_model.m.js';
+// #import {VolumeManager} from '../../../externs/volume_manager.m.js';
+// #import {FilesAppDirEntry, FakeEntry} from '../../../externs/files_app_entry_interfaces.m.js';
+// #import {FileListModel} from './file_list_model.m.js';
+// #import {AsyncUtil} from '../../common/js/async_util.m.js';
+// #import {constants} from './constants.m.js';
+// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {assert} from 'chrome://resources/js/assert.m.js';
+// #import {util} from '../../common/js/util.m.js';
+// #import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
+// #import {dispatchSimpleEvent} from 'chrome://resources/js/cr.m.js';
+// #import {metrics} from '../../common/js/metrics.m.js';
+// clang-format on
+
 /**
  * Scanner of the entries.
  */
-class ContentScanner {
+/* #export */ class ContentScanner {
   constructor() {
     this.cancelled_ = false;
   }
@@ -36,7 +51,7 @@
 /**
  * Scanner of the entries in a directory.
  */
-class DirectoryContentScanner extends ContentScanner {
+/* #export */ class DirectoryContentScanner extends ContentScanner {
   /**
    * @param {DirectoryEntry|FilesAppDirEntry} entry The directory to be read.
    */
@@ -85,7 +100,7 @@
 /**
  * Scanner of the entries for the search results on Drive File System.
  */
-class DriveSearchContentScanner extends ContentScanner {
+/* #export */ class DriveSearchContentScanner extends ContentScanner {
   /** @param {string} query The query string. */
   constructor(query) {
     super();
@@ -160,7 +175,7 @@
  * Scanner of the entries of the file name search on the directory tree, whose
  * root is entry.
  */
-class LocalSearchContentScanner extends ContentScanner {
+/* #export */ class LocalSearchContentScanner extends ContentScanner {
   /**
    * @param {DirectoryEntry} entry The root of the search target directory tree.
    * @param {string} query The query of the search.
@@ -189,9 +204,9 @@
 /**
  * Scanner of the entries for the metadata search on Drive File System.
  */
-class DriveMetadataSearchContentScanner extends ContentScanner {
+/* #export */ class DriveMetadataSearchContentScanner extends ContentScanner {
   /**
-   * @param {!DriveMetadataSearchContentScanner.SearchType} searchType The
+   * @param {!chrome.fileManagerPrivate.SearchType} searchType The
    *     option of the search.
    */
   constructor(searchType) {
@@ -232,19 +247,7 @@
   }
 }
 
-/**
- * The search types on the Drive File System.
- * @enum {!chrome.fileManagerPrivate.SearchType}
- */
-DriveMetadataSearchContentScanner.SearchType = {
-  SEARCH_ALL: chrome.fileManagerPrivate.SearchType.ALL,
-  SEARCH_SHARED_WITH_ME: chrome.fileManagerPrivate.SearchType.SHARED_WITH_ME,
-  SEARCH_RECENT_FILES: chrome.fileManagerPrivate.SearchType.EXCLUDE_DIRECTORIES,
-  SEARCH_OFFLINE: chrome.fileManagerPrivate.SearchType.OFFLINE,
-};
-Object.freeze(DriveMetadataSearchContentScanner.SearchType);
-
-class RecentContentScanner extends ContentScanner {
+/* #export */ class RecentContentScanner extends ContentScanner {
   /**
    * @param {string} query Search query.
    * @param {chrome.fileManagerPrivate.SourceRestriction=} opt_sourceRestriction
@@ -295,7 +298,7 @@
 /**
  * Scanner of media-view volumes.
  */
-class MediaViewContentScanner extends ContentScanner {
+/* #export */ class MediaViewContentScanner extends ContentScanner {
   /**
    * @param {!DirectoryEntry} rootEntry The root entry of the media-view volume.
    */
@@ -338,7 +341,7 @@
  * is mounted as a disk volume and hide the fake root item while the
  * disk volume exists.
  */
-class CrostiniMounter extends ContentScanner {
+/* #export */ class CrostiniMounter extends ContentScanner {
   /**
    * @override
    */
@@ -348,8 +351,7 @@
         console.error(
             'mountCrostini error: ', chrome.runtime.lastError.message);
         errorCallback(util.createDOMError(
-            DirectoryModel.CROSTINI_CONNECT_ERR,
-            chrome.runtime.lastError.message));
+            constants.CROSTINI_CONNECT_ERR, chrome.runtime.lastError.message));
         return;
       }
       successCallback();
@@ -361,7 +363,7 @@
  * This class manages filters and determines a file should be shown or not.
  * When filters are changed, a 'changed' event is fired.
  */
-class FileFilter extends cr.EventTarget {
+/* #export */ class FileFilter extends cr.EventTarget {
   /** @param {!VolumeManager} volumeManager */
   constructor(volumeManager) {
     super();
@@ -519,7 +521,7 @@
  * A context of DirectoryContents.
  * TODO(yoshiki): remove this. crbug.com/224869.
  */
-class FileListContext {
+/* #export */ class FileListContext {
   /**
    * @param {FileFilter} fileFilter The file-filter context.
    * @param {!MetadataModel} metadataModel
@@ -584,7 +586,7 @@
  * results.
  * TODO(hidehiko): Remove EventTarget from this.
  */
-class DirectoryContents extends cr.EventTarget {
+/* #export */ class DirectoryContents extends cr.EventTarget {
   /**
    *
    * @param {FileListContext} context The file list context.
diff --git a/ui/file_manager/file_manager/foreground/js/directory_contents_unittest.js b/ui/file_manager/file_manager/foreground/js/directory_contents_unittest.m.js
similarity index 71%
rename from ui/file_manager/file_manager/foreground/js/directory_contents_unittest.js
rename to ui/file_manager/file_manager/foreground/js/directory_contents_unittest.m.js
index 020957f8..9540d2ad 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_contents_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_contents_unittest.m.js
@@ -2,10 +2,40 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {assertEquals, assertFalse} from 'chrome://test/chai_assert.js';
+import {installMockChrome} from '../../../base/js/mock_chrome.m.js';
+import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+import {EntryLocation} from '../../../externs/entry_location.m.js';
+import {VolumeManager} from '../../../externs/volume_manager.m.js';
+import {FileFilter} from './directory_contents.m.js';
+
+/**
+ * Mock chrome APIs.
+ * @type {Object}
+ */
+const mockChrome = {
+  fileManagerPrivate: {
+    SearchType: {
+      ALL: 'ALL',
+      SHARED_WITH_ME: 'SHARED_WITH_ME',
+      EXCLUDE_DIRECTORIES: 'EXCLUDE_DIRECTORIES',
+      OFFLINE: 'OFFLINE',
+    },
+  },
+};
+
+/**
+ * Initializes the test environment.
+ */
+export function setUp() {
+  // Install mock chrome APIs.
+  installMockChrome(mockChrome);
+}
+
 /**
  * Check that files are shown or hidden correctly.
  */
-function testHiddenFiles() {
+export function testHiddenFiles() {
   let volumeManagerRootType = VolumeManagerCommon.RootType.DOWNLOADS;
   // Create a fake volume manager that provides entry location info.
   const volumeManager = /** @type {!VolumeManager} */ ({
diff --git a/ui/file_manager/file_manager/foreground/js/directory_model.js b/ui/file_manager/file_manager/foreground/js/directory_model.js
index 097e9f446..ea4c2be 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_model.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_model.js
@@ -2,6 +2,29 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// clang-format off
+// #import {EntriesChangedEvent} from '../../../externs/entries_changed_event.m.js';
+// #import {ListSingleSelectionModel} from 'chrome://resources/js/cr/ui/list_single_selection_model.m.js';
+// #import {ListSelectionModel} from 'chrome://resources/js/cr/ui/list_selection_model.m.js';
+// #import {VolumeInfo} from '../../../externs/volume_info.m.js';
+// #import {FilesAppDirEntry, FakeEntry, FilesAppEntry} from '../../../externs/files_app_entry_interfaces.m.js';
+// #import {FileOperationManager} from '../../../externs/background/file_operation_manager.m.js';
+// #import {VolumeManager} from '../../../externs/volume_manager.m.js';
+// #import {MetadataModel} from './metadata/metadata_model.m.js';
+// #import {FileListSingleSelectionModel, FileListSelectionModel} from './ui/file_list_selection_model.m.js';
+// #import {FileWatcher} from './file_watcher.m.js';
+// #import {FileListModel} from './file_list_model.m.js';
+// #import {FileListContext, DirectoryContents, DirectoryContentScanner, RecentContentScanner, CrostiniMounter, DriveSearchContentScanner, LocalSearchContentScanner, MediaViewContentScanner, DriveMetadataSearchContentScanner, ContentScanner, FileFilter} from './directory_contents.m.js';
+// #import {constants} from './constants.m.js';
+// #import {assert} from 'chrome://resources/js/assert.m.js';
+// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {util} from '../../common/js/util.m.js';
+// #import {AsyncUtil} from '../../common/js/async_util.m.js';
+// #import {dispatchSimpleEvent} from 'chrome://resources/js/cr.m.js';
+// #import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
+// #import {metrics} from '../../common/js/metrics.m.js';
+// clang-format on
+
 // If directory files changes too often, don't rescan directory more than once
 // per specified interval
 const SIMULTANEOUS_RESCAN_INTERVAL = 500;
@@ -11,7 +34,7 @@
 /**
  * Data model of the file manager.
  */
-class DirectoryModel extends cr.EventTarget {
+/* #export */ class DirectoryModel extends cr.EventTarget {
   /**
    * @param {boolean} singleSelection True if only one file could be selected
    *                                  at the time.
@@ -770,7 +793,7 @@
       }
 
       // Do not rescan for crostini errors.
-      if (event.error.name === DirectoryModel.CROSTINI_CONNECT_ERR) {
+      if (event.error.name === constants.CROSTINI_CONNECT_ERR) {
         return;
       }
 
@@ -1403,16 +1426,13 @@
       let searchType;
       switch (locationInfo.rootType) {
         case VolumeManagerCommon.RootType.DRIVE_OFFLINE:
-          searchType =
-              DriveMetadataSearchContentScanner.SearchType.SEARCH_OFFLINE;
+          searchType = chrome.fileManagerPrivate.SearchType.OFFLINE;
           break;
         case VolumeManagerCommon.RootType.DRIVE_SHARED_WITH_ME:
-          searchType = DriveMetadataSearchContentScanner.SearchType
-                           .SEARCH_SHARED_WITH_ME;
+          searchType = chrome.fileManagerPrivate.SearchType.SHARED_WITH_ME;
           break;
         case VolumeManagerCommon.RootType.DRIVE_RECENT:
-          searchType =
-              DriveMetadataSearchContentScanner.SearchType.SEARCH_RECENT_FILES;
+          searchType = chrome.fileManagerPrivate.SearchType.EXCLUDE_DIRECTORIES;
           break;
         default:
           // Unknown special search entry.
@@ -1534,9 +1554,3 @@
     }
   }
 }
-
-/**
- * DOMError type for crostini connection failure.
- * @const {string}
- */
-DirectoryModel.CROSTINI_CONNECT_ERR = 'CrostiniConnectErr';
diff --git a/ui/file_manager/file_manager/foreground/js/empty_folder_controller.js b/ui/file_manager/file_manager/foreground/js/empty_folder_controller.js
index f47bb41..e2d9150 100644
--- a/ui/file_manager/file_manager/foreground/js/empty_folder_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/empty_folder_controller.js
@@ -77,7 +77,7 @@
   onScanFailed_(event) {
     this.isScanning_ = false;
     // Show alert for crostini connection error.
-    if (event.error.name == DirectoryModel.CROSTINI_CONNECT_ERR) {
+    if (event.error.name == constants.CROSTINI_CONNECT_ERR) {
       this.alertDialog_.showWithTitle(
           str('ERROR_LINUX_FILES_CONNECTION'), event.error.message);
     }
diff --git a/ui/file_manager/file_manager/foreground/js/fake_android_app_list_model.js b/ui/file_manager/file_manager/foreground/js/fake_android_app_list_model.js
index cd0c427..9229d89 100644
--- a/ui/file_manager/file_manager/foreground/js/fake_android_app_list_model.js
+++ b/ui/file_manager/file_manager/foreground/js/fake_android_app_list_model.js
@@ -2,11 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// clang-format off
+// #import {AndroidAppListModel} from './android_app_list_model.m.js';
+// #import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
+// clang-format on
+
 /**
  * @param {!Array<string>} appNames List app names to be added.
  * @returns {!AndroidAppListModel} fake for unittests.
  */
-function createFakeAndroidAppListModel(appNames) {
+/* #export */ function createFakeAndroidAppListModel(appNames) {
   /**
    * AndroidAppListModel fake.
    */
@@ -45,4 +50,4 @@
 
   const model = /** @type {!Object} */ (new FakeAndroidAppListModel(appNames));
   return /** @type {!AndroidAppListModel} */ (model);
-}
\ No newline at end of file
+}
diff --git a/ui/file_manager/file_manager/foreground/js/file_list_model.js b/ui/file_manager/file_manager/foreground/js/file_list_model.js
index f53a216..bdbed88 100644
--- a/ui/file_manager/file_manager/foreground/js/file_list_model.js
+++ b/ui/file_manager/file_manager/foreground/js/file_list_model.js
@@ -2,10 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// clang-format off
+// #import {EntryLocation} from '../../../externs/entry_location.m.js';
+// #import {VolumeManager} from '../../../externs/volume_manager.m.js';
+// #import {MetadataModel} from './metadata/metadata_model.m.js';
+// #import {FileType} from '../../common/js/file_type.m.js';
+// #import {strf, str, util} from '../../common/js/util.m.js';
+// #import {ArrayDataModel} from 'chrome://resources/js/cr/ui/array_data_model.m.js';
+// clang-format on
+
 /**
  * File list.
  */
-class FileListModel extends cr.ui.ArrayDataModel {
+/* #export */ class FileListModel extends cr.ui.ArrayDataModel {
   /** @param {!MetadataModel} metadataModel */
   constructor(metadataModel) {
     super([]);
@@ -254,8 +263,8 @@
    * @override
    */
   replaceItem(oldItem, newItem) {
-    this.onRemoveEntryFromList_(oldItem);
-    this.onAddEntryToList_(newItem);
+    this.onRemoveEntryFromList_(/** @type {?Entry} */ (oldItem));
+    this.onAddEntryToList_(/** @type {?Entry} */ (newItem));
 
     cr.ui.ArrayDataModel.prototype.replaceItem.apply(this, arguments);
   }
diff --git a/ui/file_manager/file_manager/foreground/js/file_list_model_unittest.js b/ui/file_manager/file_manager/foreground/js/file_list_model_unittest.m.js
similarity index 93%
rename from ui/file_manager/file_manager/foreground/js/file_list_model_unittest.js
rename to ui/file_manager/file_manager/foreground/js/file_list_model_unittest.m.js
index 23be6d9..f9b8384 100644
--- a/ui/file_manager/file_manager/foreground/js/file_list_model_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/file_list_model_unittest.m.js
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {assertArrayEquals, assertEquals} from 'chrome://test/chai_assert.js';
+import {FileListModel} from './file_list_model.m.js';
+import {MetadataModel} from './metadata/metadata_model.m.js';
+
 const TEST_METADATA = {
   'a.txt': {
     contentMimeType: 'text/plain',
@@ -64,7 +68,7 @@
   });
 }
 
-function testIsImageDominant() {
+export function testIsImageDominant() {
   const fileListModel =
       new FileListModel(createFakeMetadataModel(TEST_METADATA));
 
@@ -92,7 +96,7 @@
   assertEquals(fileListModel.isImageDominant(), true);
 }
 
-function testSortWithFolders() {
+export function testSortWithFolders() {
   const fileListModel =
       new FileListModel(createFakeMetadataModel(TEST_METADATA));
   fileListModel.push({name: 'dirA', isDirectory: true});
@@ -124,7 +128,7 @@
       fileListModel, ['dirB', 'dirA', 'a.txt', 'b.html', 'c.jpg']);
 }
 
-function testSplice() {
+export function testSplice() {
   const fileListModel = makeSimpleFileListModel(['d', 'a', 'x', 'n']);
   fileListModel.sort('name', 'asc');
 
@@ -145,7 +149,7 @@
   assertFileListModelElementNames(fileListModel, ['a', 'b', 'd', 'p', 'x']);
 }
 
-function testSpliceWithoutSortStatus() {
+export function testSpliceWithoutSortStatus() {
   const fileListModel = makeSimpleFileListModel(['d', 'a', 'x', 'n']);
 
   fileListModel.addEventListener('splice', event => {
@@ -168,7 +172,7 @@
   assertFileListModelElementNames(fileListModel, ['d', 'a', 'p', 'b', 'n']);
 }
 
-function testSpliceWithoutAddingNewItems() {
+export function testSpliceWithoutAddingNewItems() {
   const fileListModel = makeSimpleFileListModel(['d', 'a', 'x', 'n']);
   fileListModel.sort('name', 'asc');
 
@@ -189,7 +193,7 @@
   assertFileListModelElementNames(fileListModel, ['a', 'd', 'x']);
 }
 
-function testSpliceWithoutDeletingItems() {
+export function testSpliceWithoutDeletingItems() {
   const fileListModel = makeSimpleFileListModel(['d', 'a', 'x', 'n']);
   fileListModel.sort('name', 'asc');
 
diff --git a/ui/file_manager/file_manager/foreground/js/file_watcher.js b/ui/file_manager/file_manager/foreground/js/file_watcher.js
index bd5d55f..cc3a7a6 100644
--- a/ui/file_manager/file_manager/foreground/js/file_watcher.js
+++ b/ui/file_manager/file_manager/foreground/js/file_watcher.js
@@ -2,8 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// clang-format off
+// #import {FilesAppEntry} from '../../../externs/files_app_entry_interfaces.m.js';
+// #import {assert} from 'chrome://resources/js/assert.m.js';
+// #import {util} from '../../common/js/util.m.js';
+// #import {AsyncUtil} from '../../common/js/async_util.m.js';
+// #import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
+// clang-format on
+
 /** Watches for changes in the tracked directory. */
-class FileWatcher extends cr.EventTarget {
+/* #export */ class FileWatcher extends cr.EventTarget {
   constructor() {
     super();
 
diff --git a/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js b/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js
index be3a8b4..598fde0c 100644
--- a/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js
+++ b/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js
@@ -2,6 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// clang-format off
+// #import {FilteredVolumeManager} from '../../../base/js/filtered_volume_manager.m.js';
+// #import {util} from '../../common/js/util.m.js';
+// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {AsyncUtil} from '../../common/js/async_util.m.js';
+// #import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
+// #import {metrics} from '../../common/js/metrics.m.js';
+// clang-format on
+
 /**
  * The drive mount path used in the storage. It must be '/drive'.
  * @type {string}
@@ -13,7 +22,7 @@
  * object with additional methods for the folder shortcut feature.
  * This uses chrome.storage as backend. Items are always sorted by URL.
  */
-class FolderShortcutsDataModel extends cr.EventTarget {
+/* #export */ class FolderShortcutsDataModel extends cr.EventTarget {
   /**
    * @param {!FilteredVolumeManager} volumeManager Volume manager instance.
    */
diff --git a/ui/file_manager/file_manager/foreground/js/mock_directory_model.js b/ui/file_manager/file_manager/foreground/js/mock_directory_model.js
index ecfbe3a1d..96d3b8d 100644
--- a/ui/file_manager/file_manager/foreground/js/mock_directory_model.js
+++ b/ui/file_manager/file_manager/foreground/js/mock_directory_model.js
@@ -2,6 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// clang-format off
+// #import {FilesAppDirEntry, FakeEntry} from '../../../externs/files_app_entry_interfaces.m.js';
+// #import {DirectoryModel} from './directory_model.m.js';
+// #import {FileFilter} from './directory_contents.m.js';
+// #import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
+// clang-format on
+
 /**
  * @returns {!FileFilter} fake for unittests.
  */
@@ -26,7 +33,7 @@
 /**
  * @returns {!DirectoryModel} fake for unittests.
  */
-function createFakeDirectoryModel() {
+/* #export */ function createFakeDirectoryModel() {
   /**
    * DirectoryModel fake.
    */
diff --git a/ui/file_manager/file_manager/foreground/js/mock_folder_shortcut_data_model.js b/ui/file_manager/file_manager/foreground/js/mock_folder_shortcut_data_model.js
index dac15e6..37d96ea 100644
--- a/ui/file_manager/file_manager/foreground/js/mock_folder_shortcut_data_model.js
+++ b/ui/file_manager/file_manager/foreground/js/mock_folder_shortcut_data_model.js
@@ -2,12 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-'use strict';
+// clang-format off
+// #import {MockEntry} from '../../common/js/mock_entry.m.js';
+// #import {FolderShortcutsDataModel} from './folder_shortcuts_data_model.m.js';
+// #import {ArrayDataModel} from 'chrome://resources/js/cr/ui/array_data_model.m.js';
+// clang-format on
+
+/* #ignore */ 'use strict';
 
 /**
  * Mock FolderShortcutDataModel.
  */
-class MockFolderShortcutDataModel extends cr.ui.ArrayDataModel {
+/* #export */ class MockFolderShortcutDataModel extends cr.ui.ArrayDataModel {
   /**
    * @param {!Array} array
    */
diff --git a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
index e59e774..321203f7 100644
--- a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
+++ b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
@@ -2,10 +2,26 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// clang-format off
+// #import {FolderShortcutsDataModel} from './folder_shortcuts_data_model.m.js';
+// #import {DirectoryModel} from './directory_model.m.js';
+// #import {AndroidAppListModel} from './android_app_list_model.m.js';
+// #import {VolumeManager} from '../../../externs/volume_manager.m.js';
+// #import {FilesAppEntry, FakeEntry} from '../../../externs/files_app_entry_interfaces.m.js';
+// #import {VolumeInfo} from '../../../externs/volume_info.m.js';
+// #import {TrashRootEntry} from '../../common/js/trash.m.js';
+// #import {util, str} from '../../common/js/util.m.js';
+// #import {FakeEntryImpl, VolumeEntry, EntryList} from '../../common/js/files_app_entry_types.m.js';
+// #import {assertNotReached} from 'chrome://resources/js/assert.m.js';
+// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
+// #import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+// clang-format on
+
 /**
  * @enum {string}
  */
-const NavigationModelItemType = {
+/* #export */ const NavigationModelItemType = {
   SHORTCUT: 'shortcut',
   VOLUME: 'volume',
   RECENT: 'recent',
@@ -28,7 +44,7 @@
  *      - ANDROID_APPS: ANDROID picker apps.
  * @enum {string}
  */
-const NavigationSection = {
+/* #export */ const NavigationSection = {
   TOP: 'top',
   MY_FILES: 'my_files',
   REMOVABLE: 'removable',
@@ -39,7 +55,7 @@
 /**
  * Base item of NavigationListModel. Should not be created directly.
  */
-class NavigationModelItem {
+/* #export */ class NavigationModelItem {
   /**
    * @param {string} label
    * @param {NavigationModelItemType} type
@@ -88,7 +104,7 @@
 /**
  * Item of NavigationListModel for shortcuts.
  */
-class NavigationModelShortcutItem extends NavigationModelItem {
+/* #export */ class NavigationModelShortcutItem extends NavigationModelItem {
   /**
    * @param {string} label Label.
    * @param {!DirectoryEntry} entry Entry. Cannot be null.
@@ -106,7 +122,7 @@
 /**
  * Item of NavigationListModel for Android apps.
  */
-class NavigationModelAndroidAppItem extends NavigationModelItem {
+/* #export */ class NavigationModelAndroidAppItem extends NavigationModelItem {
   /**
    * @param {!chrome.fileManagerPrivate.AndroidApp} androidApp Android app.
    *     Cannot be null.
@@ -127,7 +143,7 @@
 /**
  * Item of NavigationListModel for volumes.
  */
-class NavigationModelVolumeItem extends NavigationModelItem {
+/* #export */ class NavigationModelVolumeItem extends NavigationModelItem {
   /**
    * @param {string} label Label.
    * @param {!VolumeInfo} volumeInfo Volume info for the volume. Cannot be null.
@@ -148,7 +164,7 @@
 /**
  * Item of NavigationListModel for a fake item such as Recent or Linux files.
  */
-class NavigationModelFakeItem extends NavigationModelItem {
+/* #export */ class NavigationModelFakeItem extends NavigationModelItem {
   /**
    * @param {string} label Label on the menu button.
    * @param {NavigationModelItemType} type
@@ -167,7 +183,7 @@
 /**
  * A navigation list model. This model combines multiple models.
  */
-class NavigationListModel extends cr.EventTarget {
+/* #export */ class NavigationListModel extends cr.EventTarget {
   /**
    * @param {!VolumeManager} volumeManager VolumeManager instance.
    * @param {!FolderShortcutsDataModel} shortcutListModel The list of folder
diff --git a/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.js b/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.m.js
similarity index 92%
rename from ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.js
rename to ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.m.js
index 6a1cf89a..2e0d16c 100644
--- a/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.m.js
@@ -2,7 +2,27 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-'use strict';
+// clang-format off
+import {assertEquals, assertTrue} from 'chrome://test/chai_assert.js';
+
+import {MockCommandLinePrivate} from '../../../base/js/mock_chrome.m.js';
+import {reportPromise, waitUntil} from '../../../base/js/test_error_reporting.m.js';
+import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+import {FilesAppEntry} from '../../../externs/files_app_entry_interfaces.m.js';
+import {MockVolumeManager} from '../../background/js/mock_volume_manager.m.js';
+import {VolumeInfoImpl} from '../../background/js/volume_info_impl.m.js';
+import { EntryList,FakeEntryImpl} from '../../common/js/files_app_entry_types.m.js';
+import { MockFileEntry,MockFileSystem} from '../../common/js/mock_entry.m.js';
+import {util} from '../../common/js/util.m.js';
+
+import {AndroidAppListModel} from './android_app_list_model.m.js';
+import {DirectoryModel} from './directory_model.m.js';
+import {createFakeAndroidAppListModel} from './fake_android_app_list_model.m.js';
+import {createFakeDirectoryModel} from './mock_directory_model.m.js';
+import {MockFolderShortcutDataModel} from './mock_folder_shortcut_data_model.m.js';
+import { NavigationListModel, NavigationModelAndroidAppItem,NavigationModelFakeItem, NavigationModelItemType, NavigationModelShortcutItem, NavigationModelVolumeItem, NavigationSection} from './navigation_list_model.m.js';
+// clang-format on
+
 
 /**
  * Mock Recent fake entry.
@@ -36,7 +56,7 @@
 let hoge;
 
 // Setup the test components.
-function setUp() {
+export function setUp() {
   // Mock LoadTimeData strings.
   window.loadTimeData.data = {
     MY_FILES_ROOT_LABEL: 'My files',
@@ -68,7 +88,7 @@
 /**
  * Tests model.
  */
-function testModel() {
+export function testModel() {
   const volumeManager = new MockVolumeManager();
 
   const shortcutListModel = new MockFolderShortcutDataModel(
@@ -124,7 +144,7 @@
 /**
  * Tests model with no Recents, Linux files, Play files.
  */
-function testNoRecentOrLinuxFiles() {
+export function testNoRecentOrLinuxFiles() {
   const volumeManager = new MockVolumeManager();
 
   const shortcutListModel = new MockFolderShortcutDataModel(
@@ -148,7 +168,7 @@
 /**
  * Tests adding and removing shortcuts.
  */
-function testAddAndRemoveShortcuts() {
+export function testAddAndRemoveShortcuts() {
   const volumeManager = new MockVolumeManager();
 
   const shortcutListModel = new MockFolderShortcutDataModel(
@@ -211,7 +231,7 @@
 /**
  * Tests testAddAndRemoveVolumes test with SinglePartitionFormat flag is on.
  */
-function testAddAndRemoveVolumesWhenSinglePartitionOn() {
+export function testAddAndRemoveVolumesWhenSinglePartitionOn() {
   window.loadTimeData.data_['FILES_SINGLE_PARTITION_FORMAT_ENABLED'] = true;
   testAddAndRemoveVolumes();
 }
@@ -219,7 +239,7 @@
 /**
  * Tests adding and removing volumes.
  */
-function testAddAndRemoveVolumes() {
+export function testAddAndRemoveVolumes() {
   const volumeManager = new MockVolumeManager();
 
   const shortcutListModel = new MockFolderShortcutDataModel(
@@ -321,7 +341,7 @@
 /**
  * Tests testOrderAndNestItems test with SinglePartitionFormat flag is on.
  */
-function testOrderAndNestItemsWhenSinglePartitionOn() {
+export function testOrderAndNestItemsWhenSinglePartitionOn() {
   window.loadTimeData.data_['FILES_SINGLE_PARTITION_FORMAT_ENABLED'] = true;
   testOrderAndNestItems();
 }
@@ -332,7 +352,7 @@
  * 2. manages NavigationSection for the relevant volumes.
  * 3. keeps MTP/Archive/Removable volumes on the original order.
  */
-function testOrderAndNestItems() {
+export function testOrderAndNestItems() {
   const volumeManager = new MockVolumeManager();
 
   const shortcutListModel = new MockFolderShortcutDataModel([
@@ -502,7 +522,7 @@
 /**
  * Tests model with My files enabled.
  */
-function testMyFilesVolumeEnabled(callback) {
+export function testMyFilesVolumeEnabled(callback) {
   const volumeManager = new MockVolumeManager();
   // Item 1 of the volume info list should have Downloads volume type.
   assertEquals(
@@ -574,7 +594,7 @@
  * Tests that adding a new partition to the same grouped USB will add the
  * partition to the grouping.
  */
-function testMultipleUsbPartitionsGrouping() {
+export function testMultipleUsbPartitionsGrouping() {
   const shortcutListModel = new MockFolderShortcutDataModel([]);
   const recentItem = null;
   const volumeManager = new MockVolumeManager();
diff --git a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
index 66d2b71..292132e 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
@@ -5,6 +5,8 @@
 import("//third_party/closure_compiler/compile_js.gni")
 import("//third_party/closure_compiler/js_unit_tests.gni")
 import("//ui/file_manager/base/gn/js_test_gen_html.gni")
+import("//ui/webui/resources/js/cr.gni")
+import("//ui/webui/resources/tools/js_modulizer.gni")
 
 visibility = [ "//ui/file_manager/file_manager/foreground/*" ]
 
@@ -12,11 +14,18 @@
   testonly = true
   visibility += [ "//ui/file_manager:closure_compile" ]
   deps = [
+    ":closure_compile_jsmodules",
     ":closure_compile_module",
+    ":js_test_gen_html_modules_type_check_auto",
     ":js_test_gen_html_type_check_auto",
   ]
 }
 
+js_type_check("closure_compile_jsmodules") {
+  uses_js_modules = true
+  deps = [ ":file_list_selection_model.m" ]
+}
+
 js_type_check("closure_compile_module") {
   deps = [
     ":action_model_ui",
@@ -232,10 +241,20 @@
   ]
 }
 
-js_unittest("file_list_selection_model_unittest") {
+js_library("file_list_selection_model.m") {
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/file_list_selection_model.m.js" ]
   deps = [
-    ":file_list_selection_model",
-    "//ui/webui/resources/js:webui_resource_test",
+    "//ui/webui/resources/js/cr/ui:list_selection_model.m",
+    "//ui/webui/resources/js/cr/ui:list_single_selection_model.m",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
+js_unittest("file_list_selection_model_unittest.m") {
+  deps = [
+    ":file_list_selection_model.m",
+    "//chrome/test/data/webui:chai_assert",
   ]
 }
 
@@ -530,12 +549,23 @@
       [ "//ui/file_manager/externs/chrome_webstore_widget_private.js" ]
 }
 
+js_test_gen_html("js_test_gen_html_modules") {
+  deps = [ ":file_list_selection_model_unittest.m" ]
+  js_module = true
+
+  closure_flags =
+      strict_error_checking_closure_args + [
+        "js_module_root=./gen/ui",
+        "js_module_root=../../ui",
+        "browser_resolver_prefix_replacements=\"chrome://test/=./\"",
+      ]
+}
+
 js_test_gen_html("js_test_gen_html") {
   deps = [
     ":actions_submenu_unittest",
     ":breadcrumb_unittest",
     ":directory_tree_unittest",
-    ":file_list_selection_model_unittest",
     ":file_manager_dialog_base_unittest",
     ":file_table_list_unittest",
     ":file_table_unittest",
@@ -544,3 +574,9 @@
     ":multi_menu_unittest",
   ]
 }
+
+js_modulizer("modulize") {
+  input_files = [ "file_list_selection_model.js" ]
+
+  namespace_rewrites = cr_namespace_rewrites
+}
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_list_selection_model.js b/ui/file_manager/file_manager/foreground/js/ui/file_list_selection_model.js
index e60a4004..b5d85ff 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_list_selection_model.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_list_selection_model.js
@@ -2,7 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-class FileListSelectionModel extends cr.ui.ListSelectionModel {
+// clang-format off
+// #import {ListSingleSelectionModel} from 'chrome://resources/js/cr/ui/list_single_selection_model.m.js';
+// #import {ListSelectionModel} from 'chrome://resources/js/cr/ui/list_selection_model.m.js';
+// clang-format on
+
+/* #export */ class FileListSelectionModel extends cr.ui.ListSelectionModel {
   /** @param {number=} opt_length The number items in the selection. */
   constructor(opt_length) {
     super(opt_length);
@@ -92,7 +97,8 @@
   }
 }
 
-class FileListSingleSelectionModel extends cr.ui.ListSingleSelectionModel {
+/* #export */ class FileListSingleSelectionModel extends
+    cr.ui.ListSingleSelectionModel {
   /**
    * Updates the check-select mode.
    * @param {boolean} enabled True if check-select mode should be enabled.
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_list_selection_model_unittest.js b/ui/file_manager/file_manager/foreground/js/ui/file_list_selection_model_unittest.m.js
similarity index 77%
rename from ui/file_manager/file_manager/foreground/js/ui/file_list_selection_model_unittest.js
rename to ui/file_manager/file_manager/foreground/js/ui/file_list_selection_model_unittest.m.js
index 91a9a8bd..05af1f5 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_list_selection_model_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_list_selection_model_unittest.m.js
@@ -2,16 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {assertArrayEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
+import {FileListSelectionModel} from './file_list_selection_model.m.js';
+
 /** @type {!FileListSelectionModel} */
 let selectionModel;
 
-function setUp() {
+export function setUp() {
   selectionModel = new FileListSelectionModel();
 }
 
 // Verify that all selection and focus is dropped if all selected files get
 // deleted.
-function testAdjustToReorderingAllAreDeleted() {
+export function testAdjustToReorderingAllAreDeleted() {
   // Set initial selection.
   selectionModel.selectedIndexes = [0, 1];
   // Delete the selected items.
@@ -23,7 +26,7 @@
 
 // Verify that all selection and focus is dropped only if all selected files get
 // deleted.
-function testAdjustToReorderingSomeAreDeleted() {
+export function testAdjustToReorderingSomeAreDeleted() {
   // Set initial selection.
   selectionModel.selectedIndexes = [0, 1];
   // Delete the selected items.
diff --git a/ui/file_manager/file_manager/test/BUILD.gn b/ui/file_manager/file_manager/test/BUILD.gn
index f48e22d..6f0b620 100644
--- a/ui/file_manager/file_manager/test/BUILD.gn
+++ b/ui/file_manager/file_manager/test/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//third_party/closure_compiler/compile_js.gni")
 
-action("create_test_main") {
+python2_action("create_test_main") {
   script = "//ui/file_manager/file_manager/test/scripts/create_test_main.py"
   output = "$target_gen_dir/../test.html"
   sources = [
diff --git a/ui/file_manager/video_player/js/BUILD.gn b/ui/file_manager/video_player/js/BUILD.gn
index fe4f9a3..668c3252 100644
--- a/ui/file_manager/video_player/js/BUILD.gn
+++ b/ui/file_manager/video_player/js/BUILD.gn
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//chrome/browser/resources/optimize_webui.gni")
+import("//chrome/browser/resources/tools/optimize_webui.gni")
 import("//third_party/closure_compiler/compile_js.gni")
 import("//third_party/closure_compiler/js_unit_tests.gni")
 import("//ui/file_manager/base/gn/js_test_gen_html.gni")