diff --git a/BUILD.gn b/BUILD.gn
index 6c5f05698..6552bd7 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -385,10 +385,10 @@
         "//chrome/android:chrome_public_apk",
         "//chrome/android:chrome_public_test_apk",
         "//chrome/android/features/media_router:media_router_junit_tests",
+        "//chrome/browser/android/examples/custom_tabs_client:custom_tabs_client_example_apk",
         "//chrome/browser/android/examples/partner_browser_customizations_provider:partner_browser_customizations_example_apk",
         "//chrome/test/chromedriver/test/webview_shell:chromedriver_webview_shell_apk",
         "//content/shell/android:content_shell_test_apk",
-        "//third_party/custom_tabs_client:custom_tabs_client_example_apk",
       ]
     }
 
@@ -813,8 +813,8 @@
 
   if (build_dawn_tests) {
     deps += [
-      "//third_party/dawn:dawn_end2end_tests_temp_group",
-      "//third_party/dawn:dawn_unittests_temp_group",
+      "//third_party/dawn/src/tests:dawn_end2end_tests",
+      "//third_party/dawn/src/tests:dawn_unittests",
     ]
   }
 
@@ -928,8 +928,8 @@
       "//sandbox/linux:chrome_sandbox",
       "//sandbox/linux:sandbox_linux_unittests",
       "//third_party/breakpad:minidump_stackwalk($host_toolchain)",
-      "//third_party/dawn:dawn_end2end_tests_temp_group",
-      "//third_party/dawn:dawn_unittests_temp_group",
+      "//third_party/dawn/src/tests:dawn_end2end_tests",
+      "//third_party/dawn/src/tests:dawn_unittests",
 
       # Blocked on https://github.com/catapult-project/catapult/issues/2297
       #"//third_party/catapult/telemetry:bitmaptools",
diff --git a/DEPS b/DEPS
index ac4afd1..11dd954 100644
--- a/DEPS
+++ b/DEPS
@@ -175,11 +175,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': 'ad653d8378d7a17502956c4addebb68eb3129961',
+  'skia_revision': 'eb1d5a2e233ccfa7d0f6e0ac7355bf4a17aff2d0',
   # 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': '02ab339626274f8c4040dd94bda29136e206827f',
+  'v8_revision': 'a0ab34903ce450d674f591ce3ffdf1314a5ffa99',
   # 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.
@@ -187,11 +187,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '965eedbfbf1e613ff4ebffe8bf4c291bc39a259c',
+  'angle_revision': '3d894d87b25bcfcc1e410cbc08109ad78665c632',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '20220a0b0640436b659d0361a9d0789bc81d4177',
+  'swiftshader_revision': 'e52e2dbcdf9d46b63ec6cc4df8bdea6f916c97e9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -210,7 +210,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling googletest
   # and whatever else without interference from each other.
-  'googletest_revision': '10b1902d893ea8cc43c69541d70868f91af3646b',
+  'googletest_revision': 'e3f0319d89f4cbf32993de595d984183b1a9fc57',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling lighttpd
   # and whatever else without interference from each other.
@@ -246,7 +246,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': '5e43b27e8b453a22e365561b6a9a08d47999e6d4',
+  'devtools_frontend_revision': 'decaee5ce9bf0b533cca09010f61e0816bf43775',
   # 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.
@@ -525,7 +525,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'd36b5e8f3d12b4123032a3a3abc9296984a617a3',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'fb7a6f4f266117319b36ae57c89d3acf07412bb5',
       'condition': 'checkout_ios',
   },
 
@@ -856,7 +856,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'e9d37e79b47f1b63df9b5569047b7bbd52dbab32',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '9aba22264b1bce883ebff2c54573ef26546339ad',
       'condition': 'checkout_linux',
   },
 
@@ -875,11 +875,6 @@
       'condition': 'checkout_linux',
   },
 
-  'src/third_party/custom_tabs_client/src': {
-      'url': Var('chromium_git') + '/custom-tabs-client.git' + '@' + 'a633542d9854151eb4f0bfd1d93da88f5934a11a',
-      'condition': 'checkout_android',
-  },
-
   'src/third_party/depot_tools':
     Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '08f4d59e0b177d3d15b65f9826bbf05491b3841d',
 
@@ -1235,7 +1230,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'e1432869418635b0097a59315b7df26a6a74fc9b',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '38cf748e7a5f5da132b43e93957468f1462397a2',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1465,7 +1460,7 @@
   },
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '8a948a3e2b43db313e3afef36af4109e9d401746',
+    Var('webrtc_git') + '/src.git' + '@' + '3e2809f4f0cd922a0785f7bbad704fa53fcf16fc',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1540,7 +1535,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@8c8408b7248ca4e68d9a3b740a99cb89cef392d5',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@62d5d8e82707f4013636a3275c612424f4cd891c',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/gfx/aw_picture.cc b/android_webview/browser/gfx/aw_picture.cc
index 5e5b2d5df..3d58d45 100644
--- a/android_webview/browser/gfx/aw_picture.cc
+++ b/android_webview/browser/gfx/aw_picture.cc
@@ -34,6 +34,9 @@
                      const JavaParamRef<jobject>& obj,
                      const JavaParamRef<jobject>& canvas) {
   const SkIRect bounds = picture_->cullRect().roundOut();
+  if (bounds.isEmpty()) {
+    return;
+  }
   std::unique_ptr<SoftwareCanvasHolder> canvas_holder =
       SoftwareCanvasHolder::Create(canvas, gfx::Vector2d(),
                                    gfx::Size(bounds.width(), bounds.height()),
diff --git a/android_webview/docs/developer-ui.md b/android_webview/docs/developer-ui.md
index ffbd1acf..78cea80 100644
--- a/android_webview/docs/developer-ui.md
+++ b/android_webview/docs/developer-ui.md
@@ -38,7 +38,52 @@
 
 ## Crash UI
 
-TODO(http://crbug.com/1058571): document this.
+Crash UI shows recent WebView-caused crashes from apps on the device, similar
+to `chrome://crashes`. You can access it by tapping the "Crashes" option in the
+bottom navigation bar.
+
+*** note
+**Note:**
+You have to opt in android crash collection in order for crash reports to show
+up in the UI. An error message will show up if you haven't opted-in. To opt-in,
+go to the device settings > Google > three-dotted menu > Usage & diagnostics
+and make sure it's enabled. For AOSP builds, you can enable crash collection
+by enabling the `enable-crash-reporter-for-testing` flag from the
+[Flags UI](#Flag-UI).
+***
+
+![WebView crashes UI](images/webview_crashes_ui.png)
+
+Tap a crash entry to expand it for more info and actions for that crash.
+
+*** note
+**Note:** Some types of crashes such as renderer crashes can show up instantly
+in the UI. However, most WebView crashes will require relaunching the
+application where the crash happened so it can be detected and appear in the
+UI.
+***
+
+### Force upload a crash report
+
+Crash reports are automatically reported to WebView's crash collection server.
+Sometimes a crash report may not be automatically uploaded. For instance, when
+the device is not connected to Wifi (will show in the crashes list with
+"pending upload" status). The crash report can also skip upload due to random
+sampling (will appear with "skipped" status). You can force upload that crash
+report by pressing the "Upload this crash report" button. After the crash
+report is uploaded you can then use the upload ID to open a bug report to
+provide more info about that crash.
+
+### Provide more info about a crash
+
+While the crash server has most of the information we need to solve issues, it
+is helpful if you can provide additional details in a bug report, such as steps
+to reproduce the crash. To do so press the "File bug report" button which will
+open [crbug.com](https://bugs.chromium.org/p/chromium/issues/entry?template=Webview+Bugs)
+in the browser. You can use the bug report template to provide additional info
+about the crash for the WebView engineering team. Make sure to fill all the
+relevant fields in the bug report and leave the crash upload ID in the bug
+description so that the WebView team can effectively investigate the crash.
 
 ## Flag UI
 
diff --git a/android_webview/docs/images/webview_crashes_ui.png b/android_webview/docs/images/webview_crashes_ui.png
new file mode 100644
index 0000000..5a91217
--- /dev/null
+++ b/android_webview/docs/images/webview_crashes_ui.png
Binary files differ
diff --git a/android_webview/system_webview_apk_tmpl.gni b/android_webview/system_webview_apk_tmpl.gni
index 30cab84..ce911bf 100644
--- a/android_webview/system_webview_apk_tmpl.gni
+++ b/android_webview/system_webview_apk_tmpl.gni
@@ -19,7 +19,7 @@
   system_webview_package_name = "com.android.webview"
 
   # Whether to enable standalone and trichrome WebView bundle build targets.
-  enable_webview_bundles = false
+  enable_webview_bundles = true
 }
 
 template("system_webview_apk_or_module_tmpl") {
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index e8a5e4b..8f2849b 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -734,6 +734,10 @@
     "system/accessibility/autoclick_scroll_view.h",
     "system/accessibility/dictation_button_tray.cc",
     "system/accessibility/dictation_button_tray.h",
+    "system/accessibility/floating_accessibility_controller.cc",
+    "system/accessibility/floating_accessibility_controller.h",
+    "system/accessibility/floating_accessibility_view.cc",
+    "system/accessibility/floating_accessibility_view.h",
     "system/accessibility/floating_menu_button.cc",
     "system/accessibility/floating_menu_button.h",
     "system/accessibility/select_to_speak_tray.cc",
@@ -1961,6 +1965,7 @@
     "system/accessibility/accessibility_feature_pod_controller_unittest.cc",
     "system/accessibility/autoclick_menu_bubble_controller_unittest.cc",
     "system/accessibility/dictation_button_tray_unittest.cc",
+    "system/accessibility/floating_accessibility_controller_unittest.cc",
     "system/accessibility/select_to_speak_tray_unittest.cc",
     "system/accessibility/switch_access_menu_bubble_controller_unittest.cc",
     "system/accessibility/tray_accessibility_unittest.cc",
diff --git a/ash/accessibility/accessibility_controller_impl.cc b/ash/accessibility/accessibility_controller_impl.cc
index d20924a..a897794f 100644
--- a/ash/accessibility/accessibility_controller_impl.cc
+++ b/ash/accessibility/accessibility_controller_impl.cc
@@ -32,6 +32,7 @@
 #include "ash/sticky_keys/sticky_keys_controller.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/accessibility/accessibility_feature_disable_dialog.h"
+#include "ash/system/accessibility/floating_accessibility_controller.h"
 #include "ash/system/accessibility/switch_access_menu_bubble_controller.h"
 #include "ash/system/power/backlights_forced_off_setter.h"
 #include "ash/system/power/power_status.h"
@@ -590,6 +591,10 @@
   registry->RegisterBooleanPref(
       prefs::kAccessibilityFloatingMenuEnabled, false,
       user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
+  registry->RegisterIntegerPref(
+      prefs::kAccessibilityFloatingMenuPosition,
+      static_cast<int>(kDefaultFloatingMenuPosition),
+      user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
   registry->RegisterBooleanPref(
       prefs::kAccessibilityFocusHighlightEnabled, false,
       user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
@@ -1147,6 +1152,20 @@
   return virtual_keyboard().IsEnterpriseIconVisible();
 }
 
+void AccessibilityControllerImpl::ShowFloatingMenuIfEnabled() {
+  if (floating_menu().enabled()) {
+    DCHECK(!floating_menu_controller_);
+    floating_menu_controller_ =
+        std::make_unique<FloatingAccessibilityController>();
+    floating_menu_controller_->Show(GetFloatingMenuPosition());
+  }
+}
+
+FloatingAccessibilityController*
+AccessibilityControllerImpl::GetFloatingMenuControllerForTesting() {
+  return floating_menu_controller_.get();
+}
+
 void AccessibilityControllerImpl::SetTabletModeShelfNavigationButtonsEnabled(
     bool enabled) {
   if (!active_user_prefs_)
@@ -1388,6 +1407,11 @@
           &AccessibilityControllerImpl::UpdateAutoclickMenuPositionFromPref,
           base::Unretained(this)));
   pref_change_registrar_->Add(
+      prefs::kAccessibilityFloatingMenuPosition,
+      base::BindRepeating(
+          &AccessibilityControllerImpl::UpdateFloatingMenuPositionFromPref,
+          base::Unretained(this)));
+  pref_change_registrar_->Add(
       prefs::kAccessibilityLargeCursorDipSize,
       base::BindRepeating(
           &AccessibilityControllerImpl::UpdateLargeCursorFromPref,
@@ -1445,6 +1469,7 @@
   UpdateAutoclickStabilizePositionFromPref();
   UpdateAutoclickMovementThresholdFromPref();
   UpdateAutoclickMenuPositionFromPref();
+  UpdateFloatingMenuPositionFromPref();
   UpdateLargeCursorFromPref();
   UpdateShortcutsEnabledFromPref();
   UpdateTabletModeShelfNavigationButtonsFromPref();
@@ -1547,6 +1572,26 @@
       bounds_in_screen);
 }
 
+void AccessibilityControllerImpl::SetFloatingMenuPosition(
+    FloatingMenuPosition position) {
+  if (!active_user_prefs_)
+    return;
+  active_user_prefs_->SetInteger(prefs::kAccessibilityFloatingMenuPosition,
+                                 static_cast<int>(position));
+  active_user_prefs_->CommitPendingWrite();
+}
+
+void AccessibilityControllerImpl::UpdateFloatingMenuPositionFromPref() {
+  if (floating_menu_controller_)
+    floating_menu_controller_->SetMenuPosition(GetFloatingMenuPosition());
+}
+
+FloatingMenuPosition AccessibilityControllerImpl::GetFloatingMenuPosition() {
+  DCHECK(active_user_prefs_);
+  return static_cast<FloatingMenuPosition>(active_user_prefs_->GetInteger(
+      prefs::kAccessibilityFloatingMenuPosition));
+}
+
 void AccessibilityControllerImpl::UpdateLargeCursorFromPref() {
   DCHECK(active_user_prefs_);
   const bool enabled =
diff --git a/ash/accessibility/accessibility_controller_impl.h b/ash/accessibility/accessibility_controller_impl.h
index 9e3c17f..9a9c34f 100644
--- a/ash/accessibility/accessibility_controller_impl.h
+++ b/ash/accessibility/accessibility_controller_impl.h
@@ -36,6 +36,7 @@
 
 class AccessibilityHighlightController;
 class AccessibilityObserver;
+class FloatingAccessibilityController;
 class ScopedBacklightsForcedOff;
 class SelectToSpeakEventHandler;
 class SwitchAccessMenuBubbleController;
@@ -58,8 +59,8 @@
     kCaretHighlight,
     KCursorHighlight,
     kDictation,
-    kFocusHighlight,
     kFloatingMenu,
+    kFocusHighlight,
     kFullscreenMagnifier,
     kDockedMagnifier,
     kHighContrast,
@@ -167,9 +168,9 @@
   Feature& caret_highlight() const;
   Feature& cursor_highlight() const;
   FeatureWithDialog& dictation() const;
+  Feature& floating_menu() const;
   Feature& focus_highlight() const;
   FeatureWithDialog& fullscreen_magnifier() const;
-  Feature& floating_menu() const;
   FeatureWithDialog& docked_magnifier() const;
   FeatureWithDialog& high_contrast() const;
   Feature& large_cursor() const;
@@ -205,6 +206,10 @@
   FloatingMenuPosition GetAutoclickMenuPosition();
   void RequestAutoclickScrollableBoundsForPoint(gfx::Point& point_in_screen);
 
+  void SetFloatingMenuPosition(FloatingMenuPosition position);
+  FloatingMenuPosition GetFloatingMenuPosition();
+  FloatingAccessibilityController* GetFloatingMenuControllerForTesting();
+
   // Update the autoclick menu bounds if necessary. This may need to happen when
   // the display work area changes, or if system ui regions change (like the
   // virtual keyboard position).
@@ -289,6 +294,8 @@
     return tablet_mode_shelf_navigation_buttons_enabled_;
   }
 
+  void ShowFloatingMenuIfEnabled() override;
+
   bool dictation_active() const { return dictation_active_; }
 
   // Returns true if accessibility shortcuts have been disabled.
@@ -417,6 +424,7 @@
   void UpdateAutoclickStabilizePositionFromPref();
   void UpdateAutoclickMovementThresholdFromPref();
   void UpdateAutoclickMenuPositionFromPref();
+  void UpdateFloatingMenuPositionFromPref();
   void UpdateLargeCursorFromPref();
   void UpdateSwitchAccessKeyCodesFromPref(SwitchAccessCommand command);
   void UpdateSwitchAccessAutoScanEnabledFromPref();
@@ -461,6 +469,9 @@
   std::unique_ptr<AccessibilityHighlightController>
       accessibility_highlight_controller_;
 
+  // Used to display accessibility floating menu.
+  std::unique_ptr<FloatingAccessibilityController> floating_menu_controller_;
+
   // Used to force the backlights off to darken the screen.
   std::unique_ptr<ScopedBacklightsForcedOff> scoped_backlights_forced_off_;
 
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 609750a..648ccafc 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -1862,9 +1862,6 @@
       <message name="IDS_ASH_PIN_KEYBOARD_DELETE_ACCESSIBLE_NAME" desc="Text to be spoken when the focus is set to the delete button of the PIN keyboard.">
         Delete
       </message>
-      <message name="IDS_ASH_LOGIN_MANAGED_DEVICE_INDICATOR" desc="Template for text shown as a bottom status on the login screen, informing the user that this device is managed.">
-        <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> managed by <ph name="DOMAIN">$2<ex>yourdomain.com</ex></ph>
-      </message>
       <message name="IDS_ASH_LOGIN_POD_OWNER_USER" desc="Login/lock screen user pod menu title for a user who owns the device.">
         <ph name="USER_NAME">$1<ex>Ivan Arbuzov</ex></ph> (owner)
       </message>
diff --git a/ash/ash_strings_grd/IDS_ASH_LOGIN_MANAGED_DEVICE_INDICATOR.png.sha1 b/ash/ash_strings_grd/IDS_ASH_LOGIN_MANAGED_DEVICE_INDICATOR.png.sha1
deleted file mode 100644
index 5e287ad..0000000
--- a/ash/ash_strings_grd/IDS_ASH_LOGIN_MANAGED_DEVICE_INDICATOR.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-c65621e3e10bd49f7ac4356d7c3dc5763d542be8
\ No newline at end of file
diff --git a/ash/login/ui/bottom_status_indicator.h b/ash/login/ui/bottom_status_indicator.h
index 24cd08b..55cc007a 100644
--- a/ash/login/ui/bottom_status_indicator.h
+++ b/ash/login/ui/bottom_status_indicator.h
@@ -24,7 +24,6 @@
  public:
   enum class ContentType {
     kNone,
-    kManagedDevice,
     kAdbSideLoadingEnabled,
   };
 
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc
index 35a13f2..12c28c4f 100644
--- a/ash/login/ui/lock_contents_view.cc
+++ b/ash/login/ui/lock_contents_view.cc
@@ -38,8 +38,6 @@
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
-#include "ash/system/model/enterprise_domain_model.h"
-#include "ash/system/model/system_tray_model.h"
 #include "ash/system/power/power_button_controller.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/status_area_widget_delegate.h"
@@ -60,7 +58,6 @@
 #include "ui/chromeos/devicetype_utils.h"
 #include "ui/display/display.h"
 #include "ui/display/manager/display_manager.h"
-#include "ui/display/manager/managed_display_info.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/rect.h"
@@ -507,13 +504,6 @@
       std::move(bottom_status_indicator_layout));
   AddChildView(bottom_status_indicator_);
 
-  std::string entreprise_domain_name = Shell::Get()
-                                           ->system_tray_model()
-                                           ->enterprise_domain()
-                                           ->enterprise_display_domain();
-  if (!entreprise_domain_name.empty())
-    ShowEntrepriseDomainName(entreprise_domain_name);
-
   note_action_ = new NoteActionLaunchButton(initial_note_action_state);
   top_header_->AddChildView(note_action_);
 
@@ -642,21 +632,6 @@
   }
 }
 
-void LockContentsView::ShowEntrepriseDomainName(
-    const std::string& entreprise_domain_name) {
-  bottom_status_indicator_->SetIcon(
-      kLoginScreenEnterpriseIcon,
-      AshColorProvider::ContentLayerType::kIconPrimary);
-  bottom_status_indicator_->SetText(
-      l10n_util::GetStringFUTF16(IDS_ASH_LOGIN_MANAGED_DEVICE_INDICATOR,
-                                 ui::GetChromeOSDeviceName(),
-                                 base::UTF8ToUTF16(entreprise_domain_name)),
-      gfx::kGoogleGrey200);
-  bottom_status_indicator_->set_content_type(
-      BottomStatusIndicator::ContentType::kManagedDevice);
-  UpdateBottomStatusIndicatorVisibility();
-}
-
 void LockContentsView::ShowAdbEnabled() {
   bottom_status_indicator_->SetIcon(
       kLockScreenAlertIcon, AshColorProvider::ContentLayerType::kIconRed);
@@ -2146,12 +2121,8 @@
 }
 
 void LockContentsView::UpdateBottomStatusIndicatorVisibility() {
-  bool visible =
-      bottom_status_indicator_->content_type() ==
-          BottomStatusIndicator::ContentType::kAdbSideLoadingEnabled ||
-      (bottom_status_indicator_->content_type() ==
-           BottomStatusIndicator::ContentType::kManagedDevice &&
-       !extension_ui_visible_);
+  bool visible = bottom_status_indicator_->content_type() ==
+                 BottomStatusIndicator::ContentType::kAdbSideLoadingEnabled;
   bottom_status_indicator_->SetVisible(visible);
 }
 
diff --git a/ash/login/ui/lock_contents_view.h b/ash/login/ui/lock_contents_view.h
index 165053c..a43a6c1 100644
--- a/ash/login/ui/lock_contents_view.h
+++ b/ash/login/ui/lock_contents_view.h
@@ -139,7 +139,6 @@
 
   void FocusNextUser();
   void FocusPreviousUser();
-  void ShowEntrepriseDomainName(const std::string& entreprise_domain_name);
   void ShowAdbEnabled();
   void ShowSystemInfo();
   void ShowParentAccessDialog();
@@ -285,8 +284,7 @@
   void LayoutTopHeader();
 
   // Lay out the bottom status indicator. This is called when system information
-  // is shown if ADB is enabled and at the initialization of lock screen if the
-  // device is enrolled.
+  // is shown if ADB is enabled.
   void LayoutBottomStatusIndicator();
 
   // Lay out the expanded public session view.
@@ -443,7 +441,7 @@
   // Bubble for displaying supervised user deprecation message.
   LoginErrorBubble* supervised_user_deprecation_bubble_;
 
-  // Bottom status indicator displaying entreprise domain or ADB enabled alert
+  // Bottom status indicator displaying ADB enabled alert.
   BottomStatusIndicator* bottom_status_indicator_;
 
   // Tracks the visibility of the extension Ui window.
diff --git a/ash/login/ui/lock_contents_view_unittest.cc b/ash/login/ui/lock_contents_view_unittest.cc
index 28cff72..b81ee27 100644
--- a/ash/login/ui/lock_contents_view_unittest.cc
+++ b/ash/login/ui/lock_contents_view_unittest.cc
@@ -39,7 +39,6 @@
 #include "ash/shelf/shelf_navigation_widget.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
-#include "ash/system/model/system_tray_model.h"
 #include "ash/system/power/backlights_forced_off_setter.h"
 #include "ash/system/power/power_button_controller.h"
 #include "ash/system/status_area_widget.h"
@@ -716,8 +715,8 @@
                 test_api.system_info()->GetBoundsInScreen().right(),
             note_action_size.width());
 
-  // Verify that bottom status indicator is invisible if neither adb sideloading
-  // is enabled nor the device is enrolled.
+  // Verify that warning indicator is invisible if ADB sideloading is not
+  // enabled.
   EXPECT_FALSE(test_api.bottom_status_indicator()->GetVisible());
 }
 
@@ -819,31 +818,6 @@
   EXPECT_TRUE(test_api.bottom_status_indicator()->GetVisible());
 }
 
-// Show bottom status indicator if device is enrolled
-TEST_F(LockContentsViewUnitTest, ShowStatusIndicatorIfEnrolledDevice) {
-  // If the device is enrolled, bottom_status_indicator should be visible.
-  Shell::Get()->system_tray_model()->SetEnterpriseDisplayDomain(
-      "BestCompanyEver", false);
-
-  auto* contents = new LockContentsView(
-      mojom::TrayActionState::kAvailable, LockScreen::ScreenType::kLock,
-      DataDispatcher(),
-      std::make_unique<FakeLoginDetachableBaseModel>(DataDispatcher()));
-  SetUserCount(1);
-
-  std::unique_ptr<views::Widget> widget = CreateWidgetWithContent(contents);
-  LockContentsView::TestApi test_api(contents);
-
-  EXPECT_TRUE(test_api.bottom_status_indicator()->GetVisible());
-
-  // bottom_status_indicator should not be visible when displaying enterprise
-  // domain and extension UI is visible.
-  DataDispatcher()->NotifyOobeDialogState(OobeDialogState::EXTENSION_LOGIN);
-  EXPECT_FALSE(test_api.bottom_status_indicator()->GetVisible());
-  DataDispatcher()->NotifyOobeDialogState(OobeDialogState::HIDDEN);
-  EXPECT_TRUE(test_api.bottom_status_indicator()->GetVisible());
-}
-
 // Verifies the easy unlock tooltip is automatically displayed when requested.
 TEST_F(LockContentsViewUnitTest, EasyUnlockForceTooltipCreatesTooltipWidget) {
   auto* lock = new LockContentsView(
diff --git a/ash/public/cpp/accessibility_controller.h b/ash/public/cpp/accessibility_controller.h
index 0f062a70..3f04151a 100644
--- a/ash/public/cpp/accessibility_controller.h
+++ b/ash/public/cpp/accessibility_controller.h
@@ -108,6 +108,9 @@
   // Disables restoring of recommended policy values.
   virtual void DisablePolicyRecommendationRestorerForTesting() {}
 
+  // Shows floating accessibility menu if it was enabled by policy.
+  virtual void ShowFloatingMenuIfEnabled() {}
+
  protected:
   AccessibilityController();
   virtual ~AccessibilityController();
diff --git a/ash/public/cpp/accessibility_controller_enums.h b/ash/public/cpp/accessibility_controller_enums.h
index f3c21f0..e8f58ef 100644
--- a/ash/public/cpp/accessibility_controller_enums.h
+++ b/ash/public/cpp/accessibility_controller_enums.h
@@ -122,9 +122,9 @@
   kMaxValue = kScroll
 };
 
-// Display location of the on-screen floating menus used by accessibility features(e.g. the
-// Automatic Clicks) . These values are written to prefs so they should not be changed. New values
-// should be added at the end.
+// Display location of the on-screen floating menus used by accessibility
+// features(e.g. the Automatic Clicks) . These values are written to prefs so
+// they should not be changed. New values should be added at the end.
 enum class FloatingMenuPosition {
   // The bottom right of the screen.
   kBottomRight,
diff --git a/ash/public/cpp/ash_constants.h b/ash/public/cpp/ash_constants.h
index f6a9fde..9e71e3c 100644
--- a/ash/public/cpp/ash_constants.h
+++ b/ash/public/cpp/ash_constants.h
@@ -60,6 +60,10 @@
 constexpr FloatingMenuPosition kDefaultAutoclickMenuPosition =
     FloatingMenuPosition::kSystemDefault;
 
+// The default floating accessibility menu position.
+constexpr FloatingMenuPosition kDefaultFloatingMenuPosition =
+    FloatingMenuPosition::kSystemDefault;
+
 // The default frame color.
 constexpr SkColor kDefaultFrameColor = SkColorSetRGB(0xFD, 0xFE, 0xFF);
 
diff --git a/ash/public/cpp/ash_pref_names.cc b/ash/public/cpp/ash_pref_names.cc
index 047297ea..9bee26a 100644
--- a/ash/public/cpp/ash_pref_names.cc
+++ b/ash/public/cpp/ash_pref_names.cc
@@ -80,6 +80,9 @@
 // A boolean pref which determines whether floating accessibility menu is
 // enabled.
 const char kAccessibilityFloatingMenuEnabled[] = "settings.a11y.floating_menu";
+// Floating a11y menu position, a FloatingMenuPosition;
+const char kAccessibilityFloatingMenuPosition[] =
+    "settings.a11y.floating_menu_position";
 // A boolean pref which determines whether focus highlighting is enabled.
 const char kAccessibilityFocusHighlightEnabled[] =
     "settings.a11y.focus_highlight";
diff --git a/ash/public/cpp/ash_pref_names.h b/ash/public/cpp/ash_pref_names.h
index b0d8c1054..4a2b3ad 100644
--- a/ash/public/cpp/ash_pref_names.h
+++ b/ash/public/cpp/ash_pref_names.h
@@ -32,6 +32,7 @@
 ASH_PUBLIC_EXPORT extern const char kAccessibilityCaretHighlightEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilityCursorHighlightEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilityFloatingMenuEnabled[];
+ASH_PUBLIC_EXPORT extern const char kAccessibilityFloatingMenuPosition[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilityFocusHighlightEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilitySelectToSpeakEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilitySwitchAccessEnabled[];
diff --git a/ash/system/accessibility/floating_accessibility_controller.cc b/ash/system/accessibility/floating_accessibility_controller.cc
new file mode 100644
index 0000000..2571ec4
--- /dev/null
+++ b/ash/system/accessibility/floating_accessibility_controller.cc
@@ -0,0 +1,187 @@
+// 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/system/accessibility/floating_accessibility_controller.h"
+
+#include "ash/public/cpp/shell_window_ids.h"
+#include "ash/session/session_controller_impl.h"
+#include "ash/shell.h"
+#include "ash/system/tray/tray_background_view.h"
+#include "ash/system/tray/tray_constants.h"
+#include "ash/wm/collision_detection/collision_detection_utils.h"
+#include "ash/wm/work_area_insets.h"
+#include "base/logging.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+
+namespace ash {
+
+namespace {
+
+constexpr int kFloatingMenuHeight = 64;
+constexpr base::TimeDelta kAnimationDuration =
+    base::TimeDelta::FromMilliseconds(150);
+
+FloatingMenuPosition DefaultSystemPosition() {
+  return base::i18n::IsRTL() ? FloatingMenuPosition::kBottomLeft
+                             : FloatingMenuPosition::kBottomRight;
+}
+
+}  // namespace
+
+FloatingAccessibilityController::FloatingAccessibilityController() {
+  Shell::Get()->locale_update_controller()->AddObserver(this);
+}
+FloatingAccessibilityController::~FloatingAccessibilityController() {
+  Shell::Get()->locale_update_controller()->RemoveObserver(this);
+  if (bubble_widget_ && !bubble_widget_->IsClosed())
+    bubble_widget_->CloseNow();
+}
+
+void FloatingAccessibilityController::Show(FloatingMenuPosition position) {
+  // Kiosk check.
+  if (!Shell::Get()->session_controller()->IsRunningInAppMode()) {
+    NOTREACHED()
+        << "Floating accessibility menu can only be run in a kiosk session.";
+    return;
+  }
+
+  DCHECK(!bubble_view_);
+
+  position_ = position;
+  TrayBubbleView::InitParams init_params;
+  init_params.delegate = this;
+  // We need our view to be on the same level as the autoclicks menu, so neither
+  // of them is overlapping each other.
+  init_params.parent_window = Shell::GetContainer(
+      Shell::GetPrimaryRootWindow(), kShellWindowId_AutoclickContainer);
+  init_params.anchor_mode = TrayBubbleView::AnchorMode::kRect;
+  // The widget's shadow is drawn below and on the sides of the view, with a
+  // width of kCollisionWindowWorkAreaInsetsDp. Set the top inset to 0 to ensure
+  // the scroll view is drawn at kCollisionWindowWorkAreaInsetsDp above the
+  // bubble menu when the position is at the bottom of the screen. The space
+  // between the bubbles belongs to the scroll view bubble's shadow.
+  init_params.insets = gfx::Insets(0, kCollisionWindowWorkAreaInsetsDp,
+                                   kCollisionWindowWorkAreaInsetsDp,
+                                   kCollisionWindowWorkAreaInsetsDp);
+  init_params.max_height = kFloatingMenuHeight;
+  init_params.corner_radius = kUnifiedTrayCornerRadius;
+  init_params.has_shadow = false;
+  init_params.translucent = true;
+  bubble_view_ = new FloatingAccessibilityBubbleView(init_params);
+
+  menu_view_ = new FloatingAccessibilityView(this);
+  menu_view_->SetBorder(
+      views::CreateEmptyBorder(kUnifiedTopShortcutSpacing, 0, 0, 0));
+  bubble_view_->AddChildView(menu_view_);
+
+  menu_view_->SetPaintToLayer();
+  menu_view_->layer()->SetFillsBoundsOpaquely(false);
+
+  bubble_widget_ = views::BubbleDialogDelegateView::CreateBubble(bubble_view_);
+  TrayBackgroundView::InitializeBubbleAnimations(bubble_widget_);
+  bubble_view_->InitializeAndShowBubble();
+
+  SetMenuPosition(position_);
+}
+
+void FloatingAccessibilityController::SetMenuPosition(
+    FloatingMenuPosition new_position) {
+  if (!menu_view_ || !bubble_view_ || !bubble_widget_)
+    return;
+
+  // Update the menu view's UX if the position has changed, or if it's not the
+  // default position (because that can change with language direction).
+  if (position_ != new_position ||
+      new_position == FloatingMenuPosition::kSystemDefault) {
+    menu_view_->SetMenuPosition(new_position);
+  }
+  position_ = new_position;
+
+  // If this is the default system position, pick the position based on the
+  // language direction.
+  if (new_position == FloatingMenuPosition::kSystemDefault)
+    new_position = DefaultSystemPosition();
+
+  // Calculates the ideal bounds.
+  // TODO(katie): Support multiple displays: draw the menu on whichever display
+  // the cursor is on.
+  aura::Window* window = Shell::GetPrimaryRootWindow();
+  gfx::Rect work_area =
+      WorkAreaInsets::ForWindow(window)->user_work_area_bounds();
+  gfx::Rect new_bounds;
+
+  gfx::Size preferred_size = menu_view_->GetPreferredSize();
+  switch (new_position) {
+    case FloatingMenuPosition::kBottomRight:
+      new_bounds = gfx::Rect(work_area.right() - preferred_size.width(),
+                             work_area.bottom() - preferred_size.height(),
+                             preferred_size.width(), preferred_size.height());
+      break;
+    case FloatingMenuPosition::kBottomLeft:
+      new_bounds =
+          gfx::Rect(work_area.x(), work_area.bottom() - preferred_size.height(),
+                    preferred_size.width(), preferred_size.height());
+      break;
+    case FloatingMenuPosition::kTopLeft:
+      // Because there is no inset at the top of the widget, add
+      // 2 * kCollisionWindowWorkAreaInsetsDp to the top of the work area.
+      // to ensure correct padding.
+      new_bounds = gfx::Rect(
+          work_area.x(), work_area.y() + 2 * kCollisionWindowWorkAreaInsetsDp,
+          preferred_size.width(), preferred_size.height());
+      break;
+    case FloatingMenuPosition::kTopRight:
+      // Because there is no inset at the top of the widget, add
+      // 2 * kCollisionWindowWorkAreaInsetsDp to the top of the work area.
+      // to ensure correct padding.
+      new_bounds =
+          gfx::Rect(work_area.right() - preferred_size.width(),
+                    work_area.y() + 2 * kCollisionWindowWorkAreaInsetsDp,
+                    preferred_size.width(), preferred_size.height());
+      break;
+    case FloatingMenuPosition::kSystemDefault:
+      return;
+  }
+
+  gfx::Rect resting_bounds =
+      CollisionDetectionUtils::AdjustToFitMovementAreaByGravity(
+          display::Screen::GetScreen()->GetDisplayNearestWindow(
+              bubble_widget_->GetNativeWindow()),
+          new_bounds);
+  // Un-inset the bounds to get the widget's bounds, which includes the drop
+  // shadow.
+  resting_bounds.Inset(-kCollisionWindowWorkAreaInsetsDp, 0,
+                       -kCollisionWindowWorkAreaInsetsDp,
+                       -kCollisionWindowWorkAreaInsetsDp);
+  if (bubble_widget_->GetWindowBoundsInScreen() == resting_bounds)
+    return;
+
+  ui::ScopedLayerAnimationSettings settings(
+      bubble_widget_->GetLayer()->GetAnimator());
+  settings.SetPreemptionStrategy(
+      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+  settings.SetTransitionDuration(kAnimationDuration);
+  settings.SetTweenType(gfx::Tween::EASE_OUT);
+  bubble_widget_->SetBounds(resting_bounds);
+}
+
+void FloatingAccessibilityController::OnDetailedMenuEnabled(bool enabled) {
+  // TODO(crbug.com/1061068): Implement detailed menu view logic.
+  detailed_view_shown_ = enabled;
+}
+
+void FloatingAccessibilityController::BubbleViewDestroyed() {
+  bubble_view_ = nullptr;
+  bubble_widget_ = nullptr;
+  menu_view_ = nullptr;
+}
+
+void FloatingAccessibilityController::OnLocaleChanged() {
+  // Layout update is needed when language changes between LTR and RTL, if the
+  // position is the system default.
+  if (position_ == FloatingMenuPosition::kSystemDefault)
+    SetMenuPosition(position_);
+}
+
+}  // namespace ash
diff --git a/ash/system/accessibility/floating_accessibility_controller.h b/ash/system/accessibility/floating_accessibility_controller.h
new file mode 100644
index 0000000..28686dd
--- /dev/null
+++ b/ash/system/accessibility/floating_accessibility_controller.h
@@ -0,0 +1,54 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_SYSTEM_ACCESSIBILITY_FLOATING_ACCESSIBILITY_CONTROLLER_H_
+#define ASH_SYSTEM_ACCESSIBILITY_FLOATING_ACCESSIBILITY_CONTROLLER_H_
+
+#include "ash/public/cpp/accessibility_controller_enums.h"
+#include "ash/public/cpp/ash_constants.h"
+#include "ash/system/accessibility/floating_accessibility_view.h"
+#include "ash/system/locale/locale_update_controller_impl.h"
+
+namespace ash {
+
+class FloatingAccessibilityView;
+
+// Controls the floating accessibility menu.
+class FloatingAccessibilityController
+    : public FloatingAccessibilityView::Delegate,
+      public TrayBubbleView::Delegate,
+      public LocaleChangeObserver {
+ public:
+  FloatingAccessibilityController();
+  FloatingAccessibilityController(const FloatingAccessibilityController&) =
+      delete;
+  FloatingAccessibilityController& operator=(
+      const FloatingAccessibilityController&) = delete;
+  ~FloatingAccessibilityController() override;
+
+  // Starts showing the floating menu when called.
+  void Show(FloatingMenuPosition position);
+  void SetMenuPosition(FloatingMenuPosition new_position);
+
+ private:
+  friend class FloatingAccessibilityControllerTest;
+  // FloatingAccessibilityView::Delegate:
+  void OnDetailedMenuEnabled(bool enabled) override;
+  // TrayBubbleView::Delegate:
+  void BubbleViewDestroyed() override;
+  // LocaleChangeObserver:
+  void OnLocaleChanged() override;
+
+  FloatingAccessibilityView* menu_view_ = nullptr;
+  FloatingAccessibilityBubbleView* bubble_view_ = nullptr;
+  views::Widget* bubble_widget_ = nullptr;
+
+  bool detailed_view_shown_ = false;
+
+  FloatingMenuPosition position_ = kDefaultFloatingMenuPosition;
+};
+
+}  // namespace ash
+
+#endif  // ASH_SYSTEM_ACCESSIBILITY_FLOATING_ACCESSIBILITY_CONTROLLER_H_
diff --git a/ash/system/accessibility/floating_accessibility_controller_unittest.cc b/ash/system/accessibility/floating_accessibility_controller_unittest.cc
new file mode 100644
index 0000000..f45e8059
--- /dev/null
+++ b/ash/system/accessibility/floating_accessibility_controller_unittest.cc
@@ -0,0 +1,179 @@
+// 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/system/accessibility/floating_accessibility_controller.h"
+
+#include "ash/accessibility/accessibility_controller_impl.h"
+#include "ash/public/cpp/session/session_types.h"
+#include "ash/session/session_controller_impl.h"
+#include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
+
+namespace ash {
+
+namespace {
+
+// A buffer for checking whether the menu view is near this region of the
+// screen. This buffer allows for things like padding and the shelf size,
+// but is still smaller than half the screen size, so that we can check the
+// general corner in which the menu is displayed.
+const int kMenuViewBoundsBuffer = 100;
+
+ui::GestureEvent CreateTapEvent() {
+  return ui::GestureEvent(0, 0, 0, base::TimeTicks(),
+                          ui::GestureEventDetails(ui::ET_GESTURE_TAP));
+}
+
+}  // namespace
+class FloatingAccessibilityControllerTest : public AshTestBase {
+ public:
+  AccessibilityControllerImpl* accessibility_controller() {
+    return Shell::Get()->accessibility_controller();
+  }
+
+  FloatingAccessibilityController* controller() {
+    return accessibility_controller()->GetFloatingMenuControllerForTesting();
+  }
+
+  FloatingMenuPosition menu_position() { return controller()->position_; }
+
+  FloatingAccessibilityView* menu_view() {
+    return controller() ? controller()->menu_view_ : nullptr;
+  }
+
+  bool detailed_view_shown() { return controller()->detailed_view_shown_; }
+
+  views::View* GetMenuButton(FloatingAccessibilityView::ButtonId button_id) {
+    FloatingAccessibilityView* view = menu_view();
+    if (!view)
+      return nullptr;
+    return view->GetViewByID(static_cast<int>(button_id));
+  }
+
+  void SetUpKioskSession() {
+    SessionInfo info;
+    info.is_running_in_app_mode = true;
+    Shell::Get()->session_controller()->SetSessionInfo(info);
+  }
+
+  gfx::Rect GetMenuViewBounds() {
+    FloatingAccessibilityView* view = menu_view();
+    return view ? view->GetBoundsInScreen()
+                : gfx::Rect(-kMenuViewBoundsBuffer, -kMenuViewBoundsBuffer);
+  }
+
+  void Show() { accessibility_controller()->ShowFloatingMenuIfEnabled(); }
+
+  void SetUpVisibleMenu() {
+    SetUpKioskSession();
+    accessibility_controller()->floating_menu().SetEnabled(true);
+    accessibility_controller()->ShowFloatingMenuIfEnabled();
+  }
+};
+
+TEST_F(FloatingAccessibilityControllerTest, MenuIsNotShownWhenNotEnabled) {
+  accessibility_controller()->ShowFloatingMenuIfEnabled();
+  EXPECT_EQ(controller(), nullptr);
+}
+
+TEST_F(FloatingAccessibilityControllerTest, ShowingMenu) {
+  SetUpKioskSession();
+  accessibility_controller()->floating_menu().SetEnabled(true);
+  accessibility_controller()->ShowFloatingMenuIfEnabled();
+
+  EXPECT_TRUE(controller());
+  EXPECT_EQ(menu_position(),
+            accessibility_controller()->GetFloatingMenuPosition());
+}
+
+TEST_F(FloatingAccessibilityControllerTest, CanChangePosition) {
+  SetUpVisibleMenu();
+
+  accessibility_controller()->SetFloatingMenuPosition(
+      FloatingMenuPosition::kTopRight);
+
+  // Get the full root window bounds to test the position.
+  gfx::Rect window_bounds = Shell::GetPrimaryRootWindow()->bounds();
+
+  // Test cases rotate clockwise.
+  const struct {
+    gfx::Point expected_location;
+    FloatingMenuPosition expected_position;
+  } kTestCases[] = {
+      {gfx::Point(window_bounds.width(), window_bounds.height()),
+       FloatingMenuPosition::kBottomRight},
+      {gfx::Point(0, window_bounds.height()),
+       FloatingMenuPosition::kBottomLeft},
+      {gfx::Point(0, 0), FloatingMenuPosition::kTopLeft},
+      {gfx::Point(window_bounds.width(), 0), FloatingMenuPosition::kTopRight},
+  };
+
+  // Find the autoclick menu position button.
+  views::View* button =
+      GetMenuButton(FloatingAccessibilityView::ButtonId::kPosition);
+  ASSERT_TRUE(button) << "No position button found.";
+
+  // Loop through all positions twice.
+  for (int i = 0; i < 2; i++) {
+    for (const auto& test : kTestCases) {
+      SCOPED_TRACE(
+          base::StringPrintf("Testing position #[%d]", test.expected_position));
+      // Tap the position button.
+      ui::GestureEvent event = CreateTapEvent();
+      button->OnGestureEvent(&event);
+
+      // Pref change happened.
+      EXPECT_EQ(test.expected_position, menu_position());
+
+      // Menu is in generally the correct screen location.
+      EXPECT_LT(
+          GetMenuViewBounds().ManhattanDistanceToPoint(test.expected_location),
+          kMenuViewBoundsBuffer);
+    }
+  }
+}
+
+TEST_F(FloatingAccessibilityControllerTest, DetailedViewToggle) {
+  SetUpVisibleMenu();
+
+  // Find the autoclick menu position button.
+  views::View* button =
+      GetMenuButton(FloatingAccessibilityView::ButtonId::kSettingsList);
+  ASSERT_TRUE(button) << "No accessibility features list button found.";
+  EXPECT_FALSE(detailed_view_shown());
+
+  ui::GestureEvent event = CreateTapEvent();
+  button->OnGestureEvent(&event);
+  EXPECT_TRUE(detailed_view_shown());
+
+  event = CreateTapEvent();
+  button->OnGestureEvent(&event);
+  EXPECT_FALSE(detailed_view_shown());
+}
+
+TEST_F(FloatingAccessibilityControllerTest, LocaleChangeObserver) {
+  SetUpVisibleMenu();
+  gfx::Rect window_bounds = Shell::GetPrimaryRootWindow()->bounds();
+
+  // RTL should position the menu on the bottom left.
+  base::i18n::SetICUDefaultLocale("he");
+  // Trigger the LocaleChangeObserver, which should cause a layout of the menu.
+  ash::LocaleUpdateController::Get()->OnLocaleChanged(
+      "en", "en", "he", base::DoNothing::Once<ash::LocaleNotificationResult>());
+  EXPECT_TRUE(base::i18n::IsRTL());
+  EXPECT_LT(
+      GetMenuViewBounds().ManhattanDistanceToPoint(window_bounds.bottom_left()),
+      kMenuViewBoundsBuffer);
+
+  // LTR should position the menu on the bottom right.
+  base::i18n::SetICUDefaultLocale("en");
+  ash::LocaleUpdateController::Get()->OnLocaleChanged(
+      "he", "he", "en", base::DoNothing::Once<ash::LocaleNotificationResult>());
+  EXPECT_FALSE(base::i18n::IsRTL());
+  EXPECT_LT(GetMenuViewBounds().ManhattanDistanceToPoint(
+                window_bounds.bottom_right()),
+            kMenuViewBoundsBuffer);
+}
+
+}  // namespace ash
diff --git a/ash/system/accessibility/floating_accessibility_view.cc b/ash/system/accessibility/floating_accessibility_view.cc
new file mode 100644
index 0000000..13025b5
--- /dev/null
+++ b/ash/system/accessibility/floating_accessibility_view.cc
@@ -0,0 +1,165 @@
+// 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/system/accessibility/floating_accessibility_view.h"
+
+#include "ash/accessibility/accessibility_controller_impl.h"
+#include "ash/keyboard/ui/keyboard_ui_controller.h"
+#include "ash/public/cpp/system_tray.h"
+#include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/root_window_controller.h"
+#include "ash/shelf/shelf.h"
+#include "ash/shell.h"
+#include "ash/strings/grit/ash_strings.h"
+#include "ash/style/ash_color_provider.h"
+#include "ash/system/accessibility/floating_menu_button.h"
+#include "ash/system/tray/tray_constants.h"
+#include "ui/views/controls/separator.h"
+#include "ui/views/layout/box_layout.h"
+
+namespace ash {
+
+namespace {
+
+constexpr int kPanelPositionButtonPadding = 16;
+constexpr int kPanelPositionButtonSize = 36;
+constexpr int kSeparatorHeight = 16;
+
+std::unique_ptr<views::Separator> CreateSeparator() {
+  auto separator = std::make_unique<views::Separator>();
+  separator->SetColor(AshColorProvider::Get()->GetContentLayerColor(
+      AshColorProvider::ContentLayerType::kSeparator,
+      AshColorProvider::AshColorMode::kDark));
+  separator->SetPreferredHeight(kSeparatorHeight);
+  int total_height = kUnifiedTopShortcutSpacing * 2 + kTrayItemSize;
+  int separator_spacing = (total_height - kSeparatorHeight) / 2;
+  separator->SetBorder(views::CreateEmptyBorder(
+      separator_spacing - kUnifiedTopShortcutSpacing, 0, separator_spacing, 0));
+  return separator;
+}
+
+std::unique_ptr<views::View> CreateButtonRowContainer() {
+  auto button_container = std::make_unique<views::View>();
+  button_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kHorizontal,
+      gfx::Insets(0, kPanelPositionButtonPadding, kPanelPositionButtonPadding,
+                  kPanelPositionButtonPadding),
+      kPanelPositionButtonPadding));
+  return button_container;
+}
+
+}  // namespace
+
+FloatingAccessibilityBubbleView::FloatingAccessibilityBubbleView(
+    const TrayBubbleView::InitParams& init_params)
+    : TrayBubbleView(init_params) {}
+
+FloatingAccessibilityBubbleView::~FloatingAccessibilityBubbleView() = default;
+
+bool FloatingAccessibilityBubbleView::IsAnchoredToStatusArea() const {
+  return false;
+}
+
+const char* FloatingAccessibilityBubbleView::GetClassName() const {
+  return "FloatingAccessibilityBubbleView";
+}
+
+FloatingAccessibilityView::FloatingAccessibilityView(Delegate* delegate)
+    : delegate_(delegate) {
+  std::unique_ptr<views::BoxLayout> layout = std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), 0);
+  SetLayoutManager(std::move(layout));
+
+  // TODO(crbug.com/1061068): Add buttons view that represents enabled features.
+
+  std::unique_ptr<views::View> tray_button_container =
+      CreateButtonRowContainer();
+  a11y_tray_button_ =
+      tray_button_container->AddChildView(std::make_unique<FloatingMenuButton>(
+          this, kUnifiedMenuAccessibilityIcon,
+          IDS_ASH_STATUS_TRAY_ACCESSIBILITY,
+          /*flip_for_rtl*/ true, kTrayItemSize));
+
+  std::unique_ptr<views::View> position_button_container =
+      CreateButtonRowContainer();
+  position_button_ = position_button_container->AddChildView(
+      std::make_unique<FloatingMenuButton>(
+          this, kAutoclickPositionBottomLeftIcon,
+          IDS_ASH_AUTOCLICK_OPTION_CHANGE_POSITION, /*flip_for_rtl*/ false,
+          kPanelPositionButtonSize, false));
+
+  AddChildView(std::move(tray_button_container));
+  AddChildView(CreateSeparator());
+  AddChildView(std::move(position_button_container));
+
+  // Set view IDs for testing.
+  position_button_->SetId(static_cast<int>(ButtonId::kPosition));
+  a11y_tray_button_->SetId(static_cast<int>(ButtonId::kSettingsList));
+}
+
+FloatingAccessibilityView::~FloatingAccessibilityView() {}
+
+void FloatingAccessibilityView::SetMenuPosition(FloatingMenuPosition position) {
+  switch (position) {
+    case FloatingMenuPosition::kBottomRight:
+      position_button_->SetVectorIcon(kAutoclickPositionBottomRightIcon);
+      return;
+    case FloatingMenuPosition::kBottomLeft:
+      position_button_->SetVectorIcon(kAutoclickPositionBottomLeftIcon);
+      return;
+    case FloatingMenuPosition::kTopLeft:
+      position_button_->SetVectorIcon(kAutoclickPositionTopLeftIcon);
+      return;
+    case FloatingMenuPosition::kTopRight:
+      position_button_->SetVectorIcon(kAutoclickPositionTopRightIcon);
+      return;
+    case FloatingMenuPosition::kSystemDefault:
+      position_button_->SetVectorIcon(base::i18n::IsRTL()
+                                          ? kAutoclickPositionBottomLeftIcon
+                                          : kAutoclickPositionBottomRightIcon);
+      return;
+  }
+}
+
+void FloatingAccessibilityView::ButtonPressed(views::Button* sender,
+                                              const ui::Event& event) {
+  if (sender == a11y_tray_button_) {
+    delegate_->OnDetailedMenuEnabled(!a11y_tray_button_->IsToggled());
+    a11y_tray_button_->SetToggled(!a11y_tray_button_->IsToggled());
+    return;
+  }
+
+  if (sender == position_button_) {
+    FloatingMenuPosition new_position;
+    // Rotate clockwise throughout the screen positions.
+    switch (
+        Shell::Get()->accessibility_controller()->GetFloatingMenuPosition()) {
+      case FloatingMenuPosition::kBottomRight:
+        new_position = FloatingMenuPosition::kBottomLeft;
+        break;
+      case FloatingMenuPosition::kBottomLeft:
+        new_position = FloatingMenuPosition::kTopLeft;
+        break;
+      case FloatingMenuPosition::kTopLeft:
+        new_position = FloatingMenuPosition::kTopRight;
+        break;
+      case FloatingMenuPosition::kTopRight:
+        new_position = FloatingMenuPosition::kBottomRight;
+        break;
+      case FloatingMenuPosition::kSystemDefault:
+        new_position = base::i18n::IsRTL() ? FloatingMenuPosition::kTopLeft
+                                           : FloatingMenuPosition::kBottomLeft;
+        break;
+    }
+    Shell::Get()->accessibility_controller()->SetFloatingMenuPosition(
+        new_position);
+  }
+  return;
+}
+
+const char* FloatingAccessibilityView::GetClassName() const {
+  return "AccessiblityFloatingView";
+}
+
+}  // namespace ash
diff --git a/ash/system/accessibility/floating_accessibility_view.h b/ash/system/accessibility/floating_accessibility_view.h
new file mode 100644
index 0000000..0041e4e
--- /dev/null
+++ b/ash/system/accessibility/floating_accessibility_view.h
@@ -0,0 +1,85 @@
+// 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 ASH_SYSTEM_ACCESSIBILITY_FLOATING_ACCESSIBILITY_VIEW_H_
+#define ASH_SYSTEM_ACCESSIBILITY_FLOATING_ACCESSIBILITY_VIEW_H_
+
+#include <vector>
+
+#include "ash/public/cpp/accessibility_controller_enums.h"
+#include "ash/shell_observer.h"
+#include "ash/system/tray/tray_bubble_view.h"
+#include "ui/views/controls/button/button.h"
+
+namespace ash {
+
+class FloatingMenuButton;
+
+class FloatingAccessibilityBubbleView : public TrayBubbleView {
+ public:
+  explicit FloatingAccessibilityBubbleView(
+      const TrayBubbleView::InitParams& init_params);
+  FloatingAccessibilityBubbleView(const FloatingAccessibilityBubbleView&) =
+      delete;
+  FloatingAccessibilityBubbleView& operator=(
+      const FloatingAccessibilityBubbleView&) = delete;
+  ~FloatingAccessibilityBubbleView() override;
+
+  // TrayBubbleView:
+  bool IsAnchoredToStatusArea() const override;
+
+  // views::View:
+  const char* GetClassName() const override;
+};
+
+// This floating view displays the currently enabled accessibility options,
+// along with buttons to configure them.
+// ---- Layout:
+// ----  ?[Dictation] ?[SelectToSpeak] ?[VirtualKeyboard]
+// ----  | [Open settings list]
+// ----  | [Change menu location]
+class FloatingAccessibilityView : public views::View,
+                                  public views::ButtonListener {
+ public:
+  // Used for testing. Starts 1 because views IDs should not be 0.
+  enum ButtonId {
+    kPosition = 1,
+    kSettingsList = 2,
+    kDictation = 3,
+    kSelectToSpeak = 4,
+    kVirtualKeyboard = 5,
+  };
+  class Delegate {
+   public:
+    // When the user click on the settings list button.
+    virtual void OnDetailedMenuEnabled(bool enabled) {}
+    virtual ~Delegate() = default;
+  };
+
+  FloatingAccessibilityView(Delegate* delegate);
+  FloatingAccessibilityView& operator=(const FloatingAccessibilityView&) =
+      delete;
+  ~FloatingAccessibilityView() override;
+  FloatingAccessibilityView(const FloatingAccessibilityView&) = delete;
+
+  void SetMenuPosition(FloatingMenuPosition position);
+
+ private:
+  // views::ButtonListener:
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
+  // views::View:
+  const char* GetClassName() const override;
+
+  // Button to list all available features.
+  FloatingMenuButton* a11y_tray_button_ = nullptr;
+  // Button to move the view around corners.
+  FloatingMenuButton* position_button_ = nullptr;
+
+  Delegate* const delegate_;
+};
+
+}  // namespace ash
+
+#endif  // ASH_SYSTEM_ACCESSIBILITY_FLOATING_ACCESSIBILITY_VIEW_H_
diff --git a/base/BUILD.gn b/base/BUILD.gn
index bb24f72..5b481711 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -195,6 +195,10 @@
     "callback_internal.h",
     "callback_list.h",
     "cancelable_callback.h",
+    "check.cc",
+    "check.h",
+    "check_op.cc",
+    "check_op.h",
     "command_line.cc",
     "command_line.h",
     "compiler_specific.h",
diff --git a/base/check.cc b/base/check.cc
new file mode 100644
index 0000000..9e5e747
--- /dev/null
+++ b/base/check.cc
@@ -0,0 +1,101 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/check.h"
+
+// check.h is a widely included header and its size has significant impact on
+// build time. Try not to raise this limit unless absolutely necessary. See
+// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
+#ifndef NACL_TC_REV
+#pragma clang max_tokens_here 17000
+#endif
+
+#include "base/logging.h"
+#include "build/build_config.h"
+
+namespace logging {
+
+CheckError CheckError::Check(const char* file,
+                             int line,
+                             const char* condition) {
+  CheckError check_error(new LogMessage(file, line, LOG_FATAL));
+  check_error.stream() << "Check failed: " << condition << ". ";
+  return check_error;
+}
+
+CheckError CheckError::CheckOp(const char* file,
+                               int line,
+                               CheckOpResult* check_op_result) {
+  CheckError check_error(new LogMessage(file, line, LOG_FATAL));
+  check_error.stream() << "Check failed: " << check_op_result->message_;
+  free(check_op_result->message_);
+  check_op_result->message_ = nullptr;
+  return check_error;
+}
+
+CheckError CheckError::DCheck(const char* file,
+                              int line,
+                              const char* condition) {
+  CheckError check_error(new LogMessage(file, line, LOG_DCHECK));
+  check_error.stream() << "Check failed: " << condition << ". ";
+  return check_error;
+}
+
+CheckError CheckError::DCheckOp(const char* file,
+                                int line,
+                                CheckOpResult* check_op_result) {
+  CheckError check_error(new LogMessage(file, line, LOG_DCHECK));
+  check_error.stream() << "Check failed: " << check_op_result->message_;
+  free(check_op_result->message_);
+  check_op_result->message_ = nullptr;
+  return check_error;
+}
+
+CheckError CheckError::PCheck(const char* file,
+                              int line,
+                              const char* condition) {
+  SystemErrorCode err_code = logging::GetLastSystemErrorCode();
+#if defined(OS_WIN)
+  CheckError check_error(
+      new Win32ErrorLogMessage(file, line, LOG_FATAL, err_code));
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+  CheckError check_error(new ErrnoLogMessage(file, line, LOG_FATAL, err_code));
+#endif
+  check_error.stream() << "Check failed: " << condition << ". ";
+  return check_error;
+}
+
+CheckError CheckError::PCheck(const char* file, int line) {
+  return PCheck(file, line, "");
+}
+
+CheckError CheckError::DPCheck(const char* file,
+                               int line,
+                               const char* condition) {
+  SystemErrorCode err_code = logging::GetLastSystemErrorCode();
+#if defined(OS_WIN)
+  CheckError check_error(
+      new Win32ErrorLogMessage(file, line, LOG_DCHECK, err_code));
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+  CheckError check_error(new ErrnoLogMessage(file, line, LOG_DCHECK, err_code));
+#endif
+  check_error.stream() << "Check failed: " << condition << ". ";
+  return check_error;
+}
+
+std::ostream& CheckError::stream() {
+  return log_message_->stream();
+}
+
+CheckError::~CheckError() {
+  delete log_message_;
+}
+
+CheckError::CheckError(LogMessage* log_message) : log_message_(log_message) {}
+
+void RawCheck(const char* message) {
+  RawLog(LOG_FATAL, message);
+}
+
+}  // namespace logging
diff --git a/base/check.h b/base/check.h
new file mode 100644
index 0000000..4f10d1ae
--- /dev/null
+++ b/base/check.h
@@ -0,0 +1,160 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CHECK_H_
+#define BASE_CHECK_H_
+
+#include <iosfwd>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/immediate_crash.h"
+
+// This header defines the CHECK, DCHECK, and DPCHECK macros.
+//
+// CHECK dies with a fatal error if its condition is not true. It is not
+// controlled by NDEBUG, so the check will be executed regardless of compilation
+// mode.
+//
+// DCHECK, the "debug mode" check, is enabled depending on NDEBUG and
+// DCHECK_ALWAYS_ON, and its severity depends on DCHECK_IS_CONFIGURABLE.
+//
+// (D)PCHECK is like (D)CHECK, but includes the system error code (c.f.
+// perror(3)).
+//
+// Additional information can be streamed to these macros and will be included
+// in the log output if the condition doesn't hold (you may need to include
+// <ostream>):
+//
+//   CHECK(condition) << "Additional info.";
+//
+// The condition is evaluated exactly once. Even in build modes where e.g.
+// DCHECK is disabled, the condition and any stream arguments are still
+// referenced to avoid warnings about unused variables and functions.
+//
+// For the (D)CHECK_EQ, etc. macros, see base/check_op.h. However, that header
+// is *significantly* larger than check.h, so try to avoid including it in
+// header files.
+
+namespace logging {
+
+// Class used to explicitly ignore an ostream, and optionally a boolean value.
+class VoidifyStream {
+ public:
+  VoidifyStream() = default;
+  explicit VoidifyStream(bool ignored) {}
+
+  // This operator has lower precedence than << but higher than ?:
+  void operator&(std::ostream&) {}
+};
+
+// Helper macro which avoids evaluating the arguents to a stream if the
+// condition is false.
+#define LAZY_CHECK_STREAM(stream, condition) \
+  !(condition) ? (void)0 : ::logging::VoidifyStream() & (stream)
+
+// Macro which uses but does not evaluate expr and any stream parameters.
+#define EAT_CHECK_STREAM_PARAMS(expr) \
+  true ? (void)0                      \
+       : ::logging::VoidifyStream(expr) & (*::logging::g_swallow_stream)
+BASE_EXPORT extern std::ostream* g_swallow_stream;
+
+class CheckOpResult;
+class LogMessage;
+
+// Class used for raising a check error upon destruction.
+class BASE_EXPORT CheckError {
+ public:
+  static CheckError Check(const char* file, int line, const char* condition);
+  static CheckError CheckOp(const char* file, int line, CheckOpResult* result);
+
+  static CheckError DCheck(const char* file, int line, const char* condition);
+  static CheckError DCheckOp(const char* file, int line, CheckOpResult* result);
+
+  static CheckError PCheck(const char* file, int line, const char* condition);
+  static CheckError PCheck(const char* file, int line);
+
+  static CheckError DPCheck(const char* file, int line, const char* condition);
+
+  // Stream for adding optional details to the error message.
+  std::ostream& stream();
+
+  ~CheckError();
+
+  CheckError(const CheckError& other) = delete;
+  CheckError& operator=(const CheckError& other) = delete;
+  CheckError(CheckError&& other) = default;
+  CheckError& operator=(CheckError&& other) = default;
+
+ private:
+  explicit CheckError(LogMessage* log_message);
+
+  LogMessage* log_message_;
+};
+
+#if defined(OFFICIAL_BUILD) && defined(NDEBUG)
+
+// Discard log strings to reduce code bloat.
+//
+// This is not calling BreakDebugger since this is called frequently, and
+// calling an out-of-line function instead of a noreturn inline macro prevents
+// compiler optimizations.
+#define CHECK(condition) \
+  UNLIKELY(!(condition)) ? IMMEDIATE_CRASH() : EAT_CHECK_STREAM_PARAMS()
+
+#define PCHECK(condition)                                         \
+  LAZY_CHECK_STREAM(                                              \
+      ::logging::CheckError::PCheck(__FILE__, __LINE__).stream(), \
+      UNLIKELY(!(condition)))
+
+#else
+
+#define CHECK(condition)                                                     \
+  LAZY_CHECK_STREAM(                                                         \
+      ::logging::CheckError::Check(__FILE__, __LINE__, #condition).stream(), \
+      !ANALYZER_ASSUME_TRUE(condition))
+
+#define PCHECK(condition)                                                     \
+  LAZY_CHECK_STREAM(                                                          \
+      ::logging::CheckError::PCheck(__FILE__, __LINE__, #condition).stream(), \
+      !ANALYZER_ASSUME_TRUE(condition))
+
+#endif
+
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+#define DCHECK_IS_ON() false
+#else
+#define DCHECK_IS_ON() true
+#endif
+
+#if DCHECK_IS_ON()
+
+#define DCHECK(condition)                                                     \
+  LAZY_CHECK_STREAM(                                                          \
+      ::logging::CheckError::DCheck(__FILE__, __LINE__, #condition).stream(), \
+      !ANALYZER_ASSUME_TRUE(condition))
+
+#define DPCHECK(condition)                                                     \
+  LAZY_CHECK_STREAM(                                                           \
+      ::logging::CheckError::DPCheck(__FILE__, __LINE__, #condition).stream(), \
+      !ANALYZER_ASSUME_TRUE(condition))
+
+#else
+
+#define DCHECK(condition) EAT_CHECK_STREAM_PARAMS(!(condition))
+#define DPCHECK(condition) EAT_CHECK_STREAM_PARAMS(!(condition))
+
+#endif
+
+// Async signal safe checking mechanism.
+BASE_EXPORT void RawCheck(const char* message);
+#define RAW_CHECK(condition)                                 \
+  do {                                                       \
+    if (!(condition))                                        \
+      ::logging::RawCheck("Check failed: " #condition "\n"); \
+  } while (0)
+
+}  // namespace logging
+
+#endif  // BASE_CHECK_H_
diff --git a/base/check_op.cc b/base/check_op.cc
new file mode 100644
index 0000000..7e080646
--- /dev/null
+++ b/base/check_op.cc
@@ -0,0 +1,68 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/check_op.h"
+
+// check_op.h is a widely included header and its size has significant impact on
+// build time. Try not to raise this limit unless absolutely necessary. See
+// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
+#ifndef NACL_TC_REV
+#pragma clang max_tokens_here 235000
+#endif
+
+#include <cstdio>
+#include <sstream>
+
+namespace logging {
+
+char* CheckOpValueStr(int v) {
+  char buf[50];
+  snprintf(buf, sizeof(buf), "%d", v);
+  return strdup(buf);
+}
+
+char* CheckOpValueStr(unsigned v) {
+  char buf[50];
+  snprintf(buf, sizeof(buf), "%u", v);
+  return strdup(buf);
+}
+
+char* CheckOpValueStr(unsigned long v) {
+  char buf[50];
+  snprintf(buf, sizeof(buf), "%lu", v);
+  return strdup(buf);
+}
+
+char* CheckOpValueStr(const void* v) {
+  char buf[50];
+  snprintf(buf, sizeof(buf), "%p", v);
+  return strdup(buf);
+}
+
+char* CheckOpValueStr(std::nullptr_t v) {
+  return strdup("nullptr");
+}
+
+char* CheckOpValueStr(double v) {
+  char buf[50];
+  snprintf(buf, sizeof(buf), "%.6lf", v);
+  return strdup(buf);
+}
+
+char* StreamValToStr(const void* v,
+                     void (*stream_func)(std::ostream&, const void*)) {
+  std::stringstream ss;
+  stream_func(ss, v);
+  return strdup(ss.str().c_str());
+}
+
+CheckOpResult::CheckOpResult(const char* expr_str, char* v1_str, char* v2_str) {
+  std::ostringstream ss;
+  ss << expr_str << " (" << v1_str << " vs. " << v2_str << ")";
+  message_ = strdup(ss.str().c_str());
+  free(v1_str);
+  free(v2_str);
+}
+
+}  // namespace logging
diff --git a/base/check_op.h b/base/check_op.h
new file mode 100644
index 0000000..67e28d1d
--- /dev/null
+++ b/base/check_op.h
@@ -0,0 +1,218 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CHECK_OP_H_
+#define BASE_CHECK_OP_H_
+
+#include <cstddef>
+#include <type_traits>
+
+#include "base/check.h"
+#include "base/template_util.h"
+
+// This header defines the (DP)CHECK_EQ etc. macros.
+//
+// (DP)CHECK_EQ(x, y) is similar to (DP)CHECK(x == y) but will also log the
+// values of x and y if the condition doesn't old. This works for basic types
+// and types with an operator<< or .ToString() method.
+//
+// The operands are evaluated exactly once, and even in build modes where e.g.
+// DCHECK is disabled, the operands and their stringification methods are still
+// referenced to avoid warnings about unused variables or functions.
+//
+// To support the stringification of the check operands, this header is
+// *significantly* larger than base/check.h, so it should be avoided in common
+// headers.
+
+namespace logging {
+
+// Functions for turning check operand values into strings.
+// Caller takes ownership of the returned string.
+BASE_EXPORT char* CheckOpValueStr(int v);
+BASE_EXPORT char* CheckOpValueStr(unsigned v);
+BASE_EXPORT char* CheckOpValueStr(unsigned long v);
+BASE_EXPORT char* CheckOpValueStr(const void* v);
+BASE_EXPORT char* CheckOpValueStr(std::nullptr_t v);
+BASE_EXPORT char* CheckOpValueStr(double v);
+
+// Convert a streamable value to string out-of-line to avoid <sstream>.
+BASE_EXPORT char* StreamValToStr(const void* v,
+                                 void (*stream_func)(std::ostream&,
+                                                     const void*));
+
+template <typename T>
+inline typename std::enable_if<
+    base::internal::SupportsOstreamOperator<const T&>::value &&
+        !std::is_function<typename std::remove_pointer<T>::type>::value,
+    char*>::type
+CheckOpValueStr(const T& v) {
+  auto f = [](std::ostream& s, const void* p) {
+    s << *reinterpret_cast<const T*>(p);
+  };
+
+  // operator& might be overloaded, so do the std::addressof dance.
+  // __builtin_addressof is preferred since it also handles Obj-C ARC pointers.
+  // Some casting is still needed, because T might be volatile.
+#if defined(__has_builtin) && __has_builtin(__builtin_addressof)
+  const void* vp = const_cast<const void*>(
+      reinterpret_cast<const volatile void*>(__builtin_addressof(v)));
+#else
+  const void* vp = reinterpret_cast<const void*>(
+      const_cast<const char*>(&reinterpret_cast<const volatile char&>(v)));
+#endif
+  return StreamValToStr(vp, f);
+}
+
+// Overload for types that have no operator<< but do have .ToString() defined.
+template <typename T>
+inline typename std::enable_if<
+    !base::internal::SupportsOstreamOperator<const T&>::value &&
+        base::internal::SupportsToString<const T&>::value,
+    char*>::type
+CheckOpValueStr(const T& v) {
+  return strdup(v.ToString().c_str());
+}
+
+// Provide an overload for functions and function pointers. Function pointers
+// don't implicitly convert to void* but do implicitly convert to bool, so
+// without this function pointers are always printed as 1 or 0. (MSVC isn't
+// standards-conforming here and converts function pointers to regular
+// pointers, so this is a no-op for MSVC.)
+template <typename T>
+inline typename std::enable_if<
+    std::is_function<typename std::remove_pointer<T>::type>::value,
+    char*>::type
+CheckOpValueStr(const T& v) {
+  return CheckOpValueStr(reinterpret_cast<const void*>(v));
+}
+
+// We need overloads for enums that don't support operator<<.
+// (i.e. scoped enums where no operator<< overload was declared).
+template <typename T>
+inline typename std::enable_if<
+    !base::internal::SupportsOstreamOperator<const T&>::value &&
+        std::is_enum<T>::value,
+    char*>::type
+CheckOpValueStr(const T& v) {
+  return CheckOpValueStr(
+      static_cast<typename std::underlying_type<T>::type>(v));
+}
+
+// Captures the result of a CHECK_op and facilitates testing as a boolean.
+class CheckOpResult {
+ public:
+  // An empty result signals success.
+  constexpr CheckOpResult() : message_(nullptr) {}
+
+  // A non-success result. expr_str is something like "foo != bar". v1_str and
+  // v2_str are the stringified run-time values of foo and bar. Takes ownership
+  // of v1_str and v2_str.
+  BASE_EXPORT CheckOpResult(const char* expr_str, char* v1_str, char* v2_str);
+
+  // Returns true if the check succeeded.
+  constexpr explicit operator bool() const { return !message_; }
+
+  friend class CheckError;
+
+ private:
+  char* message_;
+};
+
+#if defined(OFFICIAL_BUILD) && defined(NDEBUG)
+
+// Discard log strings to reduce code bloat.
+#define CHECK_OP(name, op, val1, val2) CHECK((val1)op(val2))
+
+#else
+
+// Helper macro for binary operators.
+// The 'switch' is used to prevent the 'else' from being ambiguous when the
+// macro is used in an 'if' clause such as:
+// if (a == 1)
+//   CHECK_EQ(2, a);
+#define CHECK_OP(name, op, val1, val2)                                    \
+  switch (0)                                                              \
+  case 0:                                                                 \
+  default:                                                                \
+    if (::logging::CheckOpResult true_if_passed =                         \
+            ::logging::Check##name##Impl((val1), (val2),                  \
+                                         #val1 " " #op " " #val2))        \
+      ;                                                                   \
+    else                                                                  \
+      ::logging::CheckError::CheckOp(__FILE__, __LINE__, &true_if_passed) \
+          .stream()
+
+#endif
+
+// The int-int overload avoids address-taking static int members.
+#define DEFINE_CHECK_OP_IMPL(name, op)                                         \
+  template <typename T, typename U>                                            \
+  constexpr ::logging::CheckOpResult Check##name##Impl(                        \
+      const T& v1, const U& v2, const char* expr_str) {                        \
+    if (ANALYZER_ASSUME_TRUE(v1 op v2))                                        \
+      return ::logging::CheckOpResult();                                       \
+    else                                                                       \
+      return ::logging::CheckOpResult(expr_str, CheckOpValueStr(v1),           \
+                                      CheckOpValueStr(v2));                    \
+  }                                                                            \
+  constexpr ::logging::CheckOpResult Check##name##Impl(int v1, int v2,         \
+                                                       const char* expr_str) { \
+    if (ANALYZER_ASSUME_TRUE(v1 op v2))                                        \
+      return ::logging::CheckOpResult();                                       \
+    else                                                                       \
+      return ::logging::CheckOpResult(expr_str, CheckOpValueStr(v1),           \
+                                      CheckOpValueStr(v2));                    \
+  }
+
+// clang-format off
+DEFINE_CHECK_OP_IMPL(EQ, ==)
+DEFINE_CHECK_OP_IMPL(NE, !=)
+DEFINE_CHECK_OP_IMPL(LE, <=)
+DEFINE_CHECK_OP_IMPL(LT, < )
+DEFINE_CHECK_OP_IMPL(GE, >=)
+DEFINE_CHECK_OP_IMPL(GT, > )
+#undef DEFINE_CHECK_OP_IMPL
+#define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2)
+#define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2)
+#define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2)
+#define CHECK_LT(val1, val2) CHECK_OP(LT, < , val1, val2)
+#define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2)
+#define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2)
+// clang-format on
+
+#if DCHECK_IS_ON()
+
+#define DCHECK_OP(name, op, val1, val2)                                    \
+  switch (0)                                                               \
+  case 0:                                                                  \
+  default:                                                                 \
+    if (::logging::CheckOpResult true_if_passed =                          \
+            ::logging::Check##name##Impl((val1), (val2),                   \
+                                         #val1 " " #op " " #val2))         \
+      ;                                                                    \
+    else                                                                   \
+      ::logging::CheckError::DCheckOp(__FILE__, __LINE__, &true_if_passed) \
+          .stream()
+
+#else
+
+// Don't do any evaluation but still reference the same stuff as when enabled.
+#define DCHECK_OP(name, op, val1, val2)                      \
+  EAT_CHECK_STREAM_PARAMS((::logging::CheckOpValueStr(val1), \
+                           ::logging::CheckOpValueStr(val2), (val1)op(val2)))
+
+#endif
+
+// clang-format off
+#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)
+#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)
+#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2)
+#define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2)
+#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
+#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
+// clang-format on
+
+}  // namespace logging
+
+#endif  // BASE_CHECK_OP_H_
diff --git a/base/check_unittest.cc b/base/check_unittest.cc
index 6cdc372b..fd81621 100644
--- a/base/check_unittest.cc
+++ b/base/check_unittest.cc
@@ -87,9 +87,10 @@
   EXPECT_CHECK("Check failed: false. foo", CHECK(false) << "foo");
 
   double a = 2, b = 1;
-  EXPECT_CHECK("Check failed: a < b (2 vs. 1)", CHECK_LT(a, b));
+  EXPECT_CHECK("Check failed: a < b (2.000000 vs. 1.000000)", CHECK_LT(a, b));
 
-  EXPECT_CHECK("Check failed: a < b (2 vs. 1)foo", CHECK_LT(a, b) << "foo");
+  EXPECT_CHECK("Check failed: a < b (2.000000 vs. 1.000000)foo",
+               CHECK_LT(a, b) << "foo");
 }
 
 TEST_F(CheckTest, PCheck) {
diff --git a/base/compiler_specific.h b/base/compiler_specific.h
index 2962537..592c496 100644
--- a/base/compiler_specific.h
+++ b/base/compiler_specific.h
@@ -247,4 +247,36 @@
 #define STACK_UNINITIALIZED
 #endif
 
+// The ANALYZER_ASSUME_TRUE(bool arg) macro adds compiler-specific hints
+// to Clang which control what code paths are statically analyzed,
+// and is meant to be used in conjunction with assert & assert-like functions.
+// The expression is passed straight through if analysis isn't enabled.
+//
+// ANALYZER_SKIP_THIS_PATH() suppresses static analysis for the current
+// codepath and any other branching codepaths that might follow.
+#if defined(__clang_analyzer__)
+
+inline constexpr bool AnalyzerNoReturn() __attribute__((analyzer_noreturn)) {
+  return false;
+}
+
+inline constexpr bool AnalyzerAssumeTrue(bool arg) {
+  // AnalyzerNoReturn() is invoked and analysis is terminated if |arg| is
+  // false.
+  return arg || AnalyzerNoReturn();
+}
+
+#define ANALYZER_ASSUME_TRUE(arg) logging::AnalyzerAssumeTrue(!!(arg))
+#define ANALYZER_SKIP_THIS_PATH() \
+  static_cast<void>(::logging::AnalyzerNoReturn())
+#define ANALYZER_ALLOW_UNUSED(var) static_cast<void>(var);
+
+#else  // !defined(__clang_analyzer__)
+
+#define ANALYZER_ASSUME_TRUE(arg) (arg)
+#define ANALYZER_SKIP_THIS_PATH()
+#define ANALYZER_ALLOW_UNUSED(var) static_cast<void>(var);
+
+#endif  // defined(__clang_analyzer__)
+
 #endif  // BASE_COMPILER_SPECIFIC_H_
diff --git a/base/fuchsia/fuchsia_logging.h b/base/fuchsia/fuchsia_logging.h
index ba55f8db..46d33e77 100644
--- a/base/fuchsia/fuchsia_logging.h
+++ b/base/fuchsia/fuchsia_logging.h
@@ -24,7 +24,7 @@
                int line,
                LogSeverity severity,
                zx_status_t zx_err);
-  ~ZxLogMessage();
+  ~ZxLogMessage() override;
 
  private:
   zx_status_t zx_err_;
diff --git a/base/logging.cc b/base/logging.cc
index 608cc1122..57f68adbd 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -4,6 +4,13 @@
 
 #include "base/logging.h"
 
+// logging.h is a widely included header and its size has significant impact on
+// build time. Try not to raise this limit unless absolutely necessary. See
+// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
+#ifndef NACL_TC_REV
+#pragma clang max_tokens_here 370000
+#endif  // NACL_TC_REV
+
 #include <limits.h>
 #include <stdint.h>
 
@@ -551,22 +558,6 @@
   return log_message_handler;
 }
 
-// Explicit instantiations for commonly used comparisons.
-template std::string* MakeCheckOpString<int, int>(
-    const int&, const int&, const char* names);
-template std::string* MakeCheckOpString<unsigned long, unsigned long>(
-    const unsigned long&, const unsigned long&, const char* names);
-template std::string* MakeCheckOpString<unsigned long, unsigned int>(
-    const unsigned long&, const unsigned int&, const char* names);
-template std::string* MakeCheckOpString<unsigned int, unsigned long>(
-    const unsigned int&, const unsigned long&, const char* names);
-template std::string* MakeCheckOpString<std::string, std::string>(
-    const std::string&, const std::string&, const char* name);
-
-void MakeCheckOpValueString(std::ostream* os, std::nullptr_t p) {
-  (*os) << "nullptr";
-}
-
 #if !defined(NDEBUG)
 // Displays a message box to the user with the error message in it.
 // Used for fatal messages, where we close the app simultaneously.
@@ -604,21 +595,6 @@
   stream_ << "Check failed: " << condition << ". ";
 }
 
-LogMessage::LogMessage(const char* file, int line, std::string* result)
-    : severity_(LOG_FATAL), file_(file), line_(line) {
-  Init(file, line);
-  stream_ << "Check failed: " << *result;
-  delete result;
-}
-
-LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
-                       std::string* result)
-    : severity_(severity), file_(file), line_(line) {
-  Init(file, line);
-  stream_ << "Check failed: " << *result;
-  delete result;
-}
-
 LogMessage::~LogMessage() {
   size_t stack_start = stream_.tellp();
 #if !defined(OFFICIAL_BUILD) && !defined(OS_NACL) && !defined(__UCLIBC__) && \
@@ -1066,9 +1042,7 @@
                                            int line,
                                            LogSeverity severity,
                                            SystemErrorCode err)
-    : err_(err),
-      log_message_(file, line, severity) {
-}
+    : LogMessage(file, line, severity), err_(err) {}
 
 Win32ErrorLogMessage::~Win32ErrorLogMessage() {
   stream() << ": " << SystemErrorCodeToString(err_);
@@ -1082,9 +1056,7 @@
                                  int line,
                                  LogSeverity severity,
                                  SystemErrorCode err)
-    : err_(err),
-      log_message_(file, line, severity) {
-}
+    : LogMessage(file, line, severity), err_(err) {}
 
 ErrnoLogMessage::~ErrnoLogMessage() {
   stream() << ": " << SystemErrorCodeToString(err_);
diff --git a/base/logging.h b/base/logging.h
index bc602f9..7644ec1 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -9,21 +9,18 @@
 
 #include <cassert>
 #include <cstdint>
-#include <cstring>
 #include <sstream>
 #include <string>
-#include <type_traits>
-#include <utility>
 
 #include "base/base_export.h"
 #include "base/callback_forward.h"
+#include "base/check.h"
+#include "base/check_op.h"
 #include "base/compiler_specific.h"
-#include "base/immediate_crash.h"
 #include "base/logging_buildflags.h"
 #include "base/macros.h"
 #include "base/scoped_clear_last_error.h"
 #include "base/strings/string_piece_forward.h"
-#include "base/template_util.h"
 #include "build/build_config.h"
 
 #if defined(OS_CHROMEOS)
@@ -338,37 +335,6 @@
 BASE_EXPORT void SetLogMessageHandler(LogMessageHandlerFunction handler);
 BASE_EXPORT LogMessageHandlerFunction GetLogMessageHandler();
 
-// The ANALYZER_ASSUME_TRUE(bool arg) macro adds compiler-specific hints
-// to Clang which control what code paths are statically analyzed,
-// and is meant to be used in conjunction with assert & assert-like functions.
-// The expression is passed straight through if analysis isn't enabled.
-//
-// ANALYZER_SKIP_THIS_PATH() suppresses static analysis for the current
-// codepath and any other branching codepaths that might follow.
-#if defined(__clang_analyzer__)
-
-inline constexpr bool AnalyzerNoReturn() __attribute__((analyzer_noreturn)) {
-  return false;
-}
-
-inline constexpr bool AnalyzerAssumeTrue(bool arg) {
-  // AnalyzerNoReturn() is invoked and analysis is terminated if |arg| is
-  // false.
-  return arg || AnalyzerNoReturn();
-}
-
-#define ANALYZER_ASSUME_TRUE(arg) logging::AnalyzerAssumeTrue(!!(arg))
-#define ANALYZER_SKIP_THIS_PATH() \
-  static_cast<void>(::logging::AnalyzerNoReturn())
-#define ANALYZER_ALLOW_UNUSED(var) static_cast<void>(var);
-
-#else  // !defined(__clang_analyzer__)
-
-#define ANALYZER_ASSUME_TRUE(arg) (arg)
-#define ANALYZER_SKIP_THIS_PATH()
-#define ANALYZER_ALLOW_UNUSED(var) static_cast<void>(var);
-
-#endif  // defined(__clang_analyzer__)
 
 typedef int LogSeverity;
 const LogSeverity LOG_VERBOSE = -1;  // This is level 1 verbosity
@@ -525,203 +491,6 @@
   true ? (void)0              \
        : ::logging::LogMessageVoidify() & (*::logging::g_swallow_stream)
 
-// Captures the result of a CHECK_EQ (for example) and facilitates testing as a
-// boolean.
-class CheckOpResult {
- public:
-  // |message| must be non-null if and only if the check failed.
-  constexpr CheckOpResult(std::string* message) : message_(message) {}
-  // Returns true if the check succeeded.
-  constexpr operator bool() const { return !message_; }
-  // Returns the message.
-  std::string* message() { return message_; }
-
- private:
-  std::string* message_;
-};
-
-// CHECK dies with a fatal error if condition is not true.  It is *not*
-// controlled by NDEBUG, so the check will be executed regardless of
-// compilation mode.
-//
-// We make sure CHECK et al. always evaluates their arguments, as
-// doing CHECK(FunctionWithSideEffect()) is a common idiom.
-
-#if defined(OFFICIAL_BUILD) && defined(NDEBUG)
-
-// Make all CHECK functions discard their log strings to reduce code bloat, and
-// improve performance, for official release builds.
-//
-// This is not calling BreakDebugger since this is called frequently, and
-// calling an out-of-line function instead of a noreturn inline macro prevents
-// compiler optimizations.
-#define CHECK(condition) \
-  UNLIKELY(!(condition)) ? IMMEDIATE_CRASH() : EAT_STREAM_PARAMETERS
-
-// PCHECK includes the system error code, which is useful for determining
-// why the condition failed. In official builds, preserve only the error code
-// message so that it is available in crash reports. The stringified
-// condition and any additional stream parameters are dropped.
-#define PCHECK(condition)                                  \
-  LAZY_STREAM(PLOG_STREAM(FATAL), UNLIKELY(!(condition))); \
-  EAT_STREAM_PARAMETERS
-
-#define CHECK_OP(name, op, val1, val2) CHECK((val1) op (val2))
-
-#else  // !(OFFICIAL_BUILD && NDEBUG)
-
-// Do as much work as possible out of line to reduce inline code size.
-#define CHECK(condition)                                                      \
-  LAZY_STREAM(::logging::LogMessage(__FILE__, __LINE__, #condition).stream(), \
-              !ANALYZER_ASSUME_TRUE(condition))
-
-#define PCHECK(condition)                                           \
-  LAZY_STREAM(PLOG_STREAM(FATAL), !ANALYZER_ASSUME_TRUE(condition)) \
-      << "Check failed: " #condition ". "
-
-// Helper macro for binary operators.
-// Don't use this macro directly in your code, use CHECK_EQ et al below.
-// The 'switch' is used to prevent the 'else' from being ambiguous when the
-// macro is used in an 'if' clause such as:
-// if (a == 1)
-//   CHECK_EQ(2, a);
-#define CHECK_OP(name, op, val1, val2)                                         \
-  switch (0) case 0: default:                                                  \
-  if (::logging::CheckOpResult true_if_passed =                                \
-      ::logging::Check##name##Impl((val1), (val2),                             \
-                                   #val1 " " #op " " #val2))                   \
-   ;                                                                           \
-  else                                                                         \
-    ::logging::LogMessage(__FILE__, __LINE__, true_if_passed.message()).stream()
-
-#endif  // !(OFFICIAL_BUILD && NDEBUG)
-
-// This formats a value for a failing CHECK_XX statement.  Ordinarily,
-// it uses the definition for operator<<, with a few special cases below.
-template <typename T>
-inline typename std::enable_if<
-    base::internal::SupportsOstreamOperator<const T&>::value &&
-        !std::is_function<typename std::remove_pointer<T>::type>::value,
-    void>::type
-MakeCheckOpValueString(std::ostream* os, const T& v) {
-  (*os) << v;
-}
-
-// Overload for types that no operator<< but do have .ToString() defined.
-template <typename T>
-inline typename std::enable_if<
-    !base::internal::SupportsOstreamOperator<const T&>::value &&
-        base::internal::SupportsToString<const T&>::value,
-    void>::type
-MakeCheckOpValueString(std::ostream* os, const T& v) {
-  (*os) << v.ToString();
-}
-
-// Provide an overload for functions and function pointers. Function pointers
-// don't implicitly convert to void* but do implicitly convert to bool, so
-// without this function pointers are always printed as 1 or 0. (MSVC isn't
-// standards-conforming here and converts function pointers to regular
-// pointers, so this is a no-op for MSVC.)
-template <typename T>
-inline typename std::enable_if<
-    std::is_function<typename std::remove_pointer<T>::type>::value,
-    void>::type
-MakeCheckOpValueString(std::ostream* os, const T& v) {
-  (*os) << reinterpret_cast<const void*>(v);
-}
-
-// We need overloads for enums that don't support operator<<.
-// (i.e. scoped enums where no operator<< overload was declared).
-template <typename T>
-inline typename std::enable_if<
-    !base::internal::SupportsOstreamOperator<const T&>::value &&
-        std::is_enum<T>::value,
-    void>::type
-MakeCheckOpValueString(std::ostream* os, const T& v) {
-  (*os) << static_cast<typename std::underlying_type<T>::type>(v);
-}
-
-// We need an explicit overload for std::nullptr_t.
-BASE_EXPORT void MakeCheckOpValueString(std::ostream* os, std::nullptr_t p);
-
-// Build the error message string.  This is separate from the "Impl"
-// function template because it is not performance critical and so can
-// be out of line, while the "Impl" code should be inline.  Caller
-// takes ownership of the returned string.
-template<class t1, class t2>
-std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
-  std::ostringstream ss;
-  ss << names << " (";
-  MakeCheckOpValueString(&ss, v1);
-  ss << " vs. ";
-  MakeCheckOpValueString(&ss, v2);
-  ss << ")";
-  std::string* msg = new std::string(ss.str());
-  return msg;
-}
-
-// Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated
-// in logging.cc.
-extern template BASE_EXPORT std::string* MakeCheckOpString<int, int>(
-    const int&, const int&, const char* names);
-extern template BASE_EXPORT
-std::string* MakeCheckOpString<unsigned long, unsigned long>(
-    const unsigned long&, const unsigned long&, const char* names);
-extern template BASE_EXPORT
-std::string* MakeCheckOpString<unsigned long, unsigned int>(
-    const unsigned long&, const unsigned int&, const char* names);
-extern template BASE_EXPORT
-std::string* MakeCheckOpString<unsigned int, unsigned long>(
-    const unsigned int&, const unsigned long&, const char* names);
-extern template BASE_EXPORT
-std::string* MakeCheckOpString<std::string, std::string>(
-    const std::string&, const std::string&, const char* name);
-
-// Helper functions for CHECK_OP macro.
-// The (int, int) specialization works around the issue that the compiler
-// will not instantiate the template version of the function on values of
-// unnamed enum type - see comment below.
-//
-// The checked condition is wrapped with ANALYZER_ASSUME_TRUE, which under
-// static analysis builds, blocks analysis of the current path if the
-// condition is false.
-#define DEFINE_CHECK_OP_IMPL(name, op)                                 \
-  template <class t1, class t2>                                        \
-  constexpr std::string* Check##name##Impl(const t1& v1, const t2& v2, \
-                                           const char* names) {        \
-    if (ANALYZER_ASSUME_TRUE(v1 op v2))                                \
-      return nullptr;                                                  \
-    else                                                               \
-      return ::logging::MakeCheckOpString(v1, v2, names);              \
-  }                                                                    \
-  constexpr std::string* Check##name##Impl(int v1, int v2,             \
-                                           const char* names) {        \
-    if (ANALYZER_ASSUME_TRUE(v1 op v2))                                \
-      return nullptr;                                                  \
-    else                                                               \
-      return ::logging::MakeCheckOpString(v1, v2, names);              \
-  }
-DEFINE_CHECK_OP_IMPL(EQ, ==)
-DEFINE_CHECK_OP_IMPL(NE, !=)
-DEFINE_CHECK_OP_IMPL(LE, <=)
-DEFINE_CHECK_OP_IMPL(LT, < )
-DEFINE_CHECK_OP_IMPL(GE, >=)
-DEFINE_CHECK_OP_IMPL(GT, > )
-#undef DEFINE_CHECK_OP_IMPL
-
-#define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2)
-#define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2)
-#define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2)
-#define CHECK_LT(val1, val2) CHECK_OP(LT, < , val1, val2)
-#define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2)
-#define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2)
-
-#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
-#define DCHECK_IS_ON() false
-#else
-#define DCHECK_IS_ON() true
-#endif
-
 // Definitions for DLOG et al.
 
 #if DCHECK_IS_ON()
@@ -776,95 +545,6 @@
 
 #endif  // DCHECK_IS_ON()
 
-// DCHECK et al. make sure to reference |condition| regardless of
-// whether DCHECKs are enabled; this is so that we don't get unused
-// variable warnings if the only use of a variable is in a DCHECK.
-// This behavior is different from DLOG_IF et al.
-//
-// Note that the definition of the DCHECK macros depends on whether or not
-// DCHECK_IS_ON() is true. When DCHECK_IS_ON() is false, the macros use
-// EAT_STREAM_PARAMETERS to avoid expressions that would create temporaries.
-
-#if DCHECK_IS_ON()
-
-#define DCHECK(condition)                                           \
-  LAZY_STREAM(LOG_STREAM(DCHECK), !ANALYZER_ASSUME_TRUE(condition)) \
-      << "Check failed: " #condition ". "
-#define DPCHECK(condition)                                           \
-  LAZY_STREAM(PLOG_STREAM(DCHECK), !ANALYZER_ASSUME_TRUE(condition)) \
-      << "Check failed: " #condition ". "
-
-#else  // DCHECK_IS_ON()
-
-#define DCHECK(condition) EAT_STREAM_PARAMETERS << !(condition)
-#define DPCHECK(condition) EAT_STREAM_PARAMETERS << !(condition)
-
-#endif  // DCHECK_IS_ON()
-
-// Helper macro for binary operators.
-// Don't use this macro directly in your code, use DCHECK_EQ et al below.
-// The 'switch' is used to prevent the 'else' from being ambiguous when the
-// macro is used in an 'if' clause such as:
-// if (a == 1)
-//   DCHECK_EQ(2, a);
-#if DCHECK_IS_ON()
-
-#define DCHECK_OP(name, op, val1, val2)                                \
-  switch (0) case 0: default:                                          \
-  if (::logging::CheckOpResult true_if_passed =                        \
-      ::logging::Check##name##Impl((val1), (val2),                     \
-                                   #val1 " " #op " " #val2))           \
-   ;                                                                   \
-  else                                                                 \
-    ::logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK,   \
-                          true_if_passed.message()).stream()
-
-#else  // DCHECK_IS_ON()
-
-// When DCHECKs aren't enabled, DCHECK_OP still needs to reference operator<<
-// overloads for |val1| and |val2| to avoid potential compiler warnings about
-// unused functions. For the same reason, it also compares |val1| and |val2|
-// using |op|.
-//
-// Note that the contract of DCHECK_EQ, etc is that arguments are only evaluated
-// once. Even though |val1| and |val2| appear twice in this version of the macro
-// expansion, this is OK, since the expression is never actually evaluated.
-#define DCHECK_OP(name, op, val1, val2)                             \
-  EAT_STREAM_PARAMETERS << (::logging::MakeCheckOpValueString(      \
-                                ::logging::g_swallow_stream, val1), \
-                            ::logging::MakeCheckOpValueString(      \
-                                ::logging::g_swallow_stream, val2), \
-                            (val1)op(val2))
-
-#endif  // DCHECK_IS_ON()
-
-// Equality/Inequality checks - compare two values, and log a
-// LOG_DCHECK message including the two values when the result is not
-// as expected.  The values must have operator<<(ostream, ...)
-// defined.
-//
-// You may append to the error message like so:
-//   DCHECK_NE(1, 2) << "The world must be ending!";
-//
-// We are very careful to ensure that each argument is evaluated exactly
-// once, and that anything which is legal to pass as a function argument is
-// legal here.  In particular, the arguments may be temporary expressions
-// which will end up being destroyed at the end of the apparent statement,
-// for example:
-//   DCHECK_EQ(string("abc")[1], 'b');
-//
-// WARNING: These don't compile correctly if one of the arguments is a pointer
-// and the other is NULL.  In new code, prefer nullptr instead.  To
-// work around this for C++98, simply static_cast NULL to the type of the
-// desired pointer.
-
-#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)
-#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)
-#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2)
-#define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2)
-#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
-#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
-
 #if BUILDFLAG(ENABLE_LOG_ERROR_NOT_REACHED)
 // Implement logging of NOTREACHED() as a dedicated function to get function
 // call overhead down to a minimum.
@@ -896,15 +576,7 @@
   // Used for CHECK().  Implied severity = LOG_FATAL.
   LogMessage(const char* file, int line, const char* condition);
 
-  // Used for CHECK_EQ(), etc. Takes ownership of the given string.
-  // Implied severity = LOG_FATAL.
-  LogMessage(const char* file, int line, std::string* result);
-
-  // Used for DCHECK_EQ(), etc. Takes ownership of the given string.
-  LogMessage(const char* file, int line, LogSeverity severity,
-             std::string* result);
-
-  ~LogMessage();
+  virtual ~LogMessage();
 
   std::ostream& stream() { return stream_; }
 
@@ -955,7 +627,7 @@
 
 #if defined(OS_WIN)
 // Appends a formatted system message of the GetLastError() type.
-class BASE_EXPORT Win32ErrorLogMessage {
+class BASE_EXPORT Win32ErrorLogMessage : public LogMessage {
  public:
   Win32ErrorLogMessage(const char* file,
                        int line,
@@ -963,19 +635,16 @@
                        SystemErrorCode err);
 
   // Appends the error message before destructing the encapsulated class.
-  ~Win32ErrorLogMessage();
-
-  std::ostream& stream() { return log_message_.stream(); }
+  ~Win32ErrorLogMessage() override;
 
  private:
   SystemErrorCode err_;
-  LogMessage log_message_;
 
   DISALLOW_COPY_AND_ASSIGN(Win32ErrorLogMessage);
 };
 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
 // Appends a formatted system message of the errno type
-class BASE_EXPORT ErrnoLogMessage {
+class BASE_EXPORT ErrnoLogMessage : public LogMessage {
  public:
   ErrnoLogMessage(const char* file,
                   int line,
@@ -983,13 +652,10 @@
                   SystemErrorCode err);
 
   // Appends the error message before destructing the encapsulated class.
-  ~ErrnoLogMessage();
-
-  std::ostream& stream() { return log_message_.stream(); }
+  ~ErrnoLogMessage() override;
 
  private:
   SystemErrorCode err_;
-  LogMessage log_message_;
 
   DISALLOW_COPY_AND_ASSIGN(ErrnoLogMessage);
 };
@@ -1015,12 +681,6 @@
 #define RAW_LOG(level, message) \
   ::logging::RawLog(::logging::LOG_##level, message)
 
-#define RAW_CHECK(condition)                               \
-  do {                                                     \
-    if (!(condition))                                      \
-      ::logging::RawLog(::logging::LOG_FATAL,              \
-                        "Check failed: " #condition "\n"); \
-  } while (0)
 
 #if defined(OS_WIN)
 // Returns true if logging to file is enabled.
diff --git a/base/mac/mac_logging.h b/base/mac/mac_logging.h
index 30e43ead..72315e9c 100644
--- a/base/mac/mac_logging.h
+++ b/base/mac/mac_logging.h
@@ -38,7 +38,7 @@
                      int line,
                      LogSeverity severity,
                      OSStatus status);
-  ~OSStatusLogMessage();
+  ~OSStatusLogMessage() override;
 
  private:
   OSStatus status_;
diff --git a/base/mac/mach_logging.h b/base/mac/mach_logging.h
index 59ab762..c0247d2 100644
--- a/base/mac/mach_logging.h
+++ b/base/mac/mach_logging.h
@@ -39,7 +39,7 @@
                  int line,
                  LogSeverity severity,
                  mach_error_t mach_err);
-  ~MachLogMessage();
+  ~MachLogMessage() override;
 
  private:
   mach_error_t mach_err_;
@@ -106,7 +106,7 @@
                       int line,
                       LogSeverity severity,
                       kern_return_t bootstrap_err);
-  ~BootstrapLogMessage();
+  ~BootstrapLogMessage() override;
 
  private:
   kern_return_t bootstrap_err_;
diff --git a/base/util/timer/wall_clock_timer_unittest.cc b/base/util/timer/wall_clock_timer_unittest.cc
index cfb5c950..961f5c0 100644
--- a/base/util/timer/wall_clock_timer_unittest.cc
+++ b/base/util/timer/wall_clock_timer_unittest.cc
@@ -133,8 +133,7 @@
 
 TEST_F(WallClockTimerTest, Stop) {
   ::testing::StrictMock<base::MockOnceClosure> callback;
-  const auto start_time = base::Time::Now();
-  clock_.SetNow(start_time);
+  clock_.SetNow(base::Time::Now());
 
   // Set up a WallClockTimer.
   WallClockTimer wall_clock_timer(&clock_,
@@ -158,4 +157,63 @@
   ::testing::Mock::VerifyAndClearExpectations(&callback);
 }
 
+TEST_F(WallClockTimerTest, RestartRunningTimer) {
+  ::testing::StrictMock<base::MockOnceClosure> first_callback;
+  ::testing::StrictMock<base::MockOnceClosure> second_callback;
+  constexpr auto delay = base::TimeDelta::FromMinutes(1);
+
+  // Set up a WallClockTimer that will invoke |first_callback| in one minute.
+  clock_.SetNow(base::Time::Now());
+  WallClockTimer wall_clock_timer(&clock_,
+                                  task_environment_.GetMockTickClock());
+  wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay, first_callback.Get());
+
+  // After 30 seconds, replace the timer with |second_callback| with new one
+  // minute delay.
+  constexpr auto past_time = delay / 2;
+  FastForwardBy(past_time);
+  wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay,
+                         second_callback.Get());
+
+  // |first_callback| is due but it won't be called because it's replaced.
+  FastForwardBy(past_time);
+  ::testing::Mock::VerifyAndClearExpectations(&first_callback);
+  ::testing::Mock::VerifyAndClearExpectations(&second_callback);
+
+  // Timer invokes the |second_callback|.
+  EXPECT_CALL(second_callback, Run());
+  FastForwardBy(past_time);
+  ::testing::Mock::VerifyAndClearExpectations(&first_callback);
+  ::testing::Mock::VerifyAndClearExpectations(&second_callback);
+}
+
+TEST_F(WallClockTimerTest, DoubleStop) {
+  ::testing::StrictMock<base::MockOnceClosure> callback;
+  clock_.SetNow(base::Time::Now());
+
+  // Set up a WallClockTimer.
+  WallClockTimer wall_clock_timer(&clock_,
+                                  task_environment_.GetMockTickClock());
+  constexpr auto delay = base::TimeDelta::FromMinutes(1);
+  wall_clock_timer.Start(FROM_HERE, clock_.Now() + delay, callback.Get());
+
+  // After 15 seconds, timer is stopped.
+  constexpr auto past_time = delay / 4;
+  FastForwardBy(past_time);
+  EXPECT_TRUE(wall_clock_timer.IsRunning());
+  wall_clock_timer.Stop();
+  EXPECT_FALSE(wall_clock_timer.IsRunning());
+
+  // And timer is stopped again later. The second stop should be a no-op.
+  FastForwardBy(past_time);
+  EXPECT_FALSE(wall_clock_timer.IsRunning());
+  wall_clock_timer.Stop();
+  EXPECT_FALSE(wall_clock_timer.IsRunning());
+
+  // Timer won't fire after stop.
+  FastForwardBy(past_time, /*with_power=*/false);
+  FastForwardBy(delay - past_time * 3);
+  ::testing::Mock::VerifyAndClearExpectations(&callback);
+}
+
 }  // namespace util
diff --git a/build/android/pylib/local/emulator/OWNERS b/build/android/pylib/local/emulator/OWNERS
new file mode 100644
index 0000000..0853590d
--- /dev/null
+++ b/build/android/pylib/local/emulator/OWNERS
@@ -0,0 +1,4 @@
+bpastene@chromium.org
+hypan@google.com
+jbudorick@chromium.org
+liaoyuke@chromium.org
diff --git a/build/android/pylib/local/emulator/avd.py b/build/android/pylib/local/emulator/avd.py
index 012071ba..ccdbf09 100644
--- a/build/android/pylib/local/emulator/avd.py
+++ b/build/android/pylib/local/emulator/avd.py
@@ -236,8 +236,9 @@
       avd_dir = os.path.join(android_avd_home, '%s.avd' % self._config.avd_name)
       config_ini = os.path.join(avd_dir, 'config.ini')
 
-      with open(root_ini, 'a') as root_ini_file:
-        root_ini_file.write('path.rel=avd/%s.avd\n' % self._config.avd_name)
+      if os.path.exists(root_ini):
+        with open(root_ini, 'a') as root_ini_file:
+          root_ini_file.write('path.rel=avd/%s.avd\n' % self._config.avd_name)
 
       if os.path.exists(config_ini):
         with open(config_ini) as config_ini_file:
@@ -263,7 +264,10 @@
       self._Initialize()
       instance = _AvdInstance(self._emulator_path, self._emulator_home,
                               self._config)
-      instance.Start(read_only=False, snapshot_save=snapshot)
+      # Enable debug for snapshot when it is set to True
+      debug_tags = 'snapshot' if snapshot else None
+      instance.Start(
+          read_only=False, snapshot_save=snapshot, debug_tags=debug_tags)
       device_utils.DeviceUtils(instance.serial).WaitUntilFullyBooted(
           timeout=180, retries=0)
       instance.Stop()
@@ -496,7 +500,8 @@
             read_only=True,
             snapshot_save=False,
             window=False,
-            writable_system=False):
+            writable_system=False,
+            debug_tags=None):
     """Starts the emulator running an instance of the given AVD."""
 
     with tempfile_ext.TemporaryFileName() as socket_path, (contextlib.closing(
@@ -517,6 +522,8 @@
         emulator_cmd.append('-no-snapshot-save')
       if writable_system:
         emulator_cmd.append('-writable-system')
+      if debug_tags:
+        emulator_cmd.extend(['-debug', debug_tags])
 
       emulator_env = {}
       if self._emulator_home:
@@ -531,11 +538,14 @@
 
       sock.listen(1)
 
-      logging.info('Starting emulator.')
+      logging.info('Starting emulator with commands: %s',
+                   ' '.join(emulator_cmd))
 
       # TODO(jbudorick): Add support for logging emulator stdout & stderr at
       # higher logging levels.
-      self._sink = open('/dev/null', 'w')
+      # Enable the emulator log when debug_tags is set.
+      if not debug_tags:
+        self._sink = open('/dev/null', 'w')
       self._emulator_proc = cmd_helper.Popen(
           emulator_cmd, stdout=self._sink, stderr=self._sink, env=emulator_env)
 
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index c084d0b..17d4cfb 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20200413.3.1
\ No newline at end of file
+0.20200414.2.1
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index c084d0b..d82e38e3 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20200413.3.1
\ No newline at end of file
+0.20200414.1.1
\ No newline at end of file
diff --git a/cc/metrics/compositor_frame_reporter.cc b/cc/metrics/compositor_frame_reporter.cc
index 19371cf9..1b454f3a 100644
--- a/cc/metrics/compositor_frame_reporter.cc
+++ b/cc/metrics/compositor_frame_reporter.cc
@@ -290,7 +290,7 @@
 }
 
 void CompositorFrameReporter::OnDidNotProduceFrame() {
-  did_not_produce_frame_ = true;
+  did_not_produce_frame_time_ = base::TimeTicks::Now();
 }
 
 void CompositorFrameReporter::SetBlinkBreakdown(
diff --git a/cc/metrics/compositor_frame_reporter.h b/cc/metrics/compositor_frame_reporter.h
index f0139cb9..4105713 100644
--- a/cc/metrics/compositor_frame_reporter.h
+++ b/cc/metrics/compositor_frame_reporter.h
@@ -152,11 +152,17 @@
   void OnAbortBeginMainFrame(base::TimeTicks timestamp);
   void OnDidNotProduceFrame();
   bool did_finish_impl_frame() const { return did_finish_impl_frame_; }
-  bool did_not_produce_frame() const { return did_not_produce_frame_; }
   base::TimeTicks impl_frame_finish_time() const {
     return impl_frame_finish_time_;
   }
 
+  bool did_not_produce_frame() const {
+    return did_not_produce_frame_time_.has_value();
+  }
+  base::TimeTicks did_not_produce_frame_time() const {
+    return *did_not_produce_frame_time_;
+  }
+
   bool did_abort_main_frame() const {
     return main_frame_abort_time_.has_value();
   }
@@ -236,13 +242,14 @@
 
   // Indicates if work on Impl frame is finished.
   bool did_finish_impl_frame_ = false;
-  // Flag indicating if DidNotProduceFrame is called for this reporter
-  bool did_not_produce_frame_ = false;
   // The time that work on Impl frame is finished. It's only valid if the
   // reporter is in a stage other than begin impl frame.
   base::TimeTicks impl_frame_finish_time_;
   base::TimeTicks frame_deadline_;
 
+  // The timestamp of when the frame was marked as not having produced a frame
+  // (through a call to DidNotProduceFrame()).
+  base::Optional<base::TimeTicks> did_not_produce_frame_time_;
   base::Optional<base::TimeTicks> main_frame_abort_time_;
 };
 }  // namespace cc
diff --git a/cc/metrics/compositor_frame_reporting_controller.cc b/cc/metrics/compositor_frame_reporting_controller.cc
index 4ba0175d..caa801c 100644
--- a/cc/metrics/compositor_frame_reporting_controller.cc
+++ b/cc/metrics/compositor_frame_reporting_controller.cc
@@ -52,6 +52,11 @@
   return base::TimeTicks::Now();
 }
 
+bool CompositorFrameReportingController::HasReporterAt(
+    PipelineStage stage) const {
+  return !!reporters_[stage].get();
+}
+
 void CompositorFrameReportingController::WillBeginImplFrame(
     const viz::BeginFrameArgs& args) {
   base::TimeTicks begin_time = Now();
@@ -291,6 +296,19 @@
   }
 }
 
+void CompositorFrameReportingController::OnStoppedRequestingBeginFrames() {
+  // If the client stopped requesting begin-frames, that means the begin-frames
+  // currently being handled are no longer expected to produce any
+  // compositor-frames. So terminate the reporters.
+  auto now = Now();
+  for (int i = 0; i < PipelineStage::kNumPipelineStages; ++i) {
+    if (reporters_[i]) {
+      reporters_[i]->TerminateFrame(FrameTerminationStatus::kDidNotProduceFrame,
+                                    now);
+    }
+  }
+}
+
 void CompositorFrameReportingController::SetBlinkBreakdown(
     std::unique_ptr<BeginMainFrameMetrics> details,
     base::TimeTicks main_thread_start_time) {
@@ -314,16 +332,18 @@
     PipelineStage target) {
   auto& reporter = reporters_[target];
   if (reporter) {
-    auto termination_time = (target == PipelineStage::kBeginMainFrame &&
-                             reporter->did_abort_main_frame())
-                                ? reporter->main_frame_abort_time()
-                                : Now();
-    if (reporters_[target]->did_not_produce_frame())
-      reporters_[target]->TerminateFrame(
-          FrameTerminationStatus::kDidNotProduceFrame, termination_time);
-    else
-      reporters_[target]->TerminateFrame(
-          FrameTerminationStatus::kReplacedByNewReporter, termination_time);
+    auto termination_status = FrameTerminationStatus::kReplacedByNewReporter;
+    base::TimeTicks termination_time;
+    if (reporter->did_not_produce_frame()) {
+      termination_time = reporter->did_not_produce_frame_time();
+      termination_status = FrameTerminationStatus::kDidNotProduceFrame;
+    } else if (target == PipelineStage::kBeginMainFrame &&
+               reporter->did_abort_main_frame()) {
+      termination_time = reporter->main_frame_abort_time();
+    } else {
+      termination_time = Now();
+    }
+    reporter->TerminateFrame(termination_status, termination_time);
   }
   reporters_[target] = std::move(reporters_[start]);
 }
diff --git a/cc/metrics/compositor_frame_reporting_controller.h b/cc/metrics/compositor_frame_reporting_controller.h
index 8eb99e0..8e63a48 100644
--- a/cc/metrics/compositor_frame_reporting_controller.h
+++ b/cc/metrics/compositor_frame_reporting_controller.h
@@ -65,6 +65,7 @@
   virtual void DidPresentCompositorFrame(
       uint32_t frame_token,
       const viz::FrameTimingDetails& details);
+  void OnStoppedRequestingBeginFrames();
 
   void SetBlinkBreakdown(std::unique_ptr<BeginMainFrameMetrics> details,
                          base::TimeTicks main_thread_start_time);
@@ -74,7 +75,7 @@
   virtual void AddActiveTracker(FrameSequenceTrackerType type);
   virtual void RemoveActiveTracker(FrameSequenceTrackerType type);
 
-  base::flat_set<FrameSequenceTrackerType> active_trackers_;
+  std::unique_ptr<CompositorFrameReporter>* reporters() { return reporters_; }
 
  protected:
   struct SubmittedCompositorFrame {
@@ -87,8 +88,8 @@
     ~SubmittedCompositorFrame();
   };
   base::TimeTicks Now() const;
-  std::unique_ptr<CompositorFrameReporter>
-      reporters_[PipelineStage::kNumPipelineStages];
+
+  bool HasReporterAt(PipelineStage stage) const;
 
  private:
   void AdvanceReporterStage(PipelineStage start, PipelineStage target);
@@ -101,6 +102,7 @@
   viz::BeginFrameId last_submitted_frame_id_;
 
   bool next_activate_has_invalidation_ = false;
+  base::flat_set<FrameSequenceTrackerType> active_trackers_;
 
   // The latency reporter passed to each CompositorFrameReporter. Owned here
   // because it must be common among all reporters.
@@ -108,6 +110,9 @@
   // outlive the objects in |submitted_compositor_frames_|.
   std::unique_ptr<LatencyUkmReporter> latency_ukm_reporter_;
 
+  std::unique_ptr<CompositorFrameReporter>
+      reporters_[PipelineStage::kNumPipelineStages];
+
   // Mapping of frame token to pipeline reporter for submitted compositor
   // frames.
   // DO NOT reorder this line and the one above. The latency_ukm_reporter_ must
diff --git a/cc/metrics/compositor_frame_reporting_controller_unittest.cc b/cc/metrics/compositor_frame_reporting_controller_unittest.cc
index 64da64b..e2e8268 100644
--- a/cc/metrics/compositor_frame_reporting_controller_unittest.cc
+++ b/cc/metrics/compositor_frame_reporting_controller_unittest.cc
@@ -37,12 +37,10 @@
   TestCompositorFrameReportingController& operator=(
       const TestCompositorFrameReportingController& controller) = delete;
 
-  std::unique_ptr<CompositorFrameReporter>* reporters() { return reporters_; }
-
   int ActiveReporters() {
     int count = 0;
     for (int i = 0; i < PipelineStage::kNumPipelineStages; ++i) {
-      if (reporters_[i])
+      if (reporters()[i])
         ++count;
     }
     return count;
diff --git a/cc/metrics/compositor_timing_history.cc b/cc/metrics/compositor_timing_history.cc
index db50742..25d1813 100644
--- a/cc/metrics/compositor_timing_history.cc
+++ b/cc/metrics/compositor_timing_history.cc
@@ -662,6 +662,7 @@
 void CompositorTimingHistory::BeginImplFrameNotExpectedSoon() {
   SetBeginMainFrameNeededContinuously(false);
   SetCompositorDrawingContinuously(false);
+  compositor_frame_reporting_controller_->OnStoppedRequestingBeginFrames();
 }
 
 void CompositorTimingHistory::WillBeginMainFrame(
diff --git a/cc/scheduler/begin_frame_tracker.cc b/cc/scheduler/begin_frame_tracker.cc
index fe8f840..0480a2c 100644
--- a/cc/scheduler/begin_frame_tracker.cc
+++ b/cc/scheduler/begin_frame_tracker.cc
@@ -16,7 +16,7 @@
 
 BeginFrameTracker::~BeginFrameTracker() = default;
 
-void BeginFrameTracker::Start(viz::BeginFrameArgs new_args) {
+void BeginFrameTracker::Start(const viz::BeginFrameArgs& new_args) {
   // Trace the frame time being passed between BeginFrameTrackers.
   TRACE_EVENT_FLOW_STEP0(
       TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"), "BeginFrameArgs",
diff --git a/cc/scheduler/begin_frame_tracker.h b/cc/scheduler/begin_frame_tracker.h
index 2f5f3b1..fc04109 100644
--- a/cc/scheduler/begin_frame_tracker.h
+++ b/cc/scheduler/begin_frame_tracker.h
@@ -49,7 +49,7 @@
 
   // Start using a new BFA value and check invariant properties.
   // **Must** only be called after finishing with any previous BFA.
-  void Start(viz::BeginFrameArgs new_args);
+  void Start(const viz::BeginFrameArgs& new_args);
   // Finish using the current BFA.
   // **Must** only be called while still using a BFA.
   void Finish();
diff --git a/cc/test/fake_compositor_frame_reporting_controller.cc b/cc/test/fake_compositor_frame_reporting_controller.cc
index 739158d..ea3dc87 100644
--- a/cc/test/fake_compositor_frame_reporting_controller.cc
+++ b/cc/test/fake_compositor_frame_reporting_controller.cc
@@ -17,14 +17,14 @@
 
 void FakeCompositorFrameReportingController::WillBeginMainFrame(
     const viz::BeginFrameArgs& args) {
-  if (!reporters_[PipelineStage::kBeginImplFrame])
+  if (!HasReporterAt(PipelineStage::kBeginImplFrame))
     CompositorFrameReportingController::WillBeginImplFrame(args);
   CompositorFrameReportingController::WillBeginMainFrame(args);
 }
 
 void FakeCompositorFrameReportingController::BeginMainFrameAborted(
     const viz::BeginFrameId& id) {
-  if (!reporters_[PipelineStage::kBeginMainFrame]) {
+  if (!HasReporterAt(PipelineStage::kBeginMainFrame)) {
     viz::BeginFrameArgs args = viz::BeginFrameArgs();
     args.frame_id = id;
     args.frame_time = Now();
@@ -35,7 +35,7 @@
 }
 
 void FakeCompositorFrameReportingController::WillCommit() {
-  if (!reporters_[PipelineStage::kBeginMainFrame]) {
+  if (!HasReporterAt(PipelineStage::kBeginMainFrame)) {
     viz::BeginFrameArgs args = viz::BeginFrameArgs();
     args.frame_id = viz::BeginFrameId();
     args.frame_time = Now();
@@ -46,19 +46,19 @@
 }
 
 void FakeCompositorFrameReportingController::DidCommit() {
-  if (!reporters_[PipelineStage::kBeginMainFrame])
+  if (!HasReporterAt(PipelineStage::kBeginMainFrame))
     WillCommit();
   CompositorFrameReportingController::DidCommit();
 }
 
 void FakeCompositorFrameReportingController::WillActivate() {
-  if (!reporters_[PipelineStage::kCommit])
+  if (!HasReporterAt(PipelineStage::kCommit))
     DidCommit();
   CompositorFrameReportingController::WillActivate();
 }
 
 void FakeCompositorFrameReportingController::DidActivate() {
-  if (!reporters_[PipelineStage::kCommit])
+  if (!HasReporterAt(PipelineStage::kCommit))
     WillActivate();
   CompositorFrameReportingController::DidActivate();
 }
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 0226f80c..0c1cba8 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -301,6 +301,7 @@
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/settings:java",
     "//chrome/browser/share/android:java_resources",
+    "//chrome/browser/tab:java",
     "//chrome/browser/thumbnail:java",
     "//chrome/browser/ui/android/appmenu:factory_java",
     "//chrome/browser/ui/android/appmenu:java",
@@ -475,7 +476,6 @@
     "//chrome/browser/notifications/scheduler/public:jni_enums",
     "//chrome/browser/supervised_user/supervised_user_error_page:enums_srcjar",
     "//chrome/browser/ui:cookie_controls_enforcement_javagen",
-    "//chrome/browser/ui:tab_model_enums_java",
     "//chrome/browser/updates/announcement_notification:jni_enums",
     "//components/autofill_assistant/browser:autofill_assistant_enums_java",
     "//components/browsing_data/core:browsing_data_utils_java",
@@ -795,6 +795,7 @@
     "//base:base_java",
     "//base:base_java_test_support",
     "//chrome/android:chrome_java",
+    "//chrome/browser/tab:java",
     "//chrome/browser/ui/android/appmenu:java",
     "//chrome/test/android:chrome_java_test_support",
     "//content/public/android:content_java",
@@ -850,6 +851,7 @@
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/settings:java",
     "//chrome/browser/settings:javatests",
+    "//chrome/browser/tab:java",
     "//chrome/browser/thumbnail:java",
     "//chrome/browser/thumbnail:javatests",
     "//chrome/browser/ui/android/appmenu:java",
@@ -1040,6 +1042,7 @@
     "//chrome/android:app_hooks_java",
     "//chrome/android:chrome_java",
     "//chrome/android/features/vr:java",
+    "//chrome/browser/tab:java",
     "//chrome/browser/util:java",
     "//chrome/test/android:chrome_java_test_support",
     "//components/embedder_support/android:util_java",
@@ -1672,6 +1675,7 @@
     "//base:base_java",
     "//base:base_java_test_support",
     "//chrome/browser/profiles/android:java",
+    "//chrome/browser/tab:java",
     "//components/offline_items_collection/core:core_java",
     "//components/sync/protocol:protocol_java",
     "//content/public/android:content_java",
@@ -3007,6 +3011,7 @@
     "//chrome/android:chrome_java",
     "//chrome/browser/flags:java",
     "//chrome/browser/profiles/android:java",
+    "//chrome/browser/tab:java",
     "//chrome/browser/util:java",
     "//chrome/test/android:chrome_java_test_support",
     "//components/embedder_support/android:context_menu_java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index eeca7fc..f75c3a2 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1577,32 +1577,24 @@
   "java/src/org/chromium/chrome/browser/tab/AccessibilityVisibilityHandler.java",
   "java/src/org/chromium/chrome/browser/tab/AuthenticatorNavigationInterceptor.java",
   "java/src/org/chromium/chrome/browser/tab/AuthenticatorNavigationInterceptorTabHelper.java",
-  "java/src/org/chromium/chrome/browser/tab/EmptyTabObserver.java",
   "java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateClientImpl.java",
   "java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java",
   "java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTabHelper.java",
   "java/src/org/chromium/chrome/browser/tab/RedirectHandlerTabHelper.java",
   "java/src/org/chromium/chrome/browser/tab/SadTab.java",
   "java/src/org/chromium/chrome/browser/tab/SadTabView.java",
-  "java/src/org/chromium/chrome/browser/tab/Tab.java",
   "java/src/org/chromium/chrome/browser/tab/TabAssociatedApp.java",
-  "java/src/org/chromium/chrome/browser/tab/TabAttributeKeys.java",
-  "java/src/org/chromium/chrome/browser/tab/TabAttributes.java",
   "java/src/org/chromium/chrome/browser/tab/TabBrowserControlsConstraintsHelper.java",
   "java/src/org/chromium/chrome/browser/tab/TabBrowserControlsOffsetHelper.java",
   "java/src/org/chromium/chrome/browser/tab/TabBuilder.java",
   "java/src/org/chromium/chrome/browser/tab/TabContextMenuItemDelegate.java",
   "java/src/org/chromium/chrome/browser/tab/TabContextMenuPopulator.java",
-  "java/src/org/chromium/chrome/browser/tab/TabCreationState.java",
   "java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java",
   "java/src/org/chromium/chrome/browser/tab/TabFavicon.java",
   "java/src/org/chromium/chrome/browser/tab/TabHelpers.java",
-  "java/src/org/chromium/chrome/browser/tab/TabHidingType.java",
   "java/src/org/chromium/chrome/browser/tab/TabIdManager.java",
   "java/src/org/chromium/chrome/browser/tab/TabImpl.java",
   "java/src/org/chromium/chrome/browser/tab/TabImportanceManager.java",
-  "java/src/org/chromium/chrome/browser/tab/TabLifecycle.java",
-  "java/src/org/chromium/chrome/browser/tab/TabObserver.java",
   "java/src/org/chromium/chrome/browser/tab/TabParentIntent.java",
   "java/src/org/chromium/chrome/browser/tab/TabState.java",
   "java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java",
diff --git a/chrome/android/features/autofill_assistant/BUILD.gn b/chrome/android/features/autofill_assistant/BUILD.gn
index f00e666..a93eab8 100644
--- a/chrome/android/features/autofill_assistant/BUILD.gn
+++ b/chrome/android/features/autofill_assistant/BUILD.gn
@@ -35,6 +35,7 @@
     "//chrome/android:chrome_java",
     "//chrome/browser/image_fetcher:java",
     "//chrome/browser/profiles/android:java",
+    "//chrome/browser/tab:java",
     "//chrome/browser/ui/messages/android:java",
     "//chrome/browser/util:java",
     "//components/browser_ui/modaldialog/android:java",
diff --git a/chrome/android/features/keyboard_accessory/BUILD.gn b/chrome/android/features/keyboard_accessory/BUILD.gn
index 062b5200..235b10d 100644
--- a/chrome/android/features/keyboard_accessory/BUILD.gn
+++ b/chrome/android/features/keyboard_accessory/BUILD.gn
@@ -61,6 +61,7 @@
     "//chrome/android:chrome_test_java",
     "//chrome/android:chrome_test_util_java",
     "//chrome/browser/profiles/android:java",
+    "//chrome/browser/tab:java",
     "//chrome/browser/ui/messages/android:java",
     "//chrome/test/android:chrome_java_test_support",
     "//components/autofill/android:autofill_java",
diff --git a/chrome/android/features/keyboard_accessory/internal/BUILD.gn b/chrome/android/features/keyboard_accessory/internal/BUILD.gn
index 82919c4..5a710458 100644
--- a/chrome/android/features/keyboard_accessory/internal/BUILD.gn
+++ b/chrome/android/features/keyboard_accessory/internal/BUILD.gn
@@ -17,6 +17,7 @@
     "//chrome/android/features/keyboard_accessory/public:public_java",
     "//chrome/browser/flags:java",
     "//chrome/browser/profiles/android:java",
+    "//chrome/browser/tab:java",
     "//chrome/browser/ui/android/favicon:java",
     "//chrome/browser/util:java",
     "//components/autofill/android:autofill_java",
diff --git a/chrome/android/features/start_surface/internal/BUILD.gn b/chrome/android/features/start_surface/internal/BUILD.gn
index 4631bec..dccbd57f 100644
--- a/chrome/android/features/start_surface/internal/BUILD.gn
+++ b/chrome/android/features/start_surface/internal/BUILD.gn
@@ -65,6 +65,7 @@
     "//chrome/android/third_party/compositor_animator:compositor_animator_java",
     "//chrome/browser/flags:java",
     "//chrome/browser/preferences:java",
+    "//chrome/browser/tab:java",
     "//chrome/browser/ui/messages/android:java",
     "//components/browser_ui/widget/android:java",
     "//third_party/android_deps:android_support_v7_appcompat_java",
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutPerfTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutPerfTest.java
index a7a0c65..0bb47fd 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutPerfTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutPerfTest.java
@@ -172,7 +172,7 @@
     @Test
     @EnormousTest
     @DisableIf
-            .Build(sdk_is_less_than = Build.VERSION_CODES.M, message = "https://crbug.com/1045938")
+            .Build(sdk_is_less_than = Build.VERSION_CODES.N, message = "https://crbug.com/1045938")
     @CommandLineFlags.Add({BASE_PARAMS})
     public void testTabToGridFromLiveTabWith10TabsWithoutThumbnail() throws InterruptedException {
         // Note that most of the tabs won't have thumbnails.
diff --git a/chrome/android/features/tab_ui/BUILD.gn b/chrome/android/features/tab_ui/BUILD.gn
index 1af43b7..2f4a644 100644
--- a/chrome/android/features/tab_ui/BUILD.gn
+++ b/chrome/android/features/tab_ui/BUILD.gn
@@ -181,6 +181,7 @@
     "//chrome/browser/android/lifecycle:java",
     "//chrome/browser/flags:java",
     "//chrome/browser/profiles/android:java",
+    "//chrome/browser/tab:java",
     "//chrome/browser/ui/android/favicon:java",
     "//chrome/browser/ui/android/strings:ui_strings_grd",
     "//chrome/browser/ui/messages/android:java",
diff --git a/chrome/android/features/vr/BUILD.gn b/chrome/android/features/vr/BUILD.gn
index 56cb5bb..54ec251c 100644
--- a/chrome/android/features/vr/BUILD.gn
+++ b/chrome/android/features/vr/BUILD.gn
@@ -76,6 +76,7 @@
     "//chrome/browser/flags:java",
     "//chrome/browser/preferences:java",
     "//chrome/browser/profiles/android:java",
+    "//chrome/browser/tab:java",
     "//chrome/browser/util:java",
     "//components/browser_ui/modaldialog/android:java",
     "//components/embedder_support/android:content_view_java",
diff --git a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
index 019bbb1..273b5d6 100644
--- a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
+++ b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
@@ -47,6 +47,7 @@
 import org.chromium.chrome.browser.tab.TabAssociatedApp;
 import org.chromium.chrome.browser.tab.TabBrowserControlsConstraintsHelper;
 import org.chromium.chrome.browser.tab.TabCreationState;
+import org.chromium.chrome.browser.tab.TabImpl;
 import org.chromium.chrome.browser.tab.TabLaunchType;
 import org.chromium.chrome.browser.tab.TabObserver;
 import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
@@ -536,7 +537,7 @@
         // Reparent all existing tabs.
         for (TabModel model : mActivity.getTabModelSelector().getModels()) {
             for (int i = 0; i < model.getCount(); ++i) {
-                model.getTabAt(i).updateAttachment(window, null);
+                ((TabImpl) model.getTabAt(i)).updateAttachment(window, null);
             }
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/FakeboxDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/FakeboxDelegate.java
index 8fca74ce..9f2bb0a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/FakeboxDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/FakeboxDelegate.java
@@ -27,14 +27,6 @@
             boolean shouldBeFocused, @Nullable String pastedText, @OmniboxFocusReason int reason);
 
     /**
-     * Performs a search query on the current {@link Tab}.  This calls {@link
-     * TemplateUrlService#getUrlForSearchQuery(String)} to get a url based on {@code query} and
-     * loads that url in the current {@link Tab}.
-     * @param query The {@link String} that represents the text query that should be searched for.
-     */
-    void performSearchQuery(String query);
-
-    /**
      * @return Whether the URL bar is currently focused.
      */
     boolean isUrlBarFocused();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
index 6cd6e7b2..11eecb3b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -220,12 +220,6 @@
         }
 
         @Override
-        public void performSearchQuery(String query) {
-            if (mFakeboxDelegate == null) return;
-            mFakeboxDelegate.performSearchQuery(query);
-        }
-
-        @Override
         public boolean isCurrentPage() {
             if (mIsDestroyed) return false;
             if (mFakeboxDelegate == null) return false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
index 5de63a5..6a95ae84 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -267,11 +267,10 @@
         setSearchProviderInfo(searchProviderHasLogo, searchProviderIsGoogle);
         mSearchProviderLogoView.showSearchProviderInitialView();
 
-        mQueryTileSection = new QueryTileSection(findViewById(R.id.query_tiles),
-                mSearchBoxCoordinator, profile, mManager::performSearchQuery);
+        mQueryTileSection = new QueryTileSection(
+                findViewById(R.id.query_tiles), mSearchBoxCoordinator, profile);
 
-        mTileGroup.startObserving(
-                getMaxRowsForMostVisitedTiles() * getMaxColumnsForMostVisitedTiles());
+        mTileGroup.startObserving(getMaxTileRows() * getMaxTileColumns());
 
         VrModuleProvider.registerVrModeObserver(this);
         if (VrModuleProvider.getDelegate().isInVr()) onEnterVr();
@@ -786,15 +785,15 @@
         }
     }
 
-    private int getMaxRowsForMostVisitedTiles() {
-        return mQueryTileSection != null && mQueryTileSection.shouldConsiderAsSmallScreen() ? 1 : 2;
+    private static int getMaxTileRows() {
+        return 2;
     }
 
     /**
      * Determines The maximum number of tiles to try and fit in a row. On smaller screens, there
      * may not be enough space to fit all of them.
      */
-    private int getMaxColumnsForMostVisitedTiles() {
+    private int getMaxTileColumns() {
         return 4;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
index 7451c42..330bee2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -78,12 +78,6 @@
         void focusSearchBox(boolean beginVoiceSearch, String pastedText);
 
         /**
-         * Performs a search query on the current {@link Tab}.
-         * @param query The {@link String} representing the query text.
-         */
-        void performSearchQuery(String query);
-
-        /**
          * @return whether the {@link NewTabPage} associated with this manager is the current page
          * displayed to the user.
          */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index 9c4f4e4..1b4b961 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -66,6 +66,7 @@
 import org.chromium.chrome.browser.util.AccessibilityUtil;
 import org.chromium.components.browser_ui.styles.ChromeColors;
 import org.chromium.components.browser_ui.widget.CompositeTouchDelegate;
+import org.chromium.components.search_engines.TemplateUrlService;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.common.ResourceRequestBody;
 import org.chromium.ui.base.DeviceFormFactor;
@@ -729,8 +730,14 @@
         // When we restore tabs, we focus the selected tab so the URL of the page shows.
     }
 
-    @Override
-    public void performSearchQuery(String query) {
+    /**
+     * Performs a search query on the current {@link Tab}.  This calls
+     * {@link TemplateUrlService#getUrlForSearchQuery(String)} to get a url based on {@code query}
+     * and loads that url in the current {@link Tab}.
+     * @param query The {@link String} that represents the text query that should be searched for.
+     */
+    @VisibleForTesting
+    public void performSearchQueryForTest(String query) {
         if (TextUtils.isEmpty(query)) return;
 
         String queryUrl = TemplateUrlServiceFactory.get().getUrlForSearchQuery(query);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/query_tiles/QueryTileSection.java b/chrome/android/java/src/org/chromium/chrome/browser/query_tiles/QueryTileSection.java
index 7f8ef90e..e7dc62ae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/query_tiles/QueryTileSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/query_tiles/QueryTileSection.java
@@ -13,8 +13,6 @@
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.ntp.search.SearchBoxCoordinator;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.ui.display.DisplayAndroid;
-import org.chromium.ui.display.DisplayUtil;
 
 import java.util.List;
 
@@ -24,24 +22,17 @@
  * section.
  */
 public class QueryTileSection {
-    private static final String QUERY_TILES_SHORTEN_MOST_VISITED_TILES_FOR_SMALL_SCREEN =
-            "shorten_most_visited_tiles_for_small_screen";
-    private static final int SMALL_SCREEN_HEIGHT_THRESHOLD_DP = 600;
-
     private final ViewGroup mQueryTileSectionView;
     private final SearchBoxCoordinator mSearchBoxCoordinator;
-    private final Callback<String> mSubmitQueryCallback;
     private QueryTileCoordinator mQueryTileCoordinator;
     private TileProvider mTileProvider;
 
     /** Constructor. */
     public QueryTileSection(ViewGroup queryTileSectionView,
-            SearchBoxCoordinator searchBoxCoordinator, Profile profile,
-            Callback<String> performSearchQueryCallback) {
+            SearchBoxCoordinator searchBoxCoordinator, Profile profile) {
         mQueryTileSectionView = queryTileSectionView;
         mSearchBoxCoordinator = searchBoxCoordinator;
-        mSubmitQueryCallback = performSearchQueryCallback;
-        if (!isFeatureEnabled()) return;
+        if (!ChromeFeatureList.isEnabled(ChromeFeatureList.QUERY_TILES)) return;
 
         mTileProvider = TileProviderFactory.getForProfile(profile);
         mQueryTileCoordinator = QueryTileCoordinatorFactory.create(
@@ -52,46 +43,15 @@
     }
 
     private void onTileClicked(Tile tile) {
-        if (tile == null) {
-            mTileProvider.getQueryTiles(this::setTiles);
-        } else {
-            boolean isLastLevelTile = tile.children.isEmpty();
-            setTiles(tile.children);
-            if (isLastLevelTile) {
-                mSubmitQueryCallback.onResult(tile.queryText);
-            } else {
-                // TODO(shaktisahu): Show chip on fakebox;
-            }
-        }
-    }
+        mTileProvider.getQueryTiles(tiles -> {
+            mQueryTileCoordinator.setTiles(tiles);
+            mQueryTileSectionView.setVisibility(tiles.isEmpty() ? View.GONE : View.VISIBLE);
+        });
 
-    private void setTiles(List<Tile> tiles) {
-        mQueryTileCoordinator.setTiles(tiles);
-        mQueryTileSectionView.setVisibility(tiles.isEmpty() ? View.GONE : View.VISIBLE);
+        if (tile != null) mSearchBoxCoordinator.setSearchText(tile.queryText);
     }
 
     private void getVisuals(Tile tile, Callback<List<Bitmap>> callback) {
         mTileProvider.getVisuals(tile.id, callback);
     }
-
-    /**
-     * @return Whether the screen height is small. Used for shortening the most visited tiles
-     *         section on NTP so that feed is still visible above the fold.
-     */
-    public boolean shouldConsiderAsSmallScreen() {
-        if (!isFeatureEnabled()) return false;
-        boolean shortenMostVisitedTiles = ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
-                ChromeFeatureList.QUERY_TILES,
-                QUERY_TILES_SHORTEN_MOST_VISITED_TILES_FOR_SMALL_SCREEN, false);
-        if (!shortenMostVisitedTiles) return false;
-
-        DisplayAndroid display =
-                DisplayAndroid.getNonMultiDisplay(mQueryTileSectionView.getContext());
-        int screenHeightDp = DisplayUtil.pxToDp(display, display.getDisplayHeight());
-        return screenHeightDp < SMALL_SCREEN_HEIGHT_THRESHOLD_DP;
-    }
-
-    private static boolean isFeatureEnabled() {
-        return ChromeFeatureList.isEnabled(ChromeFeatureList.QUERY_TILES);
-    }
-}
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/FourStateCookieSettingsPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/FourStateCookieSettingsPreference.java
index c5bfbdd..7ba71be 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/FourStateCookieSettingsPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/FourStateCookieSettingsPreference.java
@@ -21,8 +21,6 @@
 import org.chromium.components.browser_ui.widget.text.TextViewWithCompoundDrawables;
 import org.chromium.components.content_settings.CookieControlsMode;
 
-import java.util.Arrays;
-
 /**
  * A 4-state radio group Preference used for the Cookies subpage of SiteSettings.
  */
@@ -36,14 +34,25 @@
         BLOCK
     }
 
-    // Signals used to determine the view and button states.
-    private boolean mCookiesContentSettingEnforced;
-    private boolean mThirdPartyBlockingEnforced;
-    private boolean mAllowCookies;
-    private boolean mBlockThirdPartyCookies;
-    // An enum indicating when to block third-party cookies.
-    private @CookieControlsMode int mCookieControlsMode;
-    private CookieSettingsState mState = CookieSettingsState.UNINITIALIZED;
+    /**
+     * Signals used to determine the view and button states.
+     */
+    public static class Params {
+        // Whether the cookies content setting is enabled.
+        public boolean allowCookies;
+        //  Whether third-party blocking is enabled.
+        public boolean blockThirdPartyCookies;
+        // An enum indicating when to block third-party cookies.
+        public @CookieControlsMode int cookieControlsMode;
+
+        // Whether the cookies content setting is enforced.
+        public boolean cookiesContentSettingEnforced;
+        //  Whether third-party blocking is enforced.
+        public boolean thirdPartyBlockingEnforced;
+    }
+
+    // Keeps the params that are applied to the UI if the params are set before the UI is ready.
+    private Params mInitializationParams;
 
     // UI Elements.
     private RadioButtonWithDescription mAllowButton;
@@ -66,23 +75,12 @@
 
     /**
      * Sets the cookie settings state and updates the radio buttons.
-     * @param cookiesContentSettingEnforced Whether the cookies content setting is enforced.
-     * @param thirdPartyBlockingEnforced Whether third-party blocking is enforced.
-     * @param allowCookies Whether the cookies content setting is enabled.
-     * @param blockThirdPartyCookies Whether third-party blocking is enabled.
-     * @param cookieControlsMode The CookieControlsMode enum for the current cookie settings state.
      */
-    public void setState(boolean cookiesContentSettingEnforced, boolean thirdPartyBlockingEnforced,
-            boolean allowCookies, boolean blockThirdPartyCookies,
-            @CookieControlsMode int cookieControlsMode) {
-        mCookiesContentSettingEnforced = cookiesContentSettingEnforced;
-        mThirdPartyBlockingEnforced = thirdPartyBlockingEnforced;
-        mAllowCookies = allowCookies;
-        mBlockThirdPartyCookies = blockThirdPartyCookies;
-        mCookieControlsMode = cookieControlsMode;
-
+    public void setState(Params state) {
         if (mRadioGroup != null) {
-            setRadioButtons();
+            configureRadioButtons(state);
+        } else {
+            mInitializationParams = state;
         }
     }
 
@@ -90,22 +88,30 @@
      * @return The state that is currently selected.
      */
     public CookieSettingsState getState() {
-        return mState;
+        if (mRadioGroup == null && mInitializationParams == null) {
+            return CookieSettingsState.UNINITIALIZED;
+        }
+
+        // Calculate the state from mInitializationParams if the UI is not initialized yet.
+        if (mInitializationParams != null) {
+            return getActiveState(mInitializationParams);
+        }
+
+        if (mAllowButton.isChecked()) {
+            return CookieSettingsState.ALLOW;
+        } else if (mBlockThirdPartyIncognitoButton.isChecked()) {
+            return CookieSettingsState.BLOCK_THIRD_PARTY_INCOGNITO;
+        } else if (mBlockThirdPartyButton.isChecked()) {
+            return CookieSettingsState.BLOCK_THIRD_PARTY;
+        } else {
+            assert mBlockButton.isChecked();
+            return CookieSettingsState.BLOCK;
+        }
     }
 
     @Override
     public void onCheckedChanged(RadioGroup group, int checkedId) {
-        if (mAllowButton.isChecked()) {
-            mState = CookieSettingsState.ALLOW;
-        } else if (mBlockThirdPartyIncognitoButton.isChecked()) {
-            mState = CookieSettingsState.BLOCK_THIRD_PARTY_INCOGNITO;
-        } else if (mBlockThirdPartyButton.isChecked()) {
-            mState = CookieSettingsState.BLOCK_THIRD_PARTY;
-        } else if (mBlockButton.isChecked()) {
-            mState = CookieSettingsState.BLOCK;
-        }
-
-        callChangeListener(mState);
+        callChangeListener(getState());
     }
 
     @Override
@@ -128,48 +134,51 @@
         mManagedView.setCompoundDrawablesRelativeWithIntrinsicBounds(
                 managedIcon, drawables[1], drawables[2], drawables[3]);
 
-        setRadioButtons();
+        if (mInitializationParams != null) {
+            configureRadioButtons(mInitializationParams);
+        }
     }
 
-    private RadioButtonWithDescription getActiveRadioButton() {
+    private CookieSettingsState getActiveState(Params params) {
         // These conditions only check the preference combinations that deterministically decide
         // your cookie settings state. In the future we would refactor the backend preferences to
         // reflect the only possible states you can be in
         // (Allow/BlockThirdPartyIncognito/BlockThirdParty/Block), instead of using this
         // combination of multiple signals.
-        if (!mAllowCookies) {
-            mState = CookieSettingsState.BLOCK;
-            return mBlockButton;
-        } else if (mBlockThirdPartyCookies || mCookieControlsMode == CookieControlsMode.ON) {
+        if (!params.allowCookies) {
+            return CookieSettingsState.BLOCK;
+        } else if (params.blockThirdPartyCookies
+                || params.cookieControlsMode == CookieControlsMode.ON) {
             // Having CookieControlsMode.ON is equivalent to having the BLOCK_THIRD_PARTY_COOKIES
             // pref set to enabled, because it means third party cookie blocking is always on.
-            mState = CookieSettingsState.BLOCK_THIRD_PARTY;
-            return mBlockThirdPartyButton;
-        } else if (mCookieControlsMode == CookieControlsMode.INCOGNITO_ONLY) {
-            mState = CookieSettingsState.BLOCK_THIRD_PARTY_INCOGNITO;
-            return mBlockThirdPartyIncognitoButton;
+            return CookieSettingsState.BLOCK_THIRD_PARTY;
+        } else if (params.cookieControlsMode == CookieControlsMode.INCOGNITO_ONLY) {
+            return CookieSettingsState.BLOCK_THIRD_PARTY_INCOGNITO;
         } else {
-            mState = CookieSettingsState.ALLOW;
-            return mAllowButton;
+            return CookieSettingsState.ALLOW;
         }
     }
 
-    private void setRadioButtons() {
+    private void configureRadioButtons(Params params) {
+        assert (mRadioGroup != null);
         mAllowButton.setEnabled(true);
         mBlockThirdPartyIncognitoButton.setEnabled(true);
         mBlockThirdPartyButton.setEnabled(true);
         mBlockButton.setEnabled(true);
-        for (RadioButtonWithDescription button : getEnforcedButtons()) {
+        for (RadioButtonWithDescription button : getEnforcedButtons(params)) {
             button.setEnabled(false);
         }
-        mManagedView.setVisibility((mCookiesContentSettingEnforced || mThirdPartyBlockingEnforced)
+        mManagedView.setVisibility(
+                (params.cookiesContentSettingEnforced || params.thirdPartyBlockingEnforced)
                         ? View.VISIBLE
                         : View.GONE);
 
-        RadioButtonWithDescription button = getActiveRadioButton();
+        RadioButtonWithDescription button = getButton(getActiveState(params));
         // Always want to enable the selected option.
         button.setEnabled(true);
         button.setChecked(true);
+
+        mInitializationParams = null;
     }
 
     /**
@@ -179,27 +188,45 @@
         return args;
     }
 
+    private RadioButtonWithDescription getButton(CookieSettingsState state) {
+        switch (state) {
+            case ALLOW:
+                return mAllowButton;
+            case BLOCK_THIRD_PARTY_INCOGNITO:
+                return mBlockThirdPartyIncognitoButton;
+            case BLOCK_THIRD_PARTY:
+                return mBlockThirdPartyButton;
+            case BLOCK:
+                return mBlockButton;
+            case UNINITIALIZED:
+                assert false;
+                return null;
+        }
+        assert false;
+        return null;
+    }
+
     /**
      * @return An array of radio buttons that have to be disabled as they can't be selected due to
      *         policy restrictions.
      */
-    private RadioButtonWithDescription[] getEnforcedButtons() {
-        if (!mCookiesContentSettingEnforced && !mThirdPartyBlockingEnforced) {
+    private RadioButtonWithDescription[] getEnforcedButtons(Params params) {
+        if (!params.cookiesContentSettingEnforced && !params.thirdPartyBlockingEnforced) {
             return buttons();
         }
-        if (mCookiesContentSettingEnforced && mThirdPartyBlockingEnforced) {
+        if (params.cookiesContentSettingEnforced && params.thirdPartyBlockingEnforced) {
             return buttons(mAllowButton, mBlockThirdPartyIncognitoButton, mBlockThirdPartyButton,
                     mBlockButton);
         }
-        if (mCookiesContentSettingEnforced) {
-            if (mAllowCookies) {
+        if (params.cookiesContentSettingEnforced) {
+            if (params.allowCookies) {
                 return buttons(mBlockButton);
             } else {
                 return buttons(mAllowButton, mBlockThirdPartyIncognitoButton,
                         mBlockThirdPartyButton, mBlockButton);
             }
         }
-        if (mBlockThirdPartyCookies) {
+        if (params.blockThirdPartyCookies) {
             return buttons(mAllowButton, mBlockThirdPartyIncognitoButton);
         } else {
             return buttons(mBlockThirdPartyIncognitoButton, mBlockThirdPartyButton);
@@ -207,24 +234,8 @@
     }
 
     @VisibleForTesting
-    public boolean isStateEnforced(CookieSettingsState state) {
-        RadioButtonWithDescription button;
-        switch (state) {
-            case ALLOW:
-                button = mAllowButton;
-                break;
-            case BLOCK_THIRD_PARTY_INCOGNITO:
-                button = mBlockThirdPartyIncognitoButton;
-                break;
-            case BLOCK_THIRD_PARTY:
-                button = mBlockThirdPartyButton;
-                break;
-            case BLOCK:
-                button = mBlockButton;
-                break;
-            default:
-                return false;
-        }
-        return Arrays.asList(getEnforcedButtons()).contains(button);
+    boolean isButtonEnabledForTesting(CookieSettingsState state) {
+        assert getButton(state) != null;
+        return getButton(state).isEnabled();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/SingleCategorySettings.java b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/SingleCategorySettings.java
index 754ce5e..ef0dbf6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/SingleCategorySettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/SingleCategorySettings.java
@@ -1034,11 +1034,18 @@
     private void configureFourStateCookieToggle(
             FourStateCookieSettingsPreference fourStateCookieToggle) {
         fourStateCookieToggle.setOnPreferenceChangeListener(this);
-        fourStateCookieToggle.setState(mCategory.isManaged(),
-                PrefServiceBridge.getInstance().isManagedPreference(Pref.BLOCK_THIRD_PARTY_COOKIES),
-                WebsitePreferenceBridge.isCategoryEnabled(ContentSettingsType.COOKIES),
-                PrefServiceBridge.getInstance().getBoolean(Pref.BLOCK_THIRD_PARTY_COOKIES),
-                PrefServiceBridge.getInstance().getInteger(Pref.COOKIE_CONTROLS_MODE));
+        FourStateCookieSettingsPreference.Params params =
+                new FourStateCookieSettingsPreference.Params();
+        params.allowCookies =
+                WebsitePreferenceBridge.isCategoryEnabled(ContentSettingsType.COOKIES);
+        params.blockThirdPartyCookies =
+                PrefServiceBridge.getInstance().getBoolean(Pref.BLOCK_THIRD_PARTY_COOKIES);
+        params.cookieControlsMode =
+                PrefServiceBridge.getInstance().getInteger(Pref.COOKIE_CONTROLS_MODE);
+        params.cookiesContentSettingEnforced = mCategory.isManaged();
+        params.thirdPartyBlockingEnforced =
+                PrefServiceBridge.getInstance().isManagedPreference(Pref.BLOCK_THIRD_PARTY_COOKIES);
+        fourStateCookieToggle.setState(params);
     }
 
     private void configureTriStateToggle(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabAssociatedApp.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabAssociatedApp.java
index 0f29641..0f707a1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabAssociatedApp.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabAssociatedApp.java
@@ -6,6 +6,8 @@
 
 import android.text.TextUtils;
 
+import androidx.annotation.Nullable;
+
 import org.chromium.base.ContextUtils;
 import org.chromium.content_public.browser.ImeAdapter;
 import org.chromium.content_public.browser.ImeEventObserver;
@@ -37,8 +39,9 @@
         super(tab);
         tab.addObserver(new EmptyTabObserver() {
             @Override
-            public void onInitialized(Tab tab, TabState tabState) {
-                if (tabState != null) setAppId(tabState.openerAppId);
+            public void onInitialized(
+                    Tab tab, String appId, @Nullable Boolean hasThemeColor, int themeColor) {
+                setAppId(appId);
             }
 
             @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabBrowserControlsConstraintsHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabBrowserControlsConstraintsHelper.java
index 9ad63b1..fa46584 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabBrowserControlsConstraintsHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabBrowserControlsConstraintsHelper.java
@@ -80,7 +80,8 @@
         mConstraintsChangedCallback = (constraints) -> updateEnabledState();
         mTab.addObserver(new EmptyTabObserver() {
             @Override
-            public void onInitialized(Tab tab, TabState tabState) {
+            public void onInitialized(
+                    Tab tab, String appId, @Nullable Boolean hasThemeColor, int themeColor) {
                 updateVisibilityDelegate();
             }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
index 3738986..eeac2c8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
@@ -301,7 +301,14 @@
         return mWindowAndroid;
     }
 
-    @Override
+    /**
+     * Update the attachment state to Window(Activity).
+     * @param window A new {@link WindowAndroid} to attach the tab to. If {@code null},
+     *        the tab is being detached. See {@link ReparentingTask#detach()} for details.
+     * @param tabDelegateFactory The new delegate factory this tab should be using. Can be
+     *        {@code null} even when {@code window} is not, meaning we simply want to swap out
+     *        {@link WindowAndroid} for this tab and keep using the current delegate factory.
+     */
     public void updateAttachment(
             @Nullable WindowAndroid window, @Nullable TabDelegateFactory tabDelegateFactory) {
         // Non-null delegate factory while being detached is not valid.
@@ -845,7 +852,12 @@
             if (mTimestampMillis == INVALID_TIMESTAMP) {
                 mTimestampMillis = System.currentTimeMillis();
             }
-            for (TabObserver observer : mObservers) observer.onInitialized(this, tabState);
+            String appId = tabState != null ? tabState.openerAppId : null;
+            Boolean hasThemeColor = tabState != null ? tabState.hasThemeColor() : null;
+            int themeColor = tabState != null ? tabState.getThemeColor() : 0;
+            for (TabObserver observer : mObservers) {
+                observer.onInitialized(this, appId, hasThemeColor, themeColor);
+            }
             TraceEvent.end("Tab.initialize");
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabThemeColorHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabThemeColorHelper.java
index 5009aeb8..265654db40 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabThemeColorHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabThemeColorHelper.java
@@ -213,13 +213,14 @@
     // TabObserver
 
     @Override
-    public void onInitialized(Tab tab, TabState tabState) {
-        if (tabState == null) return;
+    public void onInitialized(
+            Tab tab, String appId, @Nullable Boolean hasThemeColor, int themeColor) {
+        if (hasThemeColor == null) return;
 
         // Update from TabState.
-        mIsUsingColorFromTabContents = tabState.hasThemeColor();
+        mIsUsingColorFromTabContents = hasThemeColor;
         mIsDefaultColorUsed = !mIsUsingColorFromTabContents;
-        mColor = mIsDefaultColorUsed ? getDefaultColor() : tabState.getThemeColor();
+        mColor = mIsDefaultColorUsed ? getDefaultColor() : themeColor;
         updateIfNeeded(false);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab_activity_glue/ReparentingTask.java b/chrome/android/java/src/org/chromium/chrome/browser/tab_activity_glue/ReparentingTask.java
index ecb778f..1564ee96 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab_activity_glue/ReparentingTask.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab_activity_glue/ReparentingTask.java
@@ -144,7 +144,7 @@
 
         // TabModelSelector of this Tab, if present, gets notified to remove the tab from
         // the TabModel it belonged to.
-        mTab.updateAttachment(null, null);
+        ((TabImpl) mTab).updateAttachment(null, null);
     }
 
     /**
@@ -174,7 +174,7 @@
         // Assert that the tab is currently in detached state.
         assert mTab.getWebContents() == null
                 || mTab.getWebContents().getTopLevelNativeWindow() == null;
-        mTab.updateAttachment(window, tabDelegateFactory);
+        ((TabImpl) mTab).updateAttachment(window, tabDelegateFactory);
         ReparentingTaskJni.get().attachTab(mTab.getWebContents());
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java
index 66a1142..e6883bf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java
@@ -848,9 +848,6 @@
         }
 
         @Override
-        public void performSearchQuery(String query) {}
-
-        @Override
         public void setUrlBarFocus(boolean shouldBeFocused, @Nullable String pastedText,
                 @LocationBar.OmniboxFocusReason int reason) {}
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ShareIntentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ShareIntentTest.java
index 6625573..19af068 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ShareIntentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ShareIntentTest.java
@@ -29,6 +29,7 @@
 import org.chromium.chrome.browser.share.ShareDelegateImpl;
 import org.chromium.chrome.browser.share.ShareHelper;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabImpl;
 import org.chromium.chrome.browser.ui.RootUiCoordinator;
 import org.chromium.chrome.browser.util.ChromeFileProvider;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController;
@@ -183,7 +184,7 @@
             };
         });
         TestThreadUtils.runOnUiThreadBlocking(
-                () -> mockActivity.getActivityTab().updateAttachment(window, null));
+                () -> ((TabImpl) mockActivity.getActivityTab()).updateAttachment(window, null));
 
         TestThreadUtils.runOnUiThreadBlocking(
                 ()
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
index 23495461..67dbe4b0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
@@ -261,7 +261,7 @@
     /**
      * Checks if the button representing the given state matches the managed expectation.
      */
-    private void checkFourStateCookieToggleButtonUnmanaged(final SettingsActivity settingsActivity,
+    private void checkFourStateCookieToggleButtonEnabled(final SettingsActivity settingsActivity,
             final CookieSettingsState state, final boolean expected) {
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             SingleCategorySettings preferences =
@@ -269,8 +269,8 @@
             FourStateCookieSettingsPreference fourStateCookieToggle =
                     (FourStateCookieSettingsPreference) preferences.findPreference(
                             SingleCategorySettings.FOUR_STATE_COOKIE_TOGGLE_KEY);
-            Assert.assertNotEquals("Button should be " + (expected ? "unmanaged" : "managed"),
-                    fourStateCookieToggle.isStateEnforced(state), expected);
+            Assert.assertEquals(state + " button should be " + (expected ? "enabled" : "disabled"),
+                    fourStateCookieToggle.isButtonEnabledForTesting(state), expected);
         });
     }
 
@@ -544,58 +544,57 @@
     }
 
     /**
-     * Set the cookie content setting to managed and ensure the correct radio buttons are enforced.
+     * Set the cookie content setting to allow through policy and ensure the correct radio buttons
+     * are enabled.
      */
     @Test
     @SmallTest
     @Feature({"Preferences"})
     @Policies.Add({ @Policies.Item(key = "DefaultCookiesSetting", string = "1") })
-    public void testDefaultCookiesSettingManagedTrue() throws Exception {
+    public void testDefaultCookiesSettingManagedAllow() throws Exception {
         checkDefaultCookiesSettingManaged(true);
         checkThirdPartyCookieBlockingManaged(false);
-        // The ContentSetting is managed (and set to true) while ThirdPartyCookieBlocking is not
-        // managed. This means that every button other than BLOCKED is unmanaged.
+        // The ContentSetting is managed (and set to ALLOW) while ThirdPartyCookieBlocking is not
+        // managed. This means that every button other than BLOCK is enabled.
         SettingsActivity settingsActivity =
                 SiteSettingsTestUtils.startSiteSettingsCategory(SiteSettingsCategory.Type.COOKIES);
-        checkFourStateCookieToggleButtonUnmanaged(
-                settingsActivity, CookieSettingsState.ALLOW, true);
-        checkFourStateCookieToggleButtonUnmanaged(
+        checkFourStateCookieToggleButtonEnabled(settingsActivity, CookieSettingsState.ALLOW, true);
+        checkFourStateCookieToggleButtonEnabled(
                 settingsActivity, CookieSettingsState.BLOCK_THIRD_PARTY_INCOGNITO, true);
-        checkFourStateCookieToggleButtonUnmanaged(
+        checkFourStateCookieToggleButtonEnabled(
                 settingsActivity, CookieSettingsState.BLOCK_THIRD_PARTY, true);
-        checkFourStateCookieToggleButtonUnmanaged(
-                settingsActivity, CookieSettingsState.BLOCK, false);
+        checkFourStateCookieToggleButtonEnabled(settingsActivity, CookieSettingsState.BLOCK, false);
         settingsActivity.finish();
     }
 
     /**
-     * Set the cookie content setting to managed and ensure the correct radio buttons are enforced.
+     * Set the cookie content setting to block through a policy and ensure the correct radio buttons
+     * are enabled.
      */
     @Test
     @SmallTest
     @Feature({"Preferences"})
     @Policies.Add({ @Policies.Item(key = "DefaultCookiesSetting", string = "2") })
-    public void testDefaultCookiesSettingManagedFalse() throws Exception {
+    public void testDefaultCookiesSettingManagedBlock() {
         checkDefaultCookiesSettingManaged(true);
         checkThirdPartyCookieBlockingManaged(false);
-        // The ContentSetting is managed (and set to false) while ThirdPartyCookieBlocking is not
+        // The ContentSetting is managed (and set to BLOCK) while ThirdPartyCookieBlocking is not
         // managed. This means cookies should always be blocked, so the user cannot choose any other
-        // options and all buttons should be managed.
+        // options and all buttons except the active one should be disabled.
         SettingsActivity settingsActivity =
                 SiteSettingsTestUtils.startSiteSettingsCategory(SiteSettingsCategory.Type.COOKIES);
-        checkFourStateCookieToggleButtonUnmanaged(
-                settingsActivity, CookieSettingsState.ALLOW, false);
-        checkFourStateCookieToggleButtonUnmanaged(
+        checkFourStateCookieToggleButtonEnabled(settingsActivity, CookieSettingsState.ALLOW, false);
+        checkFourStateCookieToggleButtonEnabled(
                 settingsActivity, CookieSettingsState.BLOCK_THIRD_PARTY_INCOGNITO, false);
-        checkFourStateCookieToggleButtonUnmanaged(
+        checkFourStateCookieToggleButtonEnabled(
                 settingsActivity, CookieSettingsState.BLOCK_THIRD_PARTY, false);
-        checkFourStateCookieToggleButtonUnmanaged(
-                settingsActivity, CookieSettingsState.BLOCK, false);
+        checkFourStateCookieToggleButtonEnabled(settingsActivity, CookieSettingsState.BLOCK, true);
         settingsActivity.finish();
     }
 
     /**
-     * Set third-party cookie blocking to managed and ensure the correct radio buttons are enforced.
+     * Enable third-party cookie blocking through policy and ensure the correct radio buttons are
+     * enabled.
      */
     @Test
     @SmallTest
@@ -607,22 +606,21 @@
         checkThirdPartyCookieBlockingManaged(true);
         // ThirdPartyCookieBlocking is managed (and set to true) while the ContentSetting is not
         // managed. This means a user can choose only between BLOCK_THIRD_PARTY and BLOCK, so only
-        // these should be unmanaged.
+        // these should be enabled.
         SettingsActivity settingsActivity =
                 SiteSettingsTestUtils.startSiteSettingsCategory(SiteSettingsCategory.Type.COOKIES);
-        checkFourStateCookieToggleButtonUnmanaged(
-                settingsActivity, CookieSettingsState.ALLOW, false);
-        checkFourStateCookieToggleButtonUnmanaged(
+        checkFourStateCookieToggleButtonEnabled(settingsActivity, CookieSettingsState.ALLOW, false);
+        checkFourStateCookieToggleButtonEnabled(
                 settingsActivity, CookieSettingsState.BLOCK_THIRD_PARTY_INCOGNITO, false);
-        checkFourStateCookieToggleButtonUnmanaged(
+        checkFourStateCookieToggleButtonEnabled(
                 settingsActivity, CookieSettingsState.BLOCK_THIRD_PARTY, true);
-        checkFourStateCookieToggleButtonUnmanaged(
-                settingsActivity, CookieSettingsState.BLOCK, true);
+        checkFourStateCookieToggleButtonEnabled(settingsActivity, CookieSettingsState.BLOCK, true);
         settingsActivity.finish();
     }
 
     /**
-     * Set third-party cookie blocking to managed and ensure the correct radio buttons are enforced.
+     * Disable third-party cookie blocking through policy and ensure the correct radio buttons are
+     * enabled.
      */
     @Test
     @SmallTest
@@ -634,23 +632,21 @@
         checkThirdPartyCookieBlockingManaged(true);
         // ThirdPartyCookieBlocking is managed (and set to false) while the ContentSetting is not
         // managed. This means a user can only choose to ALLOW all cookies or BLOCK all cookies, so
-        // only these should be unmanaged.
+        // only these should be enabled.
         SettingsActivity settingsActivity =
                 SiteSettingsTestUtils.startSiteSettingsCategory(SiteSettingsCategory.Type.COOKIES);
-        checkFourStateCookieToggleButtonUnmanaged(
-                settingsActivity, CookieSettingsState.ALLOW, true);
-        checkFourStateCookieToggleButtonUnmanaged(
+        checkFourStateCookieToggleButtonEnabled(settingsActivity, CookieSettingsState.ALLOW, true);
+        checkFourStateCookieToggleButtonEnabled(
                 settingsActivity, CookieSettingsState.BLOCK_THIRD_PARTY_INCOGNITO, false);
-        checkFourStateCookieToggleButtonUnmanaged(
+        checkFourStateCookieToggleButtonEnabled(
                 settingsActivity, CookieSettingsState.BLOCK_THIRD_PARTY, false);
-        checkFourStateCookieToggleButtonUnmanaged(
-                settingsActivity, CookieSettingsState.BLOCK, true);
+        checkFourStateCookieToggleButtonEnabled(settingsActivity, CookieSettingsState.BLOCK, true);
         settingsActivity.finish();
     }
 
     /**
-     * Set both the cookie content setting and third-party cookie blocking to managed and ensure the
-     * correct radio buttons are enforced.
+     * Set both the cookie content setting and third-party cookie blocking through policy and ensure
+     * the correct radio buttons are enabled.
      */
     @Test
     @SmallTest
@@ -664,18 +660,16 @@
         checkDefaultCookiesSettingManaged(true);
         checkThirdPartyCookieBlockingManaged(true);
         // The ContentSetting and ThirdPartyCookieBlocking are managed. This means a user has a
-        // fixed setting for cookies that they cannot change. Therefore, all buttons should be
-        // managed.
+        // fixed setting for cookies that they cannot change. Therefore, all buttons except the
+        // selected one should be disabled.
         SettingsActivity settingsActivity =
                 SiteSettingsTestUtils.startSiteSettingsCategory(SiteSettingsCategory.Type.COOKIES);
-        checkFourStateCookieToggleButtonUnmanaged(
-                settingsActivity, CookieSettingsState.ALLOW, false);
-        checkFourStateCookieToggleButtonUnmanaged(
+        checkFourStateCookieToggleButtonEnabled(settingsActivity, CookieSettingsState.ALLOW, true);
+        checkFourStateCookieToggleButtonEnabled(
                 settingsActivity, CookieSettingsState.BLOCK_THIRD_PARTY_INCOGNITO, false);
-        checkFourStateCookieToggleButtonUnmanaged(
+        checkFourStateCookieToggleButtonEnabled(
                 settingsActivity, CookieSettingsState.BLOCK_THIRD_PARTY, false);
-        checkFourStateCookieToggleButtonUnmanaged(
-                settingsActivity, CookieSettingsState.BLOCK, false);
+        checkFourStateCookieToggleButtonEnabled(settingsActivity, CookieSettingsState.BLOCK, false);
         settingsActivity.finish();
     }
 
@@ -689,17 +683,15 @@
         checkDefaultCookiesSettingManaged(false);
         checkThirdPartyCookieBlockingManaged(false);
         // The ContentSetting and ThirdPartyCookieBlocking are unmanaged. This means all buttons
-        // should be unmanaged.
+        // should be enabled.
         SettingsActivity settingsActivity =
                 SiteSettingsTestUtils.startSiteSettingsCategory(SiteSettingsCategory.Type.COOKIES);
-        checkFourStateCookieToggleButtonUnmanaged(
-                settingsActivity, CookieSettingsState.ALLOW, true);
-        checkFourStateCookieToggleButtonUnmanaged(
+        checkFourStateCookieToggleButtonEnabled(settingsActivity, CookieSettingsState.ALLOW, true);
+        checkFourStateCookieToggleButtonEnabled(
                 settingsActivity, CookieSettingsState.BLOCK_THIRD_PARTY_INCOGNITO, true);
-        checkFourStateCookieToggleButtonUnmanaged(
+        checkFourStateCookieToggleButtonEnabled(
                 settingsActivity, CookieSettingsState.BLOCK_THIRD_PARTY, true);
-        checkFourStateCookieToggleButtonUnmanaged(
-                settingsActivity, CookieSettingsState.BLOCK, true);
+        checkFourStateCookieToggleButtonEnabled(settingsActivity, CookieSettingsState.BLOCK, true);
         settingsActivity.finish();
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tab/TabBrowserControlsConstraintsHelperTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tab/TabBrowserControlsConstraintsHelperTest.java
index 3ce26d9..38dca84 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/tab/TabBrowserControlsConstraintsHelperTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/tab/TabBrowserControlsConstraintsHelperTest.java
@@ -75,7 +75,7 @@
         initHelper();
         Mockito.verify(mDelegateFactory, Mockito.never())
                 .createBrowserControlsVisibilityDelegate(mTab);
-        mRegisteredTabObserver.onInitialized(mTab, null);
+        mRegisteredTabObserver.onInitialized(mTab, null, null, 0);
         Mockito.verify(mDelegateFactory, Mockito.times(1))
                 .createBrowserControlsVisibilityDelegate(mTab);
         verifyUpdateState(BrowserControlsState.BOTH);
@@ -126,7 +126,7 @@
         initHelper();
         Mockito.verify(mDelegateFactory, Mockito.never())
                 .createBrowserControlsVisibilityDelegate(mTab);
-        mRegisteredTabObserver.onInitialized(mTab, null);
+        mRegisteredTabObserver.onInitialized(mTab, null, null, 0);
         Mockito.verify(mDelegateFactory).createBrowserControlsVisibilityDelegate(mTab);
         Mockito.verifyNoMoreInteractions(mDelegateFactory);
         verifyUpdateState(BrowserControlsState.BOTH);
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index ca39bc9..e8d8e2e 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -4740,6 +4740,13 @@
 #endif  // OS_CHROMEOS
 
 #if defined(OS_CHROMEOS)
+    {"enable-edu-coexistence-consent-log",
+     flag_descriptions::kEnableEduCoexistenceConsentLogName,
+     flag_descriptions::kEnableEduCoexistenceConsentLogDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(chromeos::features::kEduCoexistenceConsentLog)},
+#endif  // OS_CHROMEOS
+
+#if defined(OS_CHROMEOS)
     {"enable-assistant-routines",
      flag_descriptions::kEnableAssistantRoutinesName,
      flag_descriptions::kEnableAssistantRoutinesDescription, kOsCrOS,
diff --git a/chrome/browser/android/examples/custom_tabs_client/BUILD.gn b/chrome/browser/android/examples/custom_tabs_client/BUILD.gn
new file mode 100644
index 0000000..7b21ce5
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/BUILD.gn
@@ -0,0 +1,79 @@
+# Copyright 2015 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/rules.gni")
+
+android_resources("chrome_tabs_client_example_apk_resources") {
+  sources = [
+    "src/res/anim/slide_in_left.xml",
+    "src/res/anim/slide_in_right.xml",
+    "src/res/anim/slide_out_left.xml",
+    "src/res/anim/slide_out_right.xml",
+    "src/res/drawable-hdpi/cover.jpg",
+    "src/res/drawable-hdpi/ic_arrow_back.png",
+    "src/res/drawable-hdpi/ic_launcher.png",
+    "src/res/drawable-hdpi/ic_notification_icon.png",
+    "src/res/drawable-hdpi/ic_play.png",
+    "src/res/drawable-hdpi/ic_share.png",
+    "src/res/drawable-hdpi/ic_stop.png",
+    "src/res/drawable-mdpi/cover.jpg",
+    "src/res/drawable-mdpi/ic_arrow_back.png",
+    "src/res/drawable-mdpi/ic_launcher.png",
+    "src/res/drawable-mdpi/ic_notification_icon.png",
+    "src/res/drawable-mdpi/ic_play.png",
+    "src/res/drawable-mdpi/ic_share.png",
+    "src/res/drawable-mdpi/ic_stop.png",
+    "src/res/drawable-xhdpi/cover.jpg",
+    "src/res/drawable-xhdpi/ic_arrow_back.png",
+    "src/res/drawable-xhdpi/ic_launcher.png",
+    "src/res/drawable-xhdpi/ic_notification_icon.png",
+    "src/res/drawable-xhdpi/ic_play.png",
+    "src/res/drawable-xhdpi/ic_share.png",
+    "src/res/drawable-xhdpi/ic_stop.png",
+    "src/res/drawable-xxhdpi/cover.jpg",
+    "src/res/drawable-xxhdpi/ic_arrow_back.png",
+    "src/res/drawable-xxhdpi/ic_launcher.png",
+    "src/res/drawable-xxhdpi/ic_notification_icon.png",
+    "src/res/drawable-xxhdpi/ic_play.png",
+    "src/res/drawable-xxhdpi/ic_share.png",
+    "src/res/drawable-xxhdpi/ic_stop.png",
+    "src/res/drawable-xxxhdpi/ic_arrow_back.png",
+    "src/res/drawable-xxxhdpi/ic_launcher.png",
+    "src/res/drawable-xxxhdpi/ic_share.png",
+    "src/res/layout/main.xml",
+    "src/res/layout/remote_view.xml",
+    "src/res/raw/amazing_grace.mp3",
+    "src/res/values/strings.xml",
+  ]
+  android_manifest = "src/AndroidManifest.xml"
+  custom_package = "org.chromium.customtabsclient"
+  deps = [ "//third_party/android_deps:android_support_v7_appcompat_java" ]
+}
+
+android_apk("custom_tabs_client_example_apk") {
+  sources = [
+    "src/java/org/chromium/customtabsclient/BottomBarManager.java",
+    "src/java/org/chromium/customtabsclient/BrowserActionsReceiver.java",
+    "src/java/org/chromium/customtabsclient/MainActivity.java",
+    "src/java/org/chromium/customtabsclient/SessionHelper.java",
+    "src/java/org/chromium/customtabsclient/shared/CustomTabsHelper.java",
+    "src/java/org/chromium/customtabsclient/shared/KeepAliveService.java",
+    "src/java/org/chromium/customtabsclient/shared/ServiceConnection.java",
+    "src/java/org/chromium/customtabsclient/shared/ServiceConnectionCallback.java",
+  ]
+
+  android_manifest = "src/AndroidManifest.xml"
+  min_sdk_version = 19
+  target_sdk_version = 21
+  apk_name = "CustomTabsClientExample"
+
+  deps = [
+    ":chrome_tabs_client_example_apk_resources",
+    "//third_party/android_deps:android_support_v7_appcompat_java",
+    "//third_party/android_deps:androidx_annotation_annotation_java",
+    "//third_party/android_deps:androidx_appcompat_appcompat_java",
+    "//third_party/android_deps:androidx_lifecycle_lifecycle_common_java",
+    "//third_party/android_sdk/androidx_browser:androidx_browser_java",
+  ]
+}
diff --git a/chrome/browser/android/examples/custom_tabs_client/OWNERS b/chrome/browser/android/examples/custom_tabs_client/OWNERS
new file mode 100644
index 0000000..0922ed2
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/OWNERS
@@ -0,0 +1,4 @@
+file://chrome/android/java/src/org/chromium/chrome/browser/customtabs/OWNERS
+
+# COMPONENT: UI>Browser>Mobile>CustomTabs
+# OS: Android
\ No newline at end of file
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/AndroidManifest.xml b/chrome/browser/android/examples/custom_tabs_client/src/AndroidManifest.xml
new file mode 100644
index 0000000..f5d3ae19a
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/AndroidManifest.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 Google Inc. All Rights Reserved.
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="org.chromium.customtabsclient"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="19"
+        android:targetSdkVersion="21" />
+
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:allowBackup="false"
+        android:theme="@style/Theme.AppCompat.Light" >
+
+        <activity
+            android:name="org.chromium.customtabsclient.MainActivity"
+            android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW"/>
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE"/>
+                <data android:scheme="https"
+                      android:host="www.example.com"
+                      android:pathPrefix="/notifications"/>
+            </intent-filter>
+
+        </activity>
+        <service
+            android:name=".shared.KeepAliveService"
+            android:exported="true"/>
+        <receiver android:name=".BottomBarManager"/>
+
+
+        <service
+            android:name="android.support.customtabs.trusted.TrustedWebActivityService"
+            android:enabled="true"
+            android:exported="true">
+
+            <meta-data android:name="android.support.customtabs.trusted.SMALL_ICON"
+                       android:resource="@drawable/ic_notification_icon" />
+
+            <intent-filter>
+                <action android:name="android.support.customtabs.trusted.TRUSTED_WEB_ACTIVITY_SERVICE"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </service>
+    </application>
+</manifest>
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/BottomBarManager.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/BottomBarManager.java
new file mode 100644
index 0000000..7ad3574
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/BottomBarManager.java
@@ -0,0 +1,86 @@
+// Copyright 2015 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.customtabsclient;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.media.MediaPlayer;
+import android.widget.RemoteViews;
+import android.widget.Toast;
+
+import androidx.browser.customtabs.CustomTabsIntent;
+import androidx.browser.customtabs.CustomTabsSession;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * A {@link BroadcastReceiver} that manages the interaction with the active Custom Tab.
+ */
+public class BottomBarManager extends BroadcastReceiver {
+    private static WeakReference<MediaPlayer> sMediaPlayerWeakRef;
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        int clickedId = intent.getIntExtra(CustomTabsIntent.EXTRA_REMOTEVIEWS_CLICKED_ID, -1);
+        Toast.makeText(context, "Current URL " + intent.getDataString() + "\nClicked id "
+                + clickedId, Toast.LENGTH_SHORT).show();
+
+        CustomTabsSession session = SessionHelper.getCurrentSession();
+        if (session == null) return;
+
+        if (clickedId == R.id.play_pause) {
+            MediaPlayer player = sMediaPlayerWeakRef.get();
+            if (player != null) {
+                boolean isPlaying = player.isPlaying();
+                if (isPlaying) player.pause();
+                else player.start();
+                // Update the play/stop icon to respect the current state.
+                session.setSecondaryToolbarViews(createRemoteViews(context, isPlaying),
+                        getClickableIDs(), getOnClickPendingIntent(context));
+            }
+        } else if (clickedId == R.id.cover) {
+            // Clicking on the cover image will dismiss the bottom bar.
+            session.setSecondaryToolbarViews(null, null, null);
+        }
+    }
+
+    /**
+     * Creates a RemoteViews that will be shown as the bottom bar of the custom tab.
+     * @param showPlayIcon If true, a play icon will be shown, otherwise show a pause icon.
+     * @return The created RemoteViews instance.
+     */
+    public static RemoteViews createRemoteViews(Context context, boolean showPlayIcon) {
+        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.remote_view);
+
+        int iconRes = showPlayIcon ? R.drawable.ic_play : R.drawable.ic_stop;
+        remoteViews.setImageViewResource(R.id.play_pause, iconRes);
+        return remoteViews;
+    }
+
+    /**
+     * @return A list of View ids, the onClick event of which is handled by Custom Tab.
+     */
+    public static int[] getClickableIDs() {
+        return new int[]{R.id.play_pause, R.id.cover};
+    }
+
+    /**
+     * @return The PendingIntent that will be triggered when the user clicks on the Views listed by
+     * {@link BottomBarManager#getClickableIDs()}.
+     */
+    public static PendingIntent getOnClickPendingIntent(Context context) {
+        Intent broadcastIntent = new Intent(context, BottomBarManager.class);
+        return PendingIntent.getBroadcast(context, 0, broadcastIntent, 0);
+    }
+
+    /**
+     * Sets the {@link MediaPlayer} to be used when the user clicks on the RemoteViews.
+     */
+    public static void setMediaPlayer(MediaPlayer player) {
+        sMediaPlayerWeakRef = new WeakReference<>(player);
+    }
+}
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/BrowserActionsReceiver.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/BrowserActionsReceiver.java
new file mode 100644
index 0000000..93f6752
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/BrowserActionsReceiver.java
@@ -0,0 +1,22 @@
+// Copyright 2015 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.customtabsclient;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.widget.Toast;
+
+/**
+ * A {@link BroadcastReceiver} that handles the callback if default menu items are chosen from
+ * Browser Actions.
+ */
+public class BrowserActionsReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String toastMsg = "Chosen item Id: " + intent.getDataString();
+        Toast.makeText(context, toastMsg, Toast.LENGTH_SHORT).show();
+    }
+}
\ No newline at end of file
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/MainActivity.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/MainActivity.java
new file mode 100644
index 0000000..d67d86b0
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/MainActivity.java
@@ -0,0 +1,298 @@
+// Copyright 2015 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.customtabsclient;
+
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.v7.app.AppCompatActivity;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import androidx.browser.customtabs.CustomTabsCallback;
+import androidx.browser.customtabs.CustomTabsClient;
+import androidx.browser.customtabs.CustomTabsIntent;
+import androidx.browser.customtabs.CustomTabsServiceConnection;
+import androidx.browser.customtabs.CustomTabsSession;
+
+import org.chromium.customtabsclient.shared.CustomTabsHelper;
+import org.chromium.customtabsclient.shared.ServiceConnection;
+import org.chromium.customtabsclient.shared.ServiceConnectionCallback;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Example client activity for using Chrome Custom Tabs.
+ */
+public class MainActivity
+        extends AppCompatActivity implements OnClickListener, ServiceConnectionCallback {
+    private static final String TAG = "CustomTabsClientExample";
+    private static final String TOOLBAR_COLOR = "#ef6c00";
+
+    private EditText mEditText;
+    private CustomTabsSession mCustomTabsSession;
+    private CustomTabsClient mClient;
+    private CustomTabsServiceConnection mConnection;
+    private String mPackageNameToBind;
+    private Button mConnectButton;
+    private Button mWarmupButton;
+    private Button mMayLaunchButton;
+    private Button mLaunchButton;
+    private MediaPlayer mMediaPlayer;
+
+    /**
+     * Once per second, asks the framework for the process importance, and logs any change.
+     */
+    private Runnable mLogImportance = new Runnable() {
+        private int mPreviousImportance = -1;
+        private boolean mPreviousServiceInUse = false;
+        private Handler mHandler = new Handler(Looper.getMainLooper());
+
+        @Override
+        public void run() {
+            ActivityManager.RunningAppProcessInfo state =
+                    new ActivityManager.RunningAppProcessInfo();
+            ActivityManager.getMyMemoryState(state);
+            int importance = state.importance;
+            boolean serviceInUse = state.importanceReasonCode
+                    == ActivityManager.RunningAppProcessInfo.REASON_SERVICE_IN_USE;
+            if (importance != mPreviousImportance || serviceInUse != mPreviousServiceInUse) {
+                mPreviousImportance = importance;
+                mPreviousServiceInUse = serviceInUse;
+                String message = "New importance = " + importance;
+                if (serviceInUse) message += " (Reason: Service in use)";
+                Log.w(TAG, message);
+            }
+            mHandler.postDelayed(this, 1000);
+        }
+    };
+
+    private static class NavigationCallback extends CustomTabsCallback {
+        @Override
+        public void onNavigationEvent(int navigationEvent, Bundle extras) {
+            Log.w(TAG, "onNavigationEvent: Code = " + navigationEvent);
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+        mEditText = (EditText) findViewById(R.id.edit);
+        mConnectButton = (Button) findViewById(R.id.connect_button);
+        mWarmupButton = (Button) findViewById(R.id.warmup_button);
+        mMayLaunchButton = (Button) findViewById(R.id.may_launch_button);
+        mLaunchButton = (Button) findViewById(R.id.launch_button);
+        Spinner spinner = (Spinner) findViewById(R.id.spinner);
+        mEditText.requestFocus();
+        mConnectButton.setOnClickListener(this);
+        mWarmupButton.setOnClickListener(this);
+        mMayLaunchButton.setOnClickListener(this);
+        mLaunchButton.setOnClickListener(this);
+        mMediaPlayer = MediaPlayer.create(this, R.raw.amazing_grace);
+        findViewById(R.id.register_twa_service).setOnClickListener(this);
+
+        Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com"));
+        PackageManager pm = getPackageManager();
+        List<ResolveInfo> resolvedActivityList = pm.queryIntentActivities(
+                activityIntent, PackageManager.MATCH_ALL);
+        List<Pair<String, String>> packagesSupportingCustomTabs = new ArrayList<>();
+        for (ResolveInfo info : resolvedActivityList) {
+            Intent serviceIntent = new Intent();
+            serviceIntent.setAction("android.support.customtabs.action.CustomTabsService");
+            serviceIntent.setPackage(info.activityInfo.packageName);
+            if (pm.resolveService(serviceIntent, 0) != null) {
+                packagesSupportingCustomTabs.add(
+                        Pair.create(info.loadLabel(pm).toString(), info.activityInfo.packageName));
+            }
+        }
+
+        final ArrayAdapter<Pair<String, String>> adapter = new ArrayAdapter<Pair<String, String>>(
+                this, 0, packagesSupportingCustomTabs) {
+            @Override
+            public View getView(int position, View convertView, ViewGroup parent) {
+                View view = convertView;
+                if (view == null) {
+                    view = LayoutInflater.from(MainActivity.this).inflate(
+                            android.R.layout.simple_list_item_2, parent, false);
+                }
+                Pair<String, String> data = getItem(position);
+                ((TextView) view.findViewById(android.R.id.text1)).setText(data.first);
+                ((TextView) view.findViewById(android.R.id.text2)).setText(data.second);
+                return view;
+            }
+
+            @Override
+            public View getDropDownView(int position, View convertView, ViewGroup parent) {
+                return getView(position, convertView, parent);
+            }
+        };
+        spinner.setAdapter(adapter);
+        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+            @Override
+            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+                Pair<String, String> item = adapter.getItem(position);
+                if (TextUtils.isEmpty(item.second)) {
+                    onNothingSelected(parent);
+                    return;
+                }
+                mPackageNameToBind = item.second;
+            }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> parent) {
+                mPackageNameToBind = null;
+            }
+        });
+
+        mLogImportance.run();
+    }
+
+    @Override
+    protected void onDestroy() {
+        unbindCustomTabsService();
+        super.onDestroy();
+    }
+
+    private CustomTabsSession getSession() {
+        if (mClient == null) {
+            mCustomTabsSession = null;
+        } else if (mCustomTabsSession == null) {
+            mCustomTabsSession = mClient.newSession(new NavigationCallback());
+            SessionHelper.setCurrentSession(mCustomTabsSession);
+        }
+        return mCustomTabsSession;
+    }
+
+    private void bindCustomTabsService() {
+        if (mClient != null) return;
+        if (TextUtils.isEmpty(mPackageNameToBind)) {
+            mPackageNameToBind = CustomTabsHelper.getPackageNameToUse(this);
+            if (mPackageNameToBind == null) return;
+        }
+        mConnection = new ServiceConnection(this);
+        boolean ok = CustomTabsClient.bindCustomTabsService(this, mPackageNameToBind, mConnection);
+        if (ok) {
+            mConnectButton.setEnabled(false);
+        } else {
+            mConnection = null;
+        }
+    }
+
+    private void unbindCustomTabsService() {
+        if (mConnection == null) return;
+        unbindService(mConnection);
+        mClient = null;
+        mCustomTabsSession = null;
+    }
+
+    @Override
+    public void onClick(View v) {
+        String url = mEditText.getText().toString();
+        int viewId = v.getId();
+
+        if (viewId == R.id.connect_button) {
+            bindCustomTabsService();
+        } else if (viewId == R.id.warmup_button) {
+            boolean success = false;
+            if (mClient != null) success = mClient.warmup(0);
+            if (!success) mWarmupButton.setEnabled(false);
+        } else if (viewId == R.id.may_launch_button) {
+            CustomTabsSession session = getSession();
+            boolean success = false;
+            if (mClient != null) success = session.mayLaunchUrl(Uri.parse(url), null, null);
+            if (!success) mMayLaunchButton.setEnabled(false);
+        } else if (viewId == R.id.launch_button) {
+            CustomTabsSession session = getSession();
+            CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(session);
+            builder.setToolbarColor(Color.parseColor(TOOLBAR_COLOR)).setShowTitle(true);
+            prepareMenuItems(builder);
+            prepareActionButton(builder);
+            if (session != null) prepareBottombar(builder);
+            builder.setStartAnimations(this, R.anim.slide_in_right, R.anim.slide_out_left);
+            builder.setExitAnimations(this, R.anim.slide_in_left, R.anim.slide_out_right);
+            builder.setCloseButtonIcon(
+                    BitmapFactory.decodeResource(getResources(), R.drawable.ic_arrow_back));
+            CustomTabsIntent customTabsIntent = builder.build();
+            if (session != null) {
+                CustomTabsHelper.addKeepAliveExtra(this, customTabsIntent.intent);
+            } else {
+                if (!TextUtils.isEmpty(mPackageNameToBind)) {
+                    customTabsIntent.intent.setPackage(mPackageNameToBind);
+                }
+            }
+            customTabsIntent.launchUrl(this, Uri.parse(url));
+        }
+    }
+
+    private void prepareMenuItems(CustomTabsIntent.Builder builder) {
+        Intent menuIntent = new Intent();
+        menuIntent.setClass(getApplicationContext(), this.getClass());
+        // Optional animation configuration when the user clicks menu items.
+        Bundle menuBundle = ActivityOptions.makeCustomAnimation(this, android.R.anim.slide_in_left,
+                android.R.anim.slide_out_right).toBundle();
+        PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0, menuIntent, 0,
+                menuBundle);
+        builder.addMenuItem("Menu entry 1", pi);
+    }
+
+    private void prepareActionButton(CustomTabsIntent.Builder builder) {
+        // An example intent that sends an email.
+        Intent actionIntent = new Intent(Intent.ACTION_SEND);
+        actionIntent.setType("*/*");
+        actionIntent.putExtra(Intent.EXTRA_EMAIL, "example@example.com");
+        actionIntent.putExtra(Intent.EXTRA_SUBJECT, "example");
+        PendingIntent pi = PendingIntent.getActivity(this, 0, actionIntent, 0);
+        Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_share);
+        builder.setActionButton(icon, "send email", pi, true);
+    }
+
+    private void prepareBottombar(CustomTabsIntent.Builder builder) {
+        BottomBarManager.setMediaPlayer(mMediaPlayer);
+        builder.setSecondaryToolbarViews(BottomBarManager.createRemoteViews(this, true),
+                BottomBarManager.getClickableIDs(), BottomBarManager.getOnClickPendingIntent(this));
+    }
+
+    @Override
+    public void onServiceConnected(CustomTabsClient client) {
+        mClient = client;
+        mConnectButton.setEnabled(false);
+        mWarmupButton.setEnabled(true);
+        mMayLaunchButton.setEnabled(true);
+        mLaunchButton.setEnabled(true);
+    }
+
+    @Override
+    public void onServiceDisconnected() {
+        mConnectButton.setEnabled(true);
+        mWarmupButton.setEnabled(false);
+        mMayLaunchButton.setEnabled(false);
+        mLaunchButton.setEnabled(false);
+        mClient = null;
+    }
+}
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/SessionHelper.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/SessionHelper.java
new file mode 100644
index 0000000..98a46d1
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/SessionHelper.java
@@ -0,0 +1,34 @@
+// Copyright 2015 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.customtabsclient;
+
+import android.support.annotation.Nullable;
+
+import androidx.browser.customtabs.CustomTabsSession;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * A class that keeps tracks of the current {@link CustomTabsSession} and helps other components of
+ * the app to get access to the current session.
+ */
+public class SessionHelper {
+    private static WeakReference<CustomTabsSession> sCurrentSession;
+
+    /**
+     * @return The current {@link CustomTabsSession} object.
+     */
+    public static @Nullable CustomTabsSession getCurrentSession() {
+        return sCurrentSession == null ? null : sCurrentSession.get();
+    }
+
+    /**
+     * Sets the current session to the given one.
+     * @param session The current session.
+     */
+    public static void setCurrentSession(CustomTabsSession session) {
+        sCurrentSession = new WeakReference<CustomTabsSession>(session);
+    }
+}
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/CustomTabsHelper.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/CustomTabsHelper.java
new file mode 100644
index 0000000..132769ce
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/CustomTabsHelper.java
@@ -0,0 +1,132 @@
+// Copyright 2015 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.customtabsclient.shared;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper class for Custom Tabs.
+ */
+public class CustomTabsHelper {
+    private static final String TAG = "CustomTabsHelper";
+    static final String STABLE_PACKAGE = "com.android.chrome";
+    static final String BETA_PACKAGE = "com.chrome.beta";
+    static final String DEV_PACKAGE = "com.chrome.dev";
+    static final String LOCAL_PACKAGE = "com.google.android.apps.chrome";
+    private static final String EXTRA_CUSTOM_TABS_KEEP_ALIVE =
+            "android.support.customtabs.extra.KEEP_ALIVE";
+    private static final String ACTION_CUSTOM_TABS_CONNECTION =
+            "android.support.customtabs.action.CustomTabsService";
+
+    private static String sPackageNameToUse;
+
+    private CustomTabsHelper() {}
+
+    public static void addKeepAliveExtra(Context context, Intent intent) {
+        Intent keepAliveIntent = new Intent().setClassName(
+                context.getPackageName(), KeepAliveService.class.getCanonicalName());
+        intent.putExtra(EXTRA_CUSTOM_TABS_KEEP_ALIVE, keepAliveIntent);
+    }
+
+    /**
+     * Goes through all apps that handle VIEW intents and have a warmup service. Picks
+     * the one chosen by the user if there is one, otherwise makes a best effort to return a
+     * valid package name.
+     *
+     * This is <strong>not</strong> threadsafe.
+     *
+     * @param context {@link Context} to use for accessing {@link PackageManager}.
+     * @return The package name recommended to use for connecting to custom tabs related components.
+     */
+    public static String getPackageNameToUse(Context context) {
+        if (sPackageNameToUse != null) return sPackageNameToUse;
+
+        PackageManager pm = context.getPackageManager();
+        // Get default VIEW intent handler.
+        Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com"));
+        ResolveInfo defaultViewHandlerInfo = pm.resolveActivity(activityIntent, 0);
+        String defaultViewHandlerPackageName = null;
+        if (defaultViewHandlerInfo != null) {
+            defaultViewHandlerPackageName = defaultViewHandlerInfo.activityInfo.packageName;
+        }
+
+        // Get all apps that can handle VIEW intents.
+        List<ResolveInfo> resolvedActivityList = pm.queryIntentActivities(activityIntent, 0);
+        List<String> packagesSupportingCustomTabs = new ArrayList<>();
+        for (ResolveInfo info : resolvedActivityList) {
+            Intent serviceIntent = new Intent();
+            serviceIntent.setAction(ACTION_CUSTOM_TABS_CONNECTION);
+            serviceIntent.setPackage(info.activityInfo.packageName);
+            if (pm.resolveService(serviceIntent, 0) != null) {
+                packagesSupportingCustomTabs.add(info.activityInfo.packageName);
+            }
+        }
+
+        // Now packagesSupportingCustomTabs contains all apps that can handle both VIEW intents
+        // and service calls.
+        if (packagesSupportingCustomTabs.isEmpty()) {
+            sPackageNameToUse = null;
+        } else if (packagesSupportingCustomTabs.size() == 1) {
+            sPackageNameToUse = packagesSupportingCustomTabs.get(0);
+        } else if (!TextUtils.isEmpty(defaultViewHandlerPackageName)
+                && !hasSpecializedHandlerIntents(context, activityIntent)
+                && packagesSupportingCustomTabs.contains(defaultViewHandlerPackageName)) {
+            sPackageNameToUse = defaultViewHandlerPackageName;
+        } else if (packagesSupportingCustomTabs.contains(STABLE_PACKAGE)) {
+            sPackageNameToUse = STABLE_PACKAGE;
+        } else if (packagesSupportingCustomTabs.contains(BETA_PACKAGE)) {
+            sPackageNameToUse = BETA_PACKAGE;
+        } else if (packagesSupportingCustomTabs.contains(DEV_PACKAGE)) {
+            sPackageNameToUse = DEV_PACKAGE;
+        } else if (packagesSupportingCustomTabs.contains(LOCAL_PACKAGE)) {
+            sPackageNameToUse = LOCAL_PACKAGE;
+        }
+        return sPackageNameToUse;
+    }
+
+    /**
+     * Used to check whether there is a specialized handler for a given intent.
+     * @param intent The intent to check with.
+     * @return Whether there is a specialized handler for the given intent.
+     */
+    private static boolean hasSpecializedHandlerIntents(Context context, Intent intent) {
+        try {
+            PackageManager pm = context.getPackageManager();
+            List<ResolveInfo> handlers = pm.queryIntentActivities(
+                    intent,
+                    PackageManager.GET_RESOLVED_FILTER);
+            if (handlers == null || handlers.size() == 0) {
+                return false;
+            }
+            for (ResolveInfo resolveInfo : handlers) {
+                IntentFilter filter = resolveInfo.filter;
+                if (filter == null) continue;
+                if (filter.countDataAuthorities() == 0 || filter.countDataPaths() == 0) continue;
+                if (resolveInfo.activityInfo == null) continue;
+                return true;
+            }
+        } catch (RuntimeException e) {
+            Log.e(TAG, "Runtime exception while getting specialized handlers");
+        }
+        return false;
+    }
+
+    /**
+     * @return All possible chrome package names that provide custom tabs feature.
+     */
+    public static String[] getPackages() {
+        return new String[]{"", STABLE_PACKAGE, BETA_PACKAGE, DEV_PACKAGE, LOCAL_PACKAGE};
+    }
+}
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/KeepAliveService.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/KeepAliveService.java
new file mode 100644
index 0000000..3bde921
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/KeepAliveService.java
@@ -0,0 +1,22 @@
+// Copyright 2015 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.customtabsclient.shared;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+
+/**
+ * Empty service used by the custom tab to bind to, raising the application's importance.
+ */
+public class KeepAliveService extends Service {
+    private static final Binder sBinder = new Binder();
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return sBinder;
+    }
+}
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/ServiceConnection.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/ServiceConnection.java
new file mode 100644
index 0000000..3de4ff2f
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/ServiceConnection.java
@@ -0,0 +1,37 @@
+// Copyright 2015 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.customtabsclient.shared;
+
+import android.content.ComponentName;
+
+import androidx.browser.customtabs.CustomTabsClient;
+import androidx.browser.customtabs.CustomTabsServiceConnection;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Implementation for the CustomTabsServiceConnection that avoids leaking the
+ * ServiceConnectionCallback
+ */
+public class ServiceConnection extends CustomTabsServiceConnection {
+    // A weak reference to the ServiceConnectionCallback to avoid leaking it.
+    private WeakReference<ServiceConnectionCallback> mConnectionCallback;
+
+    public ServiceConnection(ServiceConnectionCallback connectionCallback) {
+        mConnectionCallback = new WeakReference<>(connectionCallback);
+    }
+
+    @Override
+    public void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) {
+        ServiceConnectionCallback connectionCallback = mConnectionCallback.get();
+        if (connectionCallback != null) connectionCallback.onServiceConnected(client);
+    }
+
+    @Override
+    public void onServiceDisconnected(ComponentName name) {
+        ServiceConnectionCallback connectionCallback = mConnectionCallback.get();
+        if (connectionCallback != null) connectionCallback.onServiceDisconnected();
+    }
+}
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/ServiceConnectionCallback.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/ServiceConnectionCallback.java
new file mode 100644
index 0000000..dcb57a9
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/ServiceConnectionCallback.java
@@ -0,0 +1,23 @@
+// Copyright 2015 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.customtabsclient.shared;
+
+import androidx.browser.customtabs.CustomTabsClient;
+
+/**
+ * Callback for events when connecting and disconnecting from Custom Tabs Service.
+ */
+public interface ServiceConnectionCallback {
+    /**
+     * Called when the service is connected.
+     * @param client a CustomTabsClient
+     */
+    void onServiceConnected(CustomTabsClient client);
+
+    /**
+     * Called when the service is disconnected.
+     */
+    void onServiceDisconnected();
+}
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_in_left.xml b/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_in_left.xml
new file mode 100644
index 0000000..373537bb3
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_in_left.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 Google Inc. All Rights Reserved.
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <translate android:fromXDelta="-100%p" android:toXDelta="0"
+        android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_in_right.xml b/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_in_right.xml
new file mode 100644
index 0000000..75d0675
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_in_right.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 Google Inc. All Rights Reserved.
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <translate android:fromXDelta="100%p" android:toXDelta="0"
+        android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_out_left.xml b/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_out_left.xml
new file mode 100644
index 0000000..6ce1676
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_out_left.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 Google Inc. All Rights Reserved.
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <translate android:fromXDelta="0" android:toXDelta="-100%p"
+        android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_out_right.xml b/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_out_right.xml
new file mode 100644
index 0000000..def11b2
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_out_right.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 Google Inc. All Rights Reserved.
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <translate android:fromXDelta="0" android:toXDelta="100%p"
+        android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/cover.jpg b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/cover.jpg
new file mode 100644
index 0000000..190160bf
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/cover.jpg
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_arrow_back.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_arrow_back.png
new file mode 100644
index 0000000..fe424468
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_arrow_back.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_launcher.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..2a25824
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_notification_icon.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_notification_icon.png
new file mode 100644
index 0000000..c2c80d4
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_notification_icon.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_play.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_play.png
new file mode 100644
index 0000000..8baf85a
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_play.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_share.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_share.png
new file mode 100644
index 0000000..b09a692
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_share.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_stop.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_stop.png
new file mode 100644
index 0000000..33fe924
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_stop.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/cover.jpg b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/cover.jpg
new file mode 100644
index 0000000..2d44a17
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/cover.jpg
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_arrow_back.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_arrow_back.png
new file mode 100644
index 0000000..0904000
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_arrow_back.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_launcher.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c38d44c
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_notification_icon.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_notification_icon.png
new file mode 100644
index 0000000..9960b1b
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_notification_icon.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_play.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_play.png
new file mode 100644
index 0000000..000238c
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_play.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_share.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_share.png
new file mode 100644
index 0000000..e944fd70c
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_share.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_stop.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_stop.png
new file mode 100644
index 0000000..4315863
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_stop.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/cover.jpg b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/cover.jpg
new file mode 100644
index 0000000..39d46b17
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/cover.jpg
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_arrow_back.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_arrow_back.png
new file mode 100644
index 0000000..ebc826c
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_arrow_back.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_launcher.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..b12097c
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_notification_icon.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_notification_icon.png
new file mode 100644
index 0000000..00f5b4f
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_notification_icon.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_play.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_play.png
new file mode 100644
index 0000000..e4d298d
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_play.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_share.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_share.png
new file mode 100644
index 0000000..22a8783
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_share.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_stop.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_stop.png
new file mode 100644
index 0000000..7f24bf2
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_stop.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/cover.jpg b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/cover.jpg
new file mode 100644
index 0000000..3e05d2f
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/cover.jpg
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_arrow_back.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_arrow_back.png
new file mode 100644
index 0000000..099f9edc
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_arrow_back.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_launcher.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..71b68abe
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_notification_icon.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_notification_icon.png
new file mode 100644
index 0000000..c2c7d73
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_notification_icon.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_play.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_play.png
new file mode 100644
index 0000000..9f5d2b7b
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_play.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_share.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_share.png
new file mode 100644
index 0000000..a35b3cd
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_share.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_stop.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_stop.png
new file mode 100644
index 0000000..82a4ccc
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_stop.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_arrow_back.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_arrow_back.png
new file mode 100644
index 0000000..fb06e1d
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_arrow_back.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_launcher.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..32443be
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_share.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_share.png
new file mode 100644
index 0000000..e351c7b
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_share.png
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/layout/main.xml b/chrome/browser/android/examples/custom_tabs_client/src/res/layout/main.xml
new file mode 100644
index 0000000..c185d8d
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/layout/main.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 Google Inc. All Rights Reserved.
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent">
+
+    <LinearLayout
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
+        android:padding="5dp"
+        android:orientation="vertical" >
+
+        <EditText
+            android:id="@+id/edit"
+            android:padding="5dp"
+            android:layout_margin="5dp"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:hint="@string/url_hint"
+            android:inputType="textNoSuggestions"
+            android:text="@string/default_url" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="3dp"
+            android:orientation="horizontal">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="3dp"
+                android:text="@string/package_label"/>
+
+            <Spinner
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:id="@+id/spinner"
+                android:layout_margin="3dp"
+                android:layout_gravity="center_horizontal" />
+        </LinearLayout>
+
+        <Space
+            android:layout_width="match_parent"
+            android:layout_height="5dp" />
+
+        <Button
+            android:id="@+id/connect_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="3dp"
+            android:textAllCaps="false"
+            android:text="@string/connect_button_text"
+            android:enabled="true" />
+
+        <Button
+            android:id="@+id/warmup_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="3dp"
+            android:textAllCaps="false"
+            android:text="@string/warmup_button_text"
+            android:enabled="false" />
+
+        <Button
+            android:id="@+id/may_launch_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="3dp"
+            android:textAllCaps="false"
+            android:text="@string/may_launch_button_text"
+            android:enabled="false" />
+
+        <Button
+            android:id="@+id/launch_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="3dp"
+            android:textAllCaps="false"
+            android:text="@string/launch_button_text"
+            android:enabled="true" />
+
+        <Button
+            android:id="@+id/launch_browser_actions_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="3dp"
+            android:textAllCaps="false"
+            android:text="@string/launch_browser_actions_button_text" />
+
+        <Button
+            android:id="@+id/register_twa_service"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="3dp"
+            android:textAllCaps="false"
+            android:text="@string/register_twa_service" />
+
+    </LinearLayout>
+
+</ScrollView>
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/layout/remote_view.xml b/chrome/browser/android/examples/custom_tabs_client/src/res/layout/remote_view.xml
new file mode 100644
index 0000000..f41ae36
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/layout/remote_view.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="56dp"
+    android:orientation="horizontal"
+    android:background="@android:color/white">
+
+    <android.widget.ImageView
+        android:id="@+id/cover"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_margin="4dp"
+        android:scaleType="centerCrop"
+        android:src="@drawable/cover"/>
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:padding="4dp">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/amazing_grace"
+            android:paddingTop="2dp"
+            android:textSize="16sp"
+            android:textColor="@android:color/black"/>
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingTop="2dp"
+            android:text="@string/artist"
+            android:textSize="12sp"
+            android:textColor="#666666"/>
+    </LinearLayout>
+
+    <android.widget.ImageView
+        android:id="@+id/play_pause"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginStart="4dp"
+        android:layout_marginTop="4dp"
+        android:layout_marginBottom="4dp"
+        android:layout_marginEnd="8dp"
+        android:src="@drawable/ic_play"/>
+</LinearLayout>
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/raw/amazing_grace.mp3 b/chrome/browser/android/examples/custom_tabs_client/src/res/raw/amazing_grace.mp3
new file mode 100644
index 0000000..08009a6
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/raw/amazing_grace.mp3
Binary files differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/values/strings.xml b/chrome/browser/android/examples/custom_tabs_client/src/res/values/strings.xml
new file mode 100644
index 0000000..f1fc619
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/values/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright 2015 Google Inc. All Rights Reserved.
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <string name="app_name">Chrome Custom Tabs Example</string>
+    <string name="url_hint">Please type the url here.</string>
+    <string name="warmup_button_text">Warmup Chrome</string>
+    <string name="may_launch_button_text">May Launch URL</string>
+    <string name="launch_button_text">Launch URL in a Chrome Custom Tab</string>
+    <string name="connect_button_text">Connect to the service</string>
+    <string name="launch_browser_actions_button_text">Launch URL in Browser Actions Context Menu</string>
+    <string name="register_twa_service">Register TrustedWebActivityService</string>
+    <string name="default_url">https://www.google.com</string>
+    <string name="package_label">Package:</string>
+    <string name="amazing_grace">Amazing Grace 2011</string>
+    <string name="artist">Kevin MacLeod</string>
+</resources>
diff --git a/third_party/custom_tabs_client/testing_with_chromium.md b/chrome/browser/android/examples/custom_tabs_client/testing_with_chromium.md
similarity index 100%
rename from third_party/custom_tabs_client/testing_with_chromium.md
rename to chrome/browser/android/examples/custom_tabs_client/testing_with_chromium.md
diff --git a/chrome/browser/android/metrics/BUILD.gn b/chrome/browser/android/metrics/BUILD.gn
index d79c9ff..2a7b9c60 100644
--- a/chrome/browser/android/metrics/BUILD.gn
+++ b/chrome/browser/android/metrics/BUILD.gn
@@ -38,6 +38,7 @@
       ":ukm_java_test_support",
       "//base:base_java_test_support",
       "//chrome/android:chrome_java",
+      "//chrome/browser/tab:java",
       "//chrome/test/android:chrome_java_test_support",
       "//components/metrics:metrics_java",
       "//content/public/test/android:content_java_test_support",
diff --git a/chrome/browser/chrome_browser_application_mac.mm b/chrome/browser/chrome_browser_application_mac.mm
index 0004eb0..c3c52feb 100644
--- a/chrome/browser/chrome_browser_application_mac.mm
+++ b/chrome/browser/chrome_browser_application_mac.mm
@@ -21,6 +21,7 @@
 #include "content/public/browser/native_event_processor_mac.h"
 #include "content/public/browser/native_event_processor_observer_mac.h"
 #include "ui/base/cocoa/accessibility_focus_overrider.h"
+#include "ui/events/base_event_utils.h"
 
 namespace chrome_browser_application_mac {
 
@@ -94,6 +95,16 @@
     default:
       break;
   }
+
+  // TODO(bokan): Added temporarily to debug https://crbug.com/1039833.
+  base::TimeTicks event_timestamp =
+      ui::EventTimeStampFromSeconds([event timestamp]);
+  base::TimeTicks now = ui::EventTimeForNow();
+  base::TimeDelta diff = now - event_timestamp;
+  desc += base::StringPrintf(" Now: %lld Diff: %lld",
+                             (now - base::TimeTicks()).InSeconds(),
+                             diff.InSeconds());
+
   return desc;
 }
 
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 9b73c809..6a13105 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -2189,6 +2189,8 @@
     "printing/server_printers_fetcher.h",
     "printing/server_printers_provider.cc",
     "printing/server_printers_provider.h",
+    "printing/server_printers_provider_factory.cc",
+    "printing/server_printers_provider_factory.h",
     "printing/specifics_translation.cc",
     "printing/specifics_translation.h",
     "printing/synced_printers_manager.cc",
diff --git a/chrome/browser/chromeos/app_mode/app_session.cc b/chrome/browser/chromeos/app_mode/app_session.cc
index 74521616..070abde 100644
--- a/chrome/browser/chromeos/app_mode/app_session.cc
+++ b/chrome/browser/chromeos/app_mode/app_session.cc
@@ -7,6 +7,7 @@
 #include <errno.h>
 #include <signal.h>
 
+#include "ash/public/cpp/accessibility_controller.h"
 #include "base/bind.h"
 #include "base/lazy_instance.h"
 #include "base/location.h"
@@ -66,6 +67,13 @@
       power_manager::REQUEST_RESTART_OTHER, "kiosk app session");
 }
 
+void StartFloatingAccessibilityMenu() {
+  ash::AccessibilityController* accessibility_controller =
+      ash::AccessibilityController::Get();
+  if (accessibility_controller)
+    accessibility_controller->ShowFloatingMenuIfEnabled();
+}
+
 // Sends a SIGFPE signal to plugin subprocesses that matches |child_ids|
 // to trigger a dump.
 void DumpPluginProcessOnIOThread(const std::set<int>& child_ids) {
@@ -207,6 +215,8 @@
 
   plugin_handler_ = std::make_unique<KioskSessionPluginHandler>(this);
 
+  StartFloatingAccessibilityMenu();
+
   // For a demo app, we don't need to either setup the update service or
   // the idle app name notification.
   if (DemoAppLauncher::IsDemoAppSession(
@@ -240,6 +250,8 @@
   // the browser window was closed.
   browser_window_handler_ =
       std::make_unique<BrowserWindowHandler>(this, browser);
+
+  StartFloatingAccessibilityMenu();
 }
 
 void AppSession::SetAttemptUserExitForTesting(base::OnceClosure closure) {
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
index 9611ec1..33e17425d 100644
--- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
+++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
@@ -248,8 +248,8 @@
       base::Bind(&AutoEnrollmentCheckScreen::OnConnectRequested,
                  base::Unretained(this)));
   error_screen_->SetHideCallback(
-      base::BindRepeating(&AutoEnrollmentCheckScreen::OnErrorScreenHidden,
-                          weak_ptr_factory_.GetWeakPtr()));
+      base::BindOnce(&AutoEnrollmentCheckScreen::OnErrorScreenHidden,
+                     weak_ptr_factory_.GetWeakPtr()));
   error_screen_->SetParentScreen(AutoEnrollmentCheckScreenView::kScreenId);
   error_screen_->Show();
   histogram_helper_->OnErrorShow(error_state);
diff --git a/chrome/browser/chromeos/login/oobe_screen.cc b/chrome/browser/chromeos/login/oobe_screen.cc
index 662d6ad2..72fd795 100644
--- a/chrome/browser/chromeos/login/oobe_screen.cc
+++ b/chrome/browser/chromeos/login/oobe_screen.cc
@@ -51,7 +51,6 @@
 constexpr StaticOobeScreenId OobeScreen::SCREEN_FATAL_ERROR;
 constexpr StaticOobeScreenId
     OobeScreen::SCREEN_ACTIVE_DIRECTORY_PASSWORD_CHANGE;
-constexpr StaticOobeScreenId OobeScreen::SCREEN_SPECIAL_LOGIN;
 constexpr StaticOobeScreenId OobeScreen::SCREEN_SPECIAL_OOBE;
 constexpr StaticOobeScreenId OobeScreen::SCREEN_TEST_NO_WINDOW;
 constexpr StaticOobeScreenId OobeScreen::SCREEN_UNKNOWN;
diff --git a/chrome/browser/chromeos/login/oobe_screen.h b/chrome/browser/chromeos/login/oobe_screen.h
index 4aded92b..8cdb256 100644
--- a/chrome/browser/chromeos/login/oobe_screen.h
+++ b/chrome/browser/chromeos/login/oobe_screen.h
@@ -66,8 +66,6 @@
   constexpr static StaticOobeScreenId SCREEN_ACTIVE_DIRECTORY_PASSWORD_CHANGE{
       "ad-password-change"};
 
-  // Special "first screen" that initiates login flow.
-  constexpr static StaticOobeScreenId SCREEN_SPECIAL_LOGIN{"login"};
   // Special "first screen" that initiates full OOBE flow.
   constexpr static StaticOobeScreenId SCREEN_SPECIAL_OOBE{"oobe"};
   // Special test value that commands not to create any window yet.
diff --git a/chrome/browser/chromeos/login/screens/error_screen.cc b/chrome/browser/chromeos/login/screens/error_screen.cc
index bbbcb42..8cf07a8 100644
--- a/chrome/browser/chromeos/login/screens/error_screen.cc
+++ b/chrome/browser/chromeos/login/screens/error_screen.cc
@@ -151,8 +151,8 @@
   // Not really used on JS side yet so no need to propagate to screen context.
 }
 
-void ErrorScreen::SetHideCallback(const base::Closure& on_hide) {
-  on_hide_callback_.reset(new base::Closure(on_hide));
+void ErrorScreen::SetHideCallback(base::OnceClosure on_hide) {
+  on_hide_callback_ = std::move(on_hide);
 }
 
 void ErrorScreen::ShowCaptivePortal() {
@@ -198,8 +198,8 @@
 void ErrorScreen::DoHide() {
   LOG(WARNING) << "Network error screen message is hidden";
   if (on_hide_callback_) {
-    on_hide_callback_->Run();
-    on_hide_callback_.reset();
+    std::move(on_hide_callback_).Run();
+    on_hide_callback_ = base::OnceClosure();
   }
   network_portal_detector::GetInstance()->SetStrategy(
       PortalDetectorStrategy::STRATEGY_ID_LOGIN_SCREEN);
@@ -207,8 +207,8 @@
 
 void ErrorScreen::ShowImpl() {
   if (!on_hide_callback_) {
-    SetHideCallback(base::Bind(&ErrorScreen::DefaultHideCallback,
-                               weak_factory_.GetWeakPtr()));
+    SetHideCallback(base::BindOnce(&ErrorScreen::DefaultHideCallback,
+                                   weak_factory_.GetWeakPtr()));
   }
   if (view_)
     view_->Show();
diff --git a/chrome/browser/chromeos/login/screens/error_screen.h b/chrome/browser/chromeos/login/screens/error_screen.h
index ba4168b0..c4ed92f5 100644
--- a/chrome/browser/chromeos/login/screens/error_screen.h
+++ b/chrome/browser/chromeos/login/screens/error_screen.h
@@ -86,7 +86,7 @@
   void SetParentScreen(OobeScreenId parent_screen);
 
   // Sets callback that is called on hide.
-  void SetHideCallback(const base::Closure& on_hide);
+  void SetHideCallback(base::OnceClosure on_hide);
 
   // Shows captive portal dialog.
   void ShowCaptivePortal();
@@ -171,7 +171,7 @@
   OobeScreenId parent_screen_ = OobeScreen::SCREEN_UNKNOWN;
 
   // Optional callback that is called when NetworkError screen is hidden.
-  std::unique_ptr<base::Closure> on_hide_callback_;
+  base::OnceClosure on_hide_callback_;
 
   // Callbacks to be invoked when a connection attempt is requested.
   base::CallbackList<void()> connect_request_callbacks_;
diff --git a/chrome/browser/chromeos/login/screens/update_required_screen.cc b/chrome/browser/chromeos/login/screens/update_required_screen.cc
index 73542812..d4447aa 100644
--- a/chrome/browser/chromeos/login/screens/update_required_screen.cc
+++ b/chrome/browser/chromeos/login/screens/update_required_screen.cc
@@ -248,7 +248,7 @@
                           weak_factory_.GetWeakPtr()));
   error_screen_->SetUIState(NetworkError::UI_STATE_UPDATE);
   error_screen_->SetParentScreen(UpdateRequiredView::kScreenId);
-  error_screen_->SetHideCallback(base::BindRepeating(
+  error_screen_->SetHideCallback(base::BindOnce(
       &UpdateRequiredScreen::OnErrorScreenHidden, weak_factory_.GetWeakPtr()));
   error_screen_->SetIsPersistentError(true /* is_persistent */);
   error_screen_->Show();
diff --git a/chrome/browser/chromeos/login/screens/update_screen.cc b/chrome/browser/chromeos/login/screens/update_screen.cc
index 615417e1..a7e02cb 100644
--- a/chrome/browser/chromeos/login/screens/update_screen.cc
+++ b/chrome/browser/chromeos/login/screens/update_screen.cc
@@ -169,7 +169,7 @@
           &UpdateScreen::OnConnectRequested, weak_factory_.GetWeakPtr()));
   error_screen_->SetUIState(NetworkError::UI_STATE_UPDATE);
   error_screen_->SetParentScreen(UpdateView::kScreenId);
-  error_screen_->SetHideCallback(base::BindRepeating(
+  error_screen_->SetHideCallback(base::BindOnce(
       &UpdateScreen::OnErrorScreenHidden, weak_factory_.GetWeakPtr()));
   error_screen_->Show();
   histogram_helper_->OnErrorShow(error_screen_->GetErrorState());
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
index 8d09bce2..415f9f5 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
@@ -176,8 +176,7 @@
 // Returns true if signin (not oobe) should be displayed.
 bool ShouldShowSigninScreen(chromeos::OobeScreenId first_screen) {
   return (first_screen == chromeos::OobeScreen::SCREEN_UNKNOWN &&
-          IsOobeComplete()) ||
-         first_screen == chromeos::OobeScreen::SCREEN_SPECIAL_LOGIN;
+          IsOobeComplete());
 }
 
 void MaybeShowDeviceDisabledScreen() {
@@ -1081,7 +1080,7 @@
           switches::kNaturalScrollDefault));
 
   auto session_state = session_manager::SessionState::OOBE;
-  if (IsOobeComplete() || first_screen == OobeScreen::SCREEN_SPECIAL_LOGIN)
+  if (IsOobeComplete())
     session_state = session_manager::SessionState::LOGIN_PRIMARY;
   session_manager::SessionManager::Get()->SetSessionState(session_state);
 
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index c9fb4e9..8f7a952e 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -114,6 +114,7 @@
 #include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/gesture_navigation_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h"
@@ -623,7 +624,7 @@
     UMA_HISTOGRAM_MEDIUM_TIMES("OOBE.EULAToSignInTime", delta);
   }
   VLOG(1) << "Showing login screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_SPECIAL_LOGIN);
+  UpdateStatusAreaVisibilityForScreen(GaiaView::kScreenId);
   GetLoginDisplayHost()->StartSignInScreen();
   login_screen_started_ = true;
 }
@@ -1539,8 +1540,6 @@
     ShowWelcomeScreen();
   } else if (screen_id == NetworkScreenView::kScreenId) {
     ShowNetworkScreen();
-  } else if (screen_id == OobeScreen::SCREEN_SPECIAL_LOGIN) {
-    ShowLoginScreen();
   } else if (screen_id == PackagedLicenseView::kScreenId) {
     ShowPackagedLicenseScreen();
   } else if (screen_id == UpdateView::kScreenId) {
diff --git a/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc b/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc
index a36b034..7c4e99c 100644
--- a/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc
+++ b/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc
@@ -893,13 +893,21 @@
         }
       }
 
-      const auto& timezone_info = probe_result->timezone_info;
-      if (!timezone_info.is_null()) {
-        em::TimezoneInfo* const timezone_info_out =
-            response_params_.device_status->mutable_timezone_info();
-        timezone_info_out->set_posix(timezone_info->posix);
-        timezone_info_out->set_region(timezone_info->region);
+      // Process TimezoneResult.
+      const auto& timezone_result = probe_result->timezone_result;
+      if (!timezone_result.is_null()) {
+        if (timezone_result->is_error()) {
+          LOG(ERROR) << "cros_healthd: Error getting timezone info: "
+                     << timezone_result->get_error()->msg;
+        } else {
+          const auto& timezone_info = timezone_result->get_timezone_info();
+          em::TimezoneInfo* const timezone_info_out =
+              response_params_.device_status->mutable_timezone_info();
+          timezone_info_out->set_posix(timezone_info->posix);
+          timezone_info_out->set_region(timezone_info->region);
+        }
       }
+
       const auto& memory_info = probe_result->memory_info;
       if (!memory_info.is_null()) {
         em::MemoryInfo* const memory_info_out =
@@ -921,12 +929,20 @@
           backlight_info_out->set_brightness(backlight->brightness);
         }
       }
-      const auto& fan_info = probe_result->fan_info;
-      if (fan_info.has_value()) {
-        for (const auto& fan : fan_info.value()) {
-          em::FanInfo* const fan_info_out =
-              response_params_.device_status->add_fan_info();
-          fan_info_out->set_speed_rpm(fan->speed_rpm);
+
+      // Process FanResult.
+      const auto& fan_result = probe_result->fan_result;
+      if (!fan_result.is_null()) {
+        if (fan_result->is_error()) {
+          LOG(ERROR) << "cros_healthd: Error getting fan info: "
+                     << fan_result->get_error()->msg;
+        } else {
+          const auto& fan_info = fan_result->get_fan_info();
+          for (const auto& fan : fan_info) {
+            em::FanInfo* const fan_info_out =
+                response_params_.device_status->add_fan_info();
+            fan_info_out->set_speed_rpm(fan->speed_rpm);
+          }
         }
       }
 
diff --git a/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc b/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc
index 3a96dee..6cdc44e 100644
--- a/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc
+++ b/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc
@@ -480,8 +480,10 @@
   base::Optional<std::vector<
       chromeos::cros_healthd::mojom::NonRemovableBlockDeviceInfoPtr>>
       block_device_info(std::move(storage_vector));
-  chromeos::cros_healthd::mojom::TimezoneInfo timezone_info(kPosixTimezone,
-                                                            kTimezoneRegion);
+  auto timezone_result =
+      chromeos::cros_healthd::mojom::TimezoneResult::NewTimezoneInfo(
+          chromeos::cros_healthd::mojom::TimezoneInfo::New(kPosixTimezone,
+                                                           kTimezoneRegion));
   chromeos::cros_healthd::mojom::MemoryInfo memory_info(
       kFakeTotalMemory, kFakeFreeMemory, kFakeAvailableMemory, kFakePageFaults);
   std::vector<chromeos::cros_healthd::mojom::BacklightInfoPtr> backlight_vector;
@@ -491,10 +493,13 @@
   std::vector<chromeos::cros_healthd::mojom::FanInfoPtr> fan_vector;
   chromeos::cros_healthd::mojom::FanInfo fan_info(kFakeSpeedRpm);
   fan_vector.push_back(fan_info.Clone());
+  auto fan_result = chromeos::cros_healthd::mojom::FanResult::NewFanInfo(
+      std::move(fan_vector));
   chromeos::cros_healthd::mojom::TelemetryInfo fake_info(
       battery_info.Clone(), std::move(block_device_info),
-      cached_vpd_info.Clone(), std::move(cpu_result), timezone_info.Clone(),
-      memory_info.Clone(), std::move(backlight_vector), std::move(fan_vector));
+      cached_vpd_info.Clone(), std::move(cpu_result),
+      std::move(timezone_result), memory_info.Clone(),
+      std::move(backlight_vector), std::move(fan_result));
 
   // Create fake SampledData.
   em::CPUTempInfo fake_cpu_temp_sample;
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager.cc b/chrome/browser/chromeos/printing/cups_printers_manager.cc
index 6dd013b1..6ba3c52 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager.cc
+++ b/chrome/browser/chromeos/printing/cups_printers_manager.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/chromeos/printing/printer_event_tracker_factory.h"
 #include "chrome/browser/chromeos/printing/printers_map.h"
 #include "chrome/browser/chromeos/printing/server_printers_provider.h"
+#include "chrome/browser/chromeos/printing/server_printers_provider_factory.h"
 #include "chrome/browser/chromeos/printing/synced_printers_manager.h"
 #include "chrome/browser/chromeos/printing/synced_printers_manager_factory.h"
 #include "chrome/browser/chromeos/printing/usb_printer_detector.h"
@@ -62,7 +63,7 @@
       std::unique_ptr<PrinterConfigurer> printer_configurer,
       std::unique_ptr<UsbPrinterNotificationController>
           usb_notification_controller,
-      std::unique_ptr<ServerPrintersProvider> server_printers_provider,
+      ServerPrintersProvider* server_printers_provider,
       std::unique_ptr<EnterprisePrintersProvider> enterprise_printers_provider,
       PrinterEventTracker* event_tracker,
       PrefService* pref_service)
@@ -75,7 +76,7 @@
         auto_usb_printer_configurer_(std::move(printer_configurer),
                                      this,
                                      usb_notification_controller_.get()),
-        server_printers_provider_(std::move(server_printers_provider)),
+        server_printers_provider_(server_printers_provider),
         enterprise_printers_provider_(std::move(enterprise_printers_provider)),
         enterprise_printers_provider_observer_(this),
         event_tracker_(event_tracker) {
@@ -529,7 +530,8 @@
 
   AutomaticUsbPrinterConfigurer auto_usb_printer_configurer_;
 
-  std::unique_ptr<ServerPrintersProvider> server_printers_provider_;
+  // Not owned.
+  ServerPrintersProvider* server_printers_provider_;
 
   std::unique_ptr<EnterprisePrintersProvider> enterprise_printers_provider_;
   ScopedObserver<EnterprisePrintersProvider,
@@ -577,7 +579,8 @@
       UsbPrinterDetector::Create(), ZeroconfPrinterDetector::Create(),
       CreatePpdProvider(profile), PrinterConfigurer::Create(profile),
       UsbPrinterNotificationController::Create(profile),
-      ServerPrintersProvider::Create(profile),
+      ServerPrintersProviderFactory::GetInstance()->GetForBrowserContext(
+          profile),
       EnterprisePrintersProvider::Create(CrosSettings::Get(), profile),
       PrinterEventTrackerFactory::GetInstance()->GetForBrowserContext(profile),
       profile->GetPrefs());
@@ -592,7 +595,7 @@
     std::unique_ptr<PrinterConfigurer> printer_configurer,
     std::unique_ptr<UsbPrinterNotificationController>
         usb_notification_controller,
-    std::unique_ptr<ServerPrintersProvider> server_printers_provider,
+    ServerPrintersProvider* server_printers_provider,
     std::unique_ptr<EnterprisePrintersProvider> enterprise_printers_provider,
     PrinterEventTracker* event_tracker,
     PrefService* pref_service) {
@@ -600,8 +603,8 @@
       synced_printers_manager, std::move(usb_detector),
       std::move(zeroconf_detector), std::move(ppd_provider),
       std::move(printer_configurer), std::move(usb_notification_controller),
-      std::move(server_printers_provider),
-      std::move(enterprise_printers_provider), event_tracker, pref_service);
+      server_printers_provider, std::move(enterprise_printers_provider),
+      event_tracker, pref_service);
 }
 
 // static
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager.h b/chrome/browser/chromeos/printing/cups_printers_manager.h
index a13890a..1419474 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager.h
+++ b/chrome/browser/chromeos/printing/cups_printers_manager.h
@@ -65,7 +65,7 @@
       std::unique_ptr<PrinterConfigurer> printer_configurer,
       std::unique_ptr<UsbPrinterNotificationController>
           usb_notification_controller,
-      std::unique_ptr<ServerPrintersProvider> server_printers_provider,
+      ServerPrintersProvider* server_printers_provider,
       std::unique_ptr<EnterprisePrintersProvider> enterprise_printers_provider,
       PrinterEventTracker* event_tracker,
       PrefService* pref_service);
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager_factory.cc b/chrome/browser/chromeos/printing/cups_printers_manager_factory.cc
index 630514a..9aefd1a 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager_factory.cc
+++ b/chrome/browser/chromeos/printing/cups_printers_manager_factory.cc
@@ -7,6 +7,7 @@
 #include "base/memory/singleton.h"
 #include "chrome/browser/chromeos/printing/cups_printers_manager.h"
 #include "chrome/browser/chromeos/printing/cups_printers_manager_proxy.h"
+#include "chrome/browser/chromeos/printing/server_printers_provider_factory.h"
 #include "chrome/browser/chromeos/printing/synced_printers_manager_factory.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
@@ -32,6 +33,7 @@
           "CupsPrintersManagerFactory",
           BrowserContextDependencyManager::GetInstance()),
       proxy_(CupsPrintersManagerProxy::Create()) {
+  DependsOn(chromeos::ServerPrintersProviderFactory::GetInstance());
   DependsOn(chromeos::SyncedPrintersManagerFactory::GetInstance());
 }
 
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc b/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
index 8996c8a..e9232b5d8 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
+++ b/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
@@ -357,9 +357,6 @@
     auto usb_notif_controller =
         std::make_unique<FakeUsbPrinterNotificationController>();
     usb_notif_controller_ = usb_notif_controller.get();
-    auto server_printers_provider =
-        std::make_unique<FakeServerPrintersProvider>();
-    server_printers_provider_ = server_printers_provider.get();
     auto enterprise_printers_provider =
         std::make_unique<FakeEnterprisePrintersProvider>();
     enterprise_printers_provider_ = enterprise_printers_provider.get();
@@ -371,9 +368,8 @@
         &synced_printers_manager_, std::move(usb_detector),
         std::move(zeroconf_detector), ppd_provider_,
         std::move(printer_configurer), std::move(usb_notif_controller),
-        std::move(server_printers_provider),
-        std::move(enterprise_printers_provider), &event_tracker_,
-        &pref_service_);
+        &server_printers_provider_, std::move(enterprise_printers_provider),
+        &event_tracker_, &pref_service_);
     manager_->AddObserver(this);
   }
 
@@ -414,7 +410,7 @@
   FakePrinterDetector* zeroconf_detector_;     // Not owned.
   TestPrinterConfigurer* printer_configurer_;  // Not owned.
   FakeUsbPrinterNotificationController* usb_notif_controller_;  // Not owned.
-  FakeServerPrintersProvider* server_printers_provider_;        // Not owned.
+  FakeServerPrintersProvider server_printers_provider_;
   scoped_refptr<FakePpdProvider> ppd_provider_;
 
   // This is unused, it's just here for memory ownership.
diff --git a/chrome/browser/chromeos/printing/server_printers_provider.h b/chrome/browser/chromeos/printing/server_printers_provider.h
index 98c2333..773214e 100644
--- a/chrome/browser/chromeos/printing/server_printers_provider.h
+++ b/chrome/browser/chromeos/printing/server_printers_provider.h
@@ -10,6 +10,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/chromeos/printing/printer_detector.h"
+#include "components/keyed_service/core/keyed_service.h"
 
 class Profile;
 
@@ -21,11 +22,11 @@
 // printers are signaled through a callback registered with the method
 // RegisterPrintersFoundCallback(...). All methods must be called from the UI
 // sequence, the callback is also called from this sequence.
-class ServerPrintersProvider {
+class ServerPrintersProvider : public KeyedService {
  public:
   // |profile| is a user profile, it cannot be nullptr.
   static std::unique_ptr<ServerPrintersProvider> Create(Profile* profile);
-  virtual ~ServerPrintersProvider() = default;
+  ~ServerPrintersProvider() override = default;
 
   using OnPrintersUpdateCallback = base::RepeatingCallback<void(bool complete)>;
 
diff --git a/chrome/browser/chromeos/printing/server_printers_provider_factory.cc b/chrome/browser/chromeos/printing/server_printers_provider_factory.cc
new file mode 100644
index 0000000..c2a182b
--- /dev/null
+++ b/chrome/browser/chromeos/printing/server_printers_provider_factory.cc
@@ -0,0 +1,50 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/printing/server_printers_provider_factory.h"
+
+#include "base/no_destructor.h"
+#include "chrome/browser/chromeos/printing/server_printers_provider.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+
+namespace chromeos {
+
+// static
+ServerPrintersProviderFactory* ServerPrintersProviderFactory::GetInstance() {
+  static base::NoDestructor<ServerPrintersProviderFactory> instance;
+  return instance.get();
+}
+
+// static
+ServerPrintersProvider* ServerPrintersProviderFactory::GetForBrowserContext(
+    content::BrowserContext* context) {
+  return static_cast<ServerPrintersProvider*>(
+      GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+ServerPrintersProviderFactory::ServerPrintersProviderFactory()
+    : BrowserContextKeyedServiceFactory(
+          "ServerPrintersProviderFactory",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+ServerPrintersProviderFactory::~ServerPrintersProviderFactory() = default;
+
+KeyedService* ServerPrintersProviderFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  auto* profile = Profile::FromBrowserContext(context);
+  return ServerPrintersProvider::Create(profile).release();
+}
+
+content::BrowserContext* ServerPrintersProviderFactory::GetBrowserContextToUse(
+    content::BrowserContext* context) const {
+  return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
+
+bool ServerPrintersProviderFactory::ServiceIsNULLWhileTesting() const {
+  return true;
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/server_printers_provider_factory.h b/chrome/browser/chromeos/printing/server_printers_provider_factory.h
new file mode 100644
index 0000000..0a48e42
--- /dev/null
+++ b/chrome/browser/chromeos/printing/server_printers_provider_factory.h
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_PRINTING_SERVER_PRINTERS_PROVIDER_FACTORY_H_
+#define CHROME_BROWSER_CHROMEOS_PRINTING_SERVER_PRINTERS_PROVIDER_FACTORY_H_
+
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace base {
+template <typename T>
+class NoDestructor;
+}
+
+namespace chromeos {
+
+class ServerPrintersProvider;
+
+class ServerPrintersProviderFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  static ServerPrintersProviderFactory* GetInstance();
+  static ServerPrintersProvider* GetForBrowserContext(
+      content::BrowserContext* context);
+
+ private:
+  friend class base::NoDestructor<ServerPrintersProviderFactory>;
+
+  ServerPrintersProviderFactory();
+  ~ServerPrintersProviderFactory() override;
+
+  // BrowserContextKeyedServiceFactory overrides:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+  content::BrowserContext* GetBrowserContextToUse(
+      content::BrowserContext* context) const override;
+  bool ServiceIsNULLWhileTesting() const override;
+
+  DISALLOW_COPY_AND_ASSIGN(ServerPrintersProviderFactory);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_PRINTING_SERVER_PRINTERS_PROVIDER_FACTORY_H_
diff --git a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc
index 0f43e71..b67d56b 100644
--- a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc
+++ b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc
@@ -33,7 +33,9 @@
     : delegate_(delegate),
       profile_(profile),
       account_id_(token_key.account_id),
-      resolution_data_(resolution_data) {}
+      resolution_data_(resolution_data),
+      web_flow_started_(false),
+      scoped_observer_(this) {}
 
 GaiaRemoteConsentFlow::~GaiaRemoteConsentFlow() {
   if (web_flow_)
@@ -46,40 +48,16 @@
         this, profile_, resolution_data_.url, WebAuthFlow::INTERACTIVE);
   }
 
-  auto* identity_manager = IdentityManagerFactory::GetForProfile(profile_);
-  std::vector<CoreAccountId> accounts;
-  if (IdentityAPI::GetFactoryInstance()
-          ->Get(profile_)
-          ->AreExtensionsRestrictedToPrimaryAccount()) {
-    CoreAccountId primary_account_id = identity_manager->GetPrimaryAccountId();
-    accounts.push_back(primary_account_id);
-  } else {
-    auto chrome_accounts_with_refresh_tokens =
-        identity_manager->GetAccountsWithRefreshTokens();
-    for (const auto& chrome_account : chrome_accounts_with_refresh_tokens) {
-      // An account in persistent error state would make multilogin fail.
-      // Showing only a subset of accounts seems to be a better alternative than
-      // failing with an error.
-      if (identity_manager->HasAccountWithRefreshTokenInPersistentErrorState(
-              chrome_account.account_id)) {
-        continue;
-      }
-      accounts.push_back(chrome_account.account_id);
-    }
-  }
-
-  set_accounts_in_cookie_task_ =
-      identity_manager->GetAccountsCookieMutator()
-          ->SetAccountsInCookieForPartition(
-              this,
-              {gaia::MultiloginMode::MULTILOGIN_UPDATE_COOKIE_ACCOUNTS_ORDER,
-               accounts},
-              base::BindOnce(&GaiaRemoteConsentFlow::OnSetAccountsComplete,
-                             base::Unretained(this)));
+  SetAccountsInCookie();
 }
 
 void GaiaRemoteConsentFlow::OnSetAccountsComplete(
     signin::SetAccountsInCookieResult result) {
+  set_accounts_in_cookie_task_.reset();
+  if (web_flow_started_) {
+    return;
+  }
+
   if (result != signin::SetAccountsInCookieResult::kSuccess) {
     delegate_->OnGaiaRemoteConsentFlowFailed(
         GaiaRemoteConsentFlow::Failure::SET_ACCOUNTS_IN_COOKIE_FAILED);
@@ -102,8 +80,9 @@
               base::Bind(&GaiaRemoteConsentFlow::OnConsentResultSet,
                          base::Unretained(this)));
 
-  set_accounts_in_cookie_task_.reset();
+  scoped_observer_.Add(IdentityManagerFactory::GetForProfile(profile_));
   web_flow_->Start();
+  web_flow_started_ = true;
 }
 
 void GaiaRemoteConsentFlow::OnConsentResultSet(
@@ -163,6 +142,10 @@
   return web_flow_->GetGuestPartition()->GetCookieManagerForBrowserProcess();
 }
 
+void GaiaRemoteConsentFlow::OnEndBatchOfRefreshTokenStateChanges() {
+  SetAccountsInCookie();
+}
+
 void GaiaRemoteConsentFlow::SetWebAuthFlowForTesting(
     std::unique_ptr<WebAuthFlow> web_auth_flow) {
   if (web_flow_)
@@ -170,4 +153,44 @@
   web_flow_ = std::move(web_auth_flow);
 }
 
+void GaiaRemoteConsentFlow::SetAccountsInCookie() {
+  // Reset a task that is already in flight because it contains stale
+  // information.
+  if (set_accounts_in_cookie_task_)
+    set_accounts_in_cookie_task_.reset();
+
+  auto* identity_manager = IdentityManagerFactory::GetForProfile(profile_);
+  std::vector<CoreAccountId> accounts;
+  if (IdentityAPI::GetFactoryInstance()
+          ->Get(profile_)
+          ->AreExtensionsRestrictedToPrimaryAccount()) {
+    CoreAccountId primary_account_id = identity_manager->GetPrimaryAccountId();
+    accounts.push_back(primary_account_id);
+  } else {
+    auto chrome_accounts_with_refresh_tokens =
+        identity_manager->GetAccountsWithRefreshTokens();
+    for (const auto& chrome_account : chrome_accounts_with_refresh_tokens) {
+      // An account in persistent error state would make multilogin fail.
+      // Showing only a subset of accounts seems to be a better alternative than
+      // failing with an error.
+      if (identity_manager->HasAccountWithRefreshTokenInPersistentErrorState(
+              chrome_account.account_id)) {
+        continue;
+      }
+      accounts.push_back(chrome_account.account_id);
+    }
+  }
+
+  // base::Unretained() is safe here because this class owns
+  // |set_accounts_in_cookie_task_| that will eventually invoke this callback.
+  set_accounts_in_cookie_task_ =
+      identity_manager->GetAccountsCookieMutator()
+          ->SetAccountsInCookieForPartition(
+              this,
+              {gaia::MultiloginMode::MULTILOGIN_UPDATE_COOKIE_ACCOUNTS_ORDER,
+               accounts},
+              base::BindOnce(&GaiaRemoteConsentFlow::OnSetAccountsComplete,
+                             base::Unretained(this)));
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h
index 9c5d486..433777b 100644
--- a/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h
+++ b/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h
@@ -8,9 +8,12 @@
 #include "base/callback_list.h"
 
 #include "base/macros.h"
+#include "base/scoped_observer.h"
 #include "chrome/browser/extensions/api/identity/extension_token_key.h"
 #include "chrome/browser/extensions/api/identity/web_auth_flow.h"
 #include "components/signin/public/identity_manager/accounts_cookie_mutator.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+#include "components/signin/public/identity_manager/set_accounts_in_cookie_result.h"
 #include "google_apis/gaia/core_account_id.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/oauth2_mint_token_flow.h"
@@ -19,7 +22,8 @@
 
 class GaiaRemoteConsentFlow
     : public WebAuthFlow::Delegate,
-      public signin::AccountsCookieMutator::PartitionDelegate {
+      public signin::AccountsCookieMutator::PartitionDelegate,
+      public signin::IdentityManager::Observer {
  public:
   enum Failure {
     WINDOW_CLOSED,
@@ -60,27 +64,37 @@
   void OnConsentResultSet(const std::string& consent_result,
                           const std::string& window_id);
 
-  // WebAuthFlow::Delegate implementation.
+  // WebAuthFlow::Delegate:
   void OnAuthFlowFailure(WebAuthFlow::Failure failure) override;
 
-  // AccountsCookieMutator::PartitionDelegate:
+  // signin::AccountsCookieMutator::PartitionDelegate:
   std::unique_ptr<GaiaAuthFetcher> CreateGaiaAuthFetcherForPartition(
       GaiaAuthConsumer* consumer) override;
   network::mojom::CookieManager* GetCookieManagerForPartition() override;
 
+  // signin::IdentityManager::Observer:
+  void OnEndBatchOfRefreshTokenStateChanges() override;
+
   void SetWebAuthFlowForTesting(std::unique_ptr<WebAuthFlow> web_auth_flow);
 
  private:
+  void SetAccountsInCookie();
+
   Delegate* delegate_;
   Profile* profile_;
   CoreAccountId account_id_;
   RemoteConsentResolutionData resolution_data_;
+
   std::unique_ptr<WebAuthFlow> web_flow_;
+  bool web_flow_started_;
+
   std::unique_ptr<signin::AccountsCookieMutator::SetAccountsInCookieTask>
       set_accounts_in_cookie_task_;
   std::unique_ptr<base::CallbackList<void(const std::string&,
                                           const std::string&)>::Subscription>
       identity_api_set_consent_result_subscription_;
+  ScopedObserver<signin::IdentityManager, signin::IdentityManager::Observer>
+      scoped_observer_;
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/events_apitest.cc b/chrome/browser/extensions/events_apitest.cc
index ac199da..803088a 100644
--- a/chrome/browser/extensions/events_apitest.cc
+++ b/chrome/browser/extensions/events_apitest.cc
@@ -208,10 +208,16 @@
   }
 }
 
-// Disabled due to flaky timeouts. https://crbug.com/833854
+// This test is OK on Windows, but times out on other platforms.
+// https://crbug.com/833854
+#if defined(OS_WIN)
+#define MAYBE_NewlyIntroducedListener NewlyIntroducedListener
+#else
+#define MAYBE_NewlyIntroducedListener DISABLED_NewlyIntroducedListener
+#endif
 // Tests that if an extension's updated version has a new lazy listener, it
 // fires properly after the update.
-IN_PROC_BROWSER_TEST_F(EventsApiTest, DISABLED_NewlyIntroducedListener) {
+IN_PROC_BROWSER_TEST_F(EventsApiTest, MAYBE_NewlyIntroducedListener) {
   std::vector<ExtensionCRXData> data;
   data.emplace_back("v1");
   data.emplace_back("v2");
diff --git a/chrome/browser/extensions/standard_management_policy_provider.cc b/chrome/browser/extensions/standard_management_policy_provider.cc
index 785ee71..9b5bb60b 100644
--- a/chrome/browser/extensions/standard_management_policy_provider.cc
+++ b/chrome/browser/extensions/standard_management_policy_provider.cc
@@ -23,7 +23,11 @@
 #endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
 
 #if defined(OS_CHROMEOS)
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/extensions/default_web_app_ids.h"
+#include "chrome/browser/chromeos/policy/system_features_disable_list_policy_handler.h"
+#include "components/policy/core/common/policy_pref_names.h"
+#include "components/prefs/pref_service.h"
 #endif  // defined(OS_CHROMEOS)
 
 namespace extensions {
@@ -63,6 +67,21 @@
   return false;
 }
 
+#if defined(OS_CHROMEOS)
+bool IsOsSettingsDisabledBySystemFeaturesPolicy() {
+  PrefService* const local_state = g_browser_process->local_state();
+  if (!local_state)
+    return false;
+
+  const base::ListValue* system_features_pref =
+      local_state->GetList(policy::policy_prefs::kSystemFeaturesDisableList);
+
+  return system_features_pref && system_features_pref->Find(base::Value(
+                                     policy::SystemFeature::OS_SETTINGS)) !=
+                                     system_features_pref->end();
+}
+#endif
+
 }  // namespace
 
 StandardManagementPolicyProvider::StandardManagementPolicyProvider(
@@ -93,7 +112,8 @@
 #if defined(OS_CHROMEOS)
   if (extension->id() == chromeos::default_web_apps::kOsSettingsAppId &&
       (installation_mode == ExtensionManagement::INSTALLATION_BLOCKED ||
-       installation_mode == ExtensionManagement::INSTALLATION_REMOVED)) {
+       installation_mode == ExtensionManagement::INSTALLATION_REMOVED) &&
+      IsOsSettingsDisabledBySystemFeaturesPolicy()) {
     return ReturnLoadError(extension, error);
   }
 #endif  // defined(OS_CHROMEOS)
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index ede26a7..ffd4e5d 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1370,7 +1370,12 @@
   {
     "name": "enable-edu-coexistence",
     "owners": [ "anastasiian@chromium.org", "sinhak@chromium.org" ],
-    "expiry_milestone": 83
+    "expiry_milestone": 85
+  },
+  {
+    "name": "enable-edu-coexistence-consent-log",
+    "owners": [ "anastasiian@chromium.org", "sinhak@chromium.org" ],
+    "expiry_milestone": 85
   },
   {
     "name": "enable-encryption-migration",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index d0a5b83..39d98f0 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -505,6 +505,12 @@
 const char kEnableEduCoexistenceDescription[] =
     "Allows Family Link managed users to add secondary EDU accounts.";
 
+const char kEnableEduCoexistenceConsentLogName[] =
+    "Enable parent consent logging in EDU account addition flow";
+const char kEnableEduCoexistenceConsentLogDescription[] =
+    "If enabled, parent consent gets logged to ARI before adding the account "
+    "to the device.";
+
 const char kEnableSaveDataName[] = "Enables save data feature";
 const char kEnableSaveDataDescription[] =
     "Enables save data feature. May cause user's traffic to be proxied via "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index b7f1c2b3..a833253 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -308,6 +308,9 @@
 extern const char kEnableEduCoexistenceName[];
 extern const char kEnableEduCoexistenceDescription[];
 
+extern const char kEnableEduCoexistenceConsentLogName[];
+extern const char kEnableEduCoexistenceConsentLogDescription[];
+
 extern const char kEnableSaveDataName[];
 extern const char kEnableSaveDataDescription[];
 
diff --git a/chrome/browser/media/feeds/media_feeds_converter.cc b/chrome/browser/media/feeds/media_feeds_converter.cc
index b5d6429..ec100186 100644
--- a/chrome/browser/media/feeds/media_feeds_converter.cc
+++ b/chrome/browser/media/feeds/media_feeds_converter.cc
@@ -677,11 +677,6 @@
       }
     }
 
-    if (!convert_property.Run(schema_org::property::kPublication, false,
-                              base::BindOnce(&GetLiveDetails))) {
-      continue;
-    }
-
     if (!convert_property.Run(
             schema_org::property::kIdentifier, false,
             base::BindOnce(&GetIdentifiers<mojom::MediaFeedItem>))) {
@@ -698,17 +693,16 @@
                                 base::BindOnce(&GetDuration))) {
         continue;
       }
-    }
-
-    if (converted_item->type == mojom::MediaFeedItemType::kTVSeries) {
-      auto* num_episodes =
-          GetProperty(item.get(), schema_org::property::kNumberOfEpisodes);
-      if (!num_episodes || !IsPositiveInteger(*num_episodes))
+      if (!convert_property.Run(schema_org::property::kPublication, false,
+                                base::BindOnce(&GetLiveDetails))) {
         continue;
-      auto* num_seasons =
-          GetProperty(item.get(), schema_org::property::kNumberOfSeasons);
-      if (!num_seasons || !IsPositiveInteger(*num_seasons))
+      }
+    } else if (converted_item->type == mojom::MediaFeedItemType::kMovie) {
+      if (!convert_property.Run(schema_org::property::kPublication, false,
+                                base::BindOnce(&GetLiveDetails))) {
         continue;
+      }
+    } else if (converted_item->type == mojom::MediaFeedItemType::kTVSeries) {
       if (!convert_property.Run(schema_org::property::kEpisode, false,
                                 base::BindOnce(&GetEpisode))) {
         continue;
diff --git a/chrome/browser/media/feeds/media_feeds_store.mojom b/chrome/browser/media/feeds/media_feeds_store.mojom
index 43ed787..80a6d7c 100644
--- a/chrome/browser/media/feeds/media_feeds_store.mojom
+++ b/chrome/browser/media/feeds/media_feeds_store.mojom
@@ -224,7 +224,7 @@
   mojo_base.mojom.String16 name;
 
   // The author that created the content.
-  Author author;
+  Author? author;
 
   // The date/time this feed item was published.
   mojo_base.mojom.Time date_published;
diff --git a/chrome/browser/policy/extension_policy_browsertest.cc b/chrome/browser/policy/extension_policy_browsertest.cc
index 23193649..61d20e9 100644
--- a/chrome/browser/policy/extension_policy_browsertest.cc
+++ b/chrome/browser/policy/extension_policy_browsertest.cc
@@ -347,7 +347,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionPolicyTest,
-                       ExtensionInstallBlacklistOsSettings) {
+                       SystemFeaturesDisableListOsSettings) {
   extensions::ExtensionPrefs* extension_prefs =
       extensions::ExtensionPrefs::Get(browser()->profile());
 
@@ -357,6 +357,33 @@
   ASSERT_TRUE(registry->enabled_extensions().GetByID(
       chromeos::default_web_apps::kOsSettingsAppId));
 
+  base::ListValue feature_list;
+  feature_list.AppendString("os_settings");
+  PolicyMap policies;
+  policies.Set(key::kSystemFeaturesDisableList, POLICY_LEVEL_MANDATORY,
+               POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
+               feature_list.CreateDeepCopy(), nullptr);
+  UpdateProviderPolicy(policies);
+
+  EXPECT_EQ(1u, registry->disabled_extensions().size());
+  extensions::ExtensionService* service = extension_service();
+  EXPECT_FALSE(service->IsExtensionEnabled(
+      chromeos::default_web_apps::kOsSettingsAppId));
+  EXPECT_EQ(extensions::disable_reason::DISABLE_BLOCKED_BY_POLICY,
+            extension_prefs->GetDisableReasons(
+                chromeos::default_web_apps::kOsSettingsAppId));
+}
+
+// Ensure that OS Settings is only blocked by the SystemFeaturesDisableList
+// policy.
+IN_PROC_BROWSER_TEST_F(ExtensionPolicyTest,
+                       ExtensionInstallBlacklistOsSettings) {
+  extensions::ExtensionRegistry* registry = extension_registry();
+  const extensions::Extension* bookmark_app = InstallOSSettings();
+  ASSERT_TRUE(bookmark_app);
+  ASSERT_TRUE(registry->enabled_extensions().GetByID(
+      chromeos::default_web_apps::kOsSettingsAppId));
+
   base::ListValue blacklist;
   blacklist.AppendString(chromeos::default_web_apps::kOsSettingsAppId);
   PolicyMap policies;
@@ -365,31 +392,6 @@
                blacklist.CreateDeepCopy(), nullptr);
   UpdateProviderPolicy(policies);
 
-  EXPECT_EQ(1u, registry->disabled_extensions().size());
-  extensions::ExtensionService* service = extension_service();
-  EXPECT_FALSE(service->IsExtensionEnabled(
-      chromeos::default_web_apps::kOsSettingsAppId));
-  EXPECT_EQ(extensions::disable_reason::DISABLE_BLOCKED_BY_POLICY,
-            extension_prefs->GetDisableReasons(
-                chromeos::default_web_apps::kOsSettingsAppId));
-}
-
-// Ensure that OS Settings is not blocked by the ExtensionAllowedTypes policy.
-IN_PROC_BROWSER_TEST_F(ExtensionPolicyTest, ExtensionAllowedTypesOsSettings) {
-  extensions::ExtensionRegistry* registry = extension_registry();
-  const extensions::Extension* bookmark_app = InstallOSSettings();
-  ASSERT_TRUE(bookmark_app);
-  ASSERT_TRUE(registry->enabled_extensions().GetByID(
-      chromeos::default_web_apps::kOsSettingsAppId));
-
-  base::ListValue allowed_types;
-  allowed_types.AppendString("theme");
-  PolicyMap policies;
-  policies.Set(key::kExtensionAllowedTypes, POLICY_LEVEL_MANDATORY,
-               POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
-               allowed_types.CreateDeepCopy(), nullptr);
-  UpdateProviderPolicy(policies);
-
   extensions::ExtensionService* service = extension_service();
   EXPECT_TRUE(service->IsExtensionEnabled(
       chromeos::default_web_apps::kOsSettingsAppId));
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index e88ed4ef..264895d9 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -350,6 +350,17 @@
 }
 #endif
 
+// Helper function that deletes entries from the kProfilesLastActive pref list.
+// It is called when every ephemeral profile is handled.
+void RemoveFromLastActiveProfilesPrefList(base::FilePath path) {
+  PrefService* local_state = g_browser_process->local_state();
+  DCHECK(local_state);
+  ListPrefUpdate update(local_state, prefs::kProfilesLastActive);
+  base::ListValue* profile_list = update.Get();
+  base::Value entry_value = base::Value(path.BaseName().MaybeAsASCII());
+  profile_list->EraseListValue(entry_value);
+}
+
 #if defined(OS_CHROMEOS)
 bool IsLoggedIn() {
   return user_manager::UserManager::IsInitialized() &&
@@ -896,6 +907,7 @@
     base::FilePath profile_path = entry->GetPath();
     if (entry->IsEphemeral()) {
       profiles_to_delete.push_back(profile_path);
+      RemoveFromLastActiveProfilesPrefList(profile_path);
       if (profile_path.BaseName().MaybeAsASCII() == last_used_profile)
         last_active_profile_deleted = true;
     } else if (new_profile_path.empty()) {
@@ -1923,6 +1935,8 @@
     }
   }
 
+  RemoveFromLastActiveProfilesPrefList(profile_dir);
+
   const base::FilePath new_active_profile_dir =
       found_entry ? found_entry->GetPath() : GenerateNextProfileDirectoryPath();
   FinishDeletingProfile(profile_dir, new_active_profile_dir);
diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc
index 7314e0d5..65812a2 100644
--- a/chrome/browser/profiles/profile_manager_unittest.cc
+++ b/chrome/browser/profiles/profile_manager_unittest.cc
@@ -1214,15 +1214,29 @@
   PrefService* local_state = g_browser_process->local_state();
   local_state->SetString(prefs::kProfileLastUsed, profile_name1);
 
+  // Set the last used profiles.
+  ListPrefUpdate update(local_state, prefs::kProfilesLastActive);
+  base::ListValue* initial_last_active_profile_list = update.Get();
+  initial_last_active_profile_list->Append(
+      std::make_unique<base::Value>(path1.BaseName().MaybeAsASCII()));
+  initial_last_active_profile_list->Append(
+      std::make_unique<base::Value>(path2.BaseName().MaybeAsASCII()));
+
   profile_manager->CleanUpEphemeralProfiles();
   content::RunAllTasksUntilIdle();
+  const base::ListValue* final_last_active_profile_list =
+      local_state->GetList(prefs::kProfilesLastActive);
 
   // The ephemeral profile should be deleted, and the last used profile set to
-  // the other one.
+  // the other one. Also, the ephemeral profile should be removed from the
+  // kProfilesLastActive list.
   EXPECT_FALSE(base::DirectoryExists(path1));
   EXPECT_TRUE(base::DirectoryExists(path2));
   EXPECT_EQ(profile_name2, local_state->GetString(prefs::kProfileLastUsed));
   ASSERT_EQ(1u, storage.GetNumberOfProfiles());
+  ASSERT_EQ(1u, final_last_active_profile_list->GetSize());
+  ASSERT_EQ(path2.BaseName().MaybeAsASCII(),
+            (final_last_active_profile_list->GetList())[0].GetString());
 
   // Mark the remaining profile ephemeral and clean up.
   storage.GetAllProfilesAttributes()[0]->SetIsEphemeral(true);
@@ -1233,6 +1247,7 @@
   EXPECT_FALSE(base::DirectoryExists(path2));
   EXPECT_EQ(0u, storage.GetNumberOfProfiles());
   EXPECT_EQ("Profile 1", local_state->GetString(prefs::kProfileLastUsed));
+  ASSERT_EQ(0u, final_last_active_profile_list->GetSize());
 }
 
 TEST_F(ProfileManagerTest, CleanUpEphemeralProfilesWithGuestLastUsedProfile) {
diff --git a/chrome/browser/resources/chromeos/crostini_upgrader/app.html b/chrome/browser/resources/chromeos/crostini_upgrader/app.html
index de309cd3d..b105134 100644
--- a/chrome/browser/resources/chromeos/crostini_upgrader/app.html
+++ b/chrome/browser/resources/chromeos/crostini_upgrader/app.html
@@ -14,7 +14,7 @@
   }
 
   #icon {
-    fill: var(--cros-default-button-color);
+    fill: var(--cros-default-icon-color-prominent);
     height: 32px;
     margin-top: 28px;
     width: 32px;
@@ -62,7 +62,7 @@
   }
 
   paper-progress {
-    --paper-progress-active-color: var(--cros-default-button-color);
+    --paper-progress-active-color: var(--cros-default-icon-color-prominent);
     --paper-progress-container-color: rgba(var(--google-blue-600-rgb), .24);
     margin-top: 36px;
     width: 100%;
diff --git a/chrome/browser/resources/chromeos/login/oobe_network.js b/chrome/browser/resources/chromeos/login/oobe_network.js
index 0d4837b..418ae1c 100644
--- a/chrome/browser/resources/chromeos/login/oobe_network.js
+++ b/chrome/browser/resources/chromeos/login/oobe_network.js
@@ -113,8 +113,8 @@
    * @private
    */
   onShown_() {
+    this.$.networkSelectLogin.refresh();
     this.async(function() {
-      this.$.networkSelectLogin.refresh();
       if (this.isConnected_)
         this.$.nextButton.focus();
       else
diff --git a/chrome/browser/resources/chromeos/login/sync_consent.html b/chrome/browser/resources/chromeos/login/sync_consent.html
index 15553a1..005eb9b 100644
--- a/chrome/browser/resources/chromeos/login/sync_consent.html
+++ b/chrome/browser/resources/chromeos/login/sync_consent.html
@@ -85,7 +85,7 @@
       <div slot="footer" class="layout vertical">
 
         <!-- "Sync settings" -->
-        <div class="overview-list-item flex layout horizontal">
+        <div class="overview-list-item layout horizontal">
           <img class="overview-list-item-icon" src="images/settings_gear.svg"
               width="24" height="24">
           <div class="flex layout vertical center-justified">
@@ -99,8 +99,10 @@
           </div>
         </div>
 
+        <div class="flex"></div>
+
         <!-- "Chrome sync" -->
-        <div class="overview-list-item flex layout horizontal">
+        <div class="overview-list-item layout horizontal">
           <img class="overview-list-item-icon" src="images/browser_sync.svg"
               width="24" height="24">
           <div class="flex layout vertical center-justified">
@@ -117,8 +119,10 @@
           </div>
         </div>
 
+        <div class="flex"></div>
+
         <!-- Personalize Google services -->
-        <div class="overview-list-item flex layout horizontal">
+        <div class="overview-list-item layout horizontal">
           <hd-iron-icon class="overview-list-item-icon"
               icon1x="sync-consent-32:googleg" icon2x="sync-consent-64:googleg">
           </hd-iron-icon>
diff --git a/chrome/browser/resources/media/media_feeds.js b/chrome/browser/resources/media/media_feeds.js
index a22c956..a4d009a 100644
--- a/chrome/browser/resources/media/media_feeds.js
+++ b/chrome/browser/resources/media/media_feeds.js
@@ -279,7 +279,8 @@
         sortKey === 'userStatus' || sortKey === 'lastFetchResult' ||
         sortKey === 'fetchFailedCount' || sortKey === 'lastFetchItemCount' ||
         sortKey === 'lastFetchPlayNextCount' ||
-        sortKey === 'lastFetchContentTypes' || sortKey === 'safeSearchResult') {
+        sortKey === 'lastFetchContentTypes' || sortKey === 'safeSearchResult' ||
+        sortKey === 'type') {
       return val1 > val2 ? 1 : -1;
     } else if (
         sortKey === 'lastDiscoveryTime' || sortKey === 'lastFetchTime' ||
diff --git a/chrome/browser/signin/chrome_signin_helper_unittest.cc b/chrome/browser/signin/chrome_signin_helper_unittest.cc
index 074d24f..a3e9d3a 100644
--- a/chrome/browser/signin/chrome_signin_helper_unittest.cc
+++ b/chrome/browser/signin/chrome_signin_helper_unittest.cc
@@ -68,7 +68,7 @@
                       bool is_main_frame)
       : is_main_frame_(is_main_frame),
         headers_(new net::HttpResponseHeaders(std::string())) {
-    headers_->AddHeader(header_name + ": " + header_value);
+    headers_->SetHeader(header_name, header_value);
   }
 
   ~TestResponseAdapter() override {}
diff --git a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc
index 341e8d1a8..45cd3bd 100644
--- a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc
+++ b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc
@@ -253,13 +253,13 @@
 
     auto redirect_head = network::mojom::URLResponseHead::New();
     redirect_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-    redirect_head->headers->AddHeader("X-Response-1: Foo");
-    redirect_head->headers->AddHeader("X-Response-2: Bar");
+    redirect_head->headers->SetHeader("X-Response-1", "Foo");
+    redirect_head->headers->SetHeader("X-Response-2", "Bar");
 
     auto response_head = network::mojom::URLResponseHead::New();
     response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-    response_head->headers->AddHeader("X-Response-3: Foo");
-    response_head->headers->AddHeader("X-Response-4: Bar");
+    response_head->headers->SetHeader("X-Response-3", "Foo");
+    response_head->headers->SetHeader("X-Response-4", "Bar");
     std::string body("Hello.");
     network::URLLoaderCompletionStatus status;
     status.decoded_body_length = body.size();
diff --git a/chrome/browser/signin/chrome_signin_url_loader_throttle_unittest.cc b/chrome/browser/signin/chrome_signin_url_loader_throttle_unittest.cc
index 18a8222..0dc76fe 100644
--- a/chrome/browser/signin/chrome_signin_url_loader_throttle_unittest.cc
+++ b/chrome/browser/signin/chrome_signin_url_loader_throttle_unittest.cc
@@ -167,8 +167,8 @@
 
   auto response_head = network::mojom::URLResponseHead::New();
   response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-  response_head->headers->AddHeader("X-Response-1: Foo");
-  response_head->headers->AddHeader("X-Response-2: Bar");
+  response_head->headers->SetHeader("X-Response-1", "Foo");
+  response_head->headers->SetHeader("X-Response-2", "Bar");
 
   std::vector<std::string> request_headers_to_remove;
   net::HttpRequestHeaders modified_request_headers;
@@ -211,8 +211,8 @@
 
   response_head = network::mojom::URLResponseHead::New();
   response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-  response_head->headers->AddHeader("X-Response-3: Foo");
-  response_head->headers->AddHeader("X-Response-4: Bar");
+  response_head->headers->SetHeader("X-Response-3", "Foo");
+  response_head->headers->SetHeader("X-Response-4", "Bar");
 
   throttle->WillProcessResponse(kTestRedirectURL, response_head.get(), &defer);
 
diff --git a/chrome/browser/subresource_filter/BUILD.gn b/chrome/browser/subresource_filter/BUILD.gn
index d112ecdc2..73c2f2c 100644
--- a/chrome/browser/subresource_filter/BUILD.gn
+++ b/chrome/browser/subresource_filter/BUILD.gn
@@ -25,6 +25,7 @@
       "//base:base_java_test_support",
       "//chrome/android:chrome_java",
       "//chrome/android:chrome_test_java",
+      "//chrome/browser/tab:java",
       "//chrome/test/android:chrome_java_test_support",
       "//components/safe_browsing/android:safe_browsing_java",
       "//content/public/test/android:content_java_test_support",
diff --git a/chrome/browser/subresource_filter/ad_tagging_browsertest.cc b/chrome/browser/subresource_filter/ad_tagging_browsertest.cc
index 848f60fb..8106d808e 100644
--- a/chrome/browser/subresource_filter/ad_tagging_browsertest.cc
+++ b/chrome/browser/subresource_filter/ad_tagging_browsertest.cc
@@ -529,7 +529,7 @@
 // This test is flaky. See crbug.com/1069346.
 IN_PROC_BROWSER_TEST_F(
     AdTaggingBrowserTest,
-    DISABLED_ChildrenOfFrameWithWindowStopAbortedLoad_StillCorrectlyTagged) {
+    ChildrenOfFrameWithWindowStopAbortedLoad_StillCorrectlyTagged) {
   TestSubresourceFilterObserver observer(web_contents());
 
   // Main frame.
diff --git a/chrome/browser/supervised_user/supervised_user_model_type_controller_unittest.cc b/chrome/browser/supervised_user/supervised_user_model_type_controller_unittest.cc
new file mode 100644
index 0000000..99aa38f
--- /dev/null
+++ b/chrome/browser/supervised_user/supervised_user_model_type_controller_unittest.cc
@@ -0,0 +1,65 @@
+// 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/supervised_user/supervised_user_sync_model_type_controller.h"
+
+#include "base/bind_helpers.h"
+#include "chrome/browser/supervised_user/supervised_user_constants.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/sync/base/model_type.h"
+#include "components/sync/driver/data_type_controller.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using syncer::DataTypeController;
+
+class SupervisedUserSyncModelTypeControllerTest : public testing::Test {
+ private:
+  content::BrowserTaskEnvironment task_environment_;
+};
+
+TEST_F(SupervisedUserSyncModelTypeControllerTest,
+       SupervisedUserMeetsPreconditions) {
+  TestingProfile::Builder builder;
+  builder.SetSupervisedUserId(supervised_users::kChildAccountSUID);
+  std::unique_ptr<Profile> child_profile = builder.Build();
+  ASSERT_TRUE(child_profile->IsSupervised());
+
+  SupervisedUserSyncModelTypeController controller(
+      syncer::SUPERVISED_USER_SETTINGS, child_profile.get(),
+      /*dump_stack=*/base::DoNothing(),
+      /*store_factory=*/base::DoNothing(),
+      /*syncable_service=*/nullptr);
+  EXPECT_EQ(DataTypeController::PreconditionState::kPreconditionsMet,
+            controller.GetPreconditionState());
+}
+
+TEST_F(SupervisedUserSyncModelTypeControllerTest,
+       NonSupervisedUserDoesNotMeetPreconditions) {
+  TestingProfile::Builder builder;
+  std::unique_ptr<Profile> non_child_profile = builder.Build();
+  ASSERT_FALSE(non_child_profile->IsSupervised());
+
+  SupervisedUserSyncModelTypeController controller(
+      syncer::SUPERVISED_USER_SETTINGS, non_child_profile.get(),
+      /*dump_stack=*/base::DoNothing(),
+      /*store_factory=*/base::DoNothing(),
+      /*syncable_service=*/nullptr);
+  EXPECT_EQ(DataTypeController::PreconditionState::kMustStopAndClearData,
+            controller.GetPreconditionState());
+}
+
+TEST_F(SupervisedUserSyncModelTypeControllerTest, HasTransportModeDelegate) {
+  TestingProfile::Builder builder;
+  builder.SetSupervisedUserId(supervised_users::kChildAccountSUID);
+  std::unique_ptr<Profile> child_profile = builder.Build();
+  ASSERT_TRUE(child_profile->IsSupervised());
+
+  SupervisedUserSyncModelTypeController controller(
+      syncer::SUPERVISED_USER_SETTINGS, child_profile.get(),
+      /*dump_stack=*/base::DoNothing(),
+      /*store_factory=*/base::DoNothing(),
+      /*syncable_service=*/nullptr);
+  EXPECT_TRUE(controller.GetDelegateForTransportModeForTest());
+}
diff --git a/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.cc b/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.cc
index 9ceadc1..df4aeb76 100644
--- a/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.cc
+++ b/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.cc
@@ -6,26 +6,27 @@
 
 #include "base/bind.h"
 #include "chrome/browser/profiles/profile.h"
-#include "components/browser_sync/browser_sync_client.h"
 #include "components/sync/model/model_type_store_service.h"
 
 SupervisedUserSyncModelTypeController::SupervisedUserSyncModelTypeController(
     syncer::ModelType type,
     const Profile* profile,
     const base::RepeatingClosure& dump_stack,
-    browser_sync::BrowserSyncClient* sync_client)
+    syncer::OnceModelTypeStoreFactory store_factory,
+    base::WeakPtr<syncer::SyncableService> syncable_service)
     : SyncableServiceBasedModelTypeController(
           type,
-          sync_client->GetModelTypeStoreService()->GetStoreFactory(),
-          sync_client->GetSyncableServiceForType(type),
-          dump_stack),
+          std::move(store_factory),
+          syncable_service,
+          dump_stack,
+          DelegateMode::kTransportModeWithSingleModel),
       profile_(profile) {
   DCHECK(type == syncer::SUPERVISED_USER_SETTINGS ||
          type == syncer::SUPERVISED_USER_WHITELISTS);
 }
 
 SupervisedUserSyncModelTypeController::
-    ~SupervisedUserSyncModelTypeController() {}
+    ~SupervisedUserSyncModelTypeController() = default;
 
 syncer::DataTypeController::PreconditionState
 SupervisedUserSyncModelTypeController::GetPreconditionState() const {
diff --git a/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.h b/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.h
index b7a277a92..13e93f7 100644
--- a/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.h
+++ b/chrome/browser/supervised_user/supervised_user_sync_model_type_controller.h
@@ -11,12 +11,9 @@
 
 class Profile;
 
-namespace browser_sync {
-class BrowserSyncClient;
-}  // namespace browser_sync
-
 // A DataTypeController for supervised user sync datatypes, which enables or
-// disables these types based on the profile's IsSupervised state.
+// disables these types based on the profile's IsSupervised state. Runs in
+// sync transport mode.
 class SupervisedUserSyncModelTypeController
     : public syncer::SyncableServiceBasedModelTypeController {
  public:
@@ -25,7 +22,8 @@
       syncer::ModelType type,
       const Profile* profile,
       const base::RepeatingClosure& dump_stack,
-      browser_sync::BrowserSyncClient* sync_client);
+      syncer::OnceModelTypeStoreFactory store_factory,
+      base::WeakPtr<syncer::SyncableService> syncable_service);
   ~SupervisedUserSyncModelTypeController() override;
 
   // DataTypeController override.
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index f5b4ab1..aeda1c63d 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -359,9 +359,13 @@
 
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
   controllers.push_back(std::make_unique<SupervisedUserSyncModelTypeController>(
-      syncer::SUPERVISED_USER_SETTINGS, profile_, dump_stack, this));
+      syncer::SUPERVISED_USER_SETTINGS, profile_, dump_stack,
+      model_type_store_factory,
+      GetSyncableServiceForType(syncer::SUPERVISED_USER_SETTINGS)));
   controllers.push_back(std::make_unique<SupervisedUserSyncModelTypeController>(
-      syncer::SUPERVISED_USER_WHITELISTS, profile_, dump_stack, this));
+      syncer::SUPERVISED_USER_WHITELISTS, profile_, dump_stack,
+      model_type_store_factory,
+      GetSyncableServiceForType(syncer::SUPERVISED_USER_WHITELISTS)));
 #endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/tab/BUILD.gn b/chrome/browser/tab/BUILD.gn
index 37d7b38..cef802e 100644
--- a/chrome/browser/tab/BUILD.gn
+++ b/chrome/browser/tab/BUILD.gn
@@ -8,5 +8,26 @@
 import("//chrome/browser/buildflags.gni")
 
 android_library("java") {
-  sources = [ "java/src/org/chromium/chrome/browser/tab/Dummy.java" ]
+  sources = [
+    "java/src/org/chromium/chrome/browser/tab/EmptyTabObserver.java",
+    "java/src/org/chromium/chrome/browser/tab/Tab.java",
+    "java/src/org/chromium/chrome/browser/tab/TabAttributeKeys.java",
+    "java/src/org/chromium/chrome/browser/tab/TabAttributes.java",
+    "java/src/org/chromium/chrome/browser/tab/TabCreationState.java",
+    "java/src/org/chromium/chrome/browser/tab/TabHidingType.java",
+    "java/src/org/chromium/chrome/browser/tab/TabLifecycle.java",
+    "java/src/org/chromium/chrome/browser/tab/TabObserver.java",
+  ]
+
+  # TabSelectionType, TabLaunchType
+  srcjar_deps = [ "//chrome/browser/ui:tab_model_enums_java" ]
+
+  deps = [
+    "//base:base_java",
+    "//chrome/browser/ui/android/native_page:java",
+    "//components/embedder_support/android:content_view_java",
+    "//components/find_in_page/android:java",
+    "//content/public/android:content_java",
+    "//ui/android:ui_full_java",
+  ]
 }
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/DEPS b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/DEPS
new file mode 100644
index 0000000..d6bcdb1
--- /dev/null
+++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/DEPS
@@ -0,0 +1,18 @@
+noparent = True
+
+include_rules = [
+  "-chrome",
+  "+base/android/java/src/org/chromium/base",
+  "+chrome/browser/ui/android/native_page",
+  "+components/find_in_page/android/java",
+  "+content/public/android/java/src/org/chromium/content_public",
+  "+ui/android/java/src/org/chromium/ui/base",
+]
+
+specific_include_rules = {
+  'Tab\.java': [
+    "-components",
+    "+components/embedder_support/android/java/src/org/chromium/components/embedder_support/view",
+    "+url/android/java/src/org/chromium/url",
+  ],
+}
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Dummy.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Dummy.java
deleted file mode 100644
index 5cab495..0000000
--- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Dummy.java
+++ /dev/null
@@ -1,11 +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.tab;
-
-/**
- * Dummy class to get the build working for the new target chrome/browser/tab:java.
- * TODO(jinsukkim): Remove the class once the real target classes are in place.
- */
-public class Dummy {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/EmptyTabObserver.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/EmptyTabObserver.java
similarity index 81%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/EmptyTabObserver.java
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/EmptyTabObserver.java
index 1ae9df4..cd39015 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/EmptyTabObserver.java
+++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/EmptyTabObserver.java
@@ -25,7 +25,7 @@
  */
 public class EmptyTabObserver implements TabObserver {
     @Override
-    public void onInitialized(Tab tab, TabState tabState) {}
+    public void onInitialized(Tab tab, String appId, Boolean hasThemeColor, int themeColor) {}
 
     @Override
     public void onShown(Tab tab, @TabSelectionType int type) {}
@@ -34,19 +34,19 @@
     public void onHidden(Tab tab, @TabHidingType int reason) {}
 
     @Override
-    public void onClosingStateChanged(Tab tab, boolean closing) { }
+    public void onClosingStateChanged(Tab tab, boolean closing) {}
 
     @Override
-    public void onDestroyed(Tab tab) { }
+    public void onDestroyed(Tab tab) {}
 
     @Override
-    public void onContentChanged(Tab tab) { }
+    public void onContentChanged(Tab tab) {}
 
     @Override
-    public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) { }
+    public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) {}
 
     @Override
-    public void onPageLoadStarted(Tab tab, String url) { }
+    public void onPageLoadStarted(Tab tab, String url) {}
 
     @Override
     public void onPageLoadFinished(Tab tab, String url) {}
@@ -61,40 +61,40 @@
     public void onRestoreFailed(Tab tab) {}
 
     @Override
-    public void onFaviconUpdated(Tab tab, Bitmap icon) { }
+    public void onFaviconUpdated(Tab tab, Bitmap icon) {}
 
     @Override
-    public void onTitleUpdated(Tab tab) { }
+    public void onTitleUpdated(Tab tab) {}
 
     @Override
-    public void onUrlUpdated(Tab tab) { }
+    public void onUrlUpdated(Tab tab) {}
 
     @Override
-    public void onSSLStateUpdated(Tab tab) { }
+    public void onSSLStateUpdated(Tab tab) {}
 
     @Override
     public void onCrash(Tab tab) {}
 
     @Override
-    public void onWebContentsSwapped(Tab tab, boolean didStartLoad, boolean didFinishLoad) { }
+    public void onWebContentsSwapped(Tab tab, boolean didStartLoad, boolean didFinishLoad) {}
 
     @Override
-    public void onContextMenuShown(Tab tab, ContextMenu menu) { }
+    public void onContextMenuShown(Tab tab, ContextMenu menu) {}
 
     @Override
     public void onCloseContents(Tab tab) {}
 
     @Override
-    public void onLoadStarted(Tab tab, boolean toDifferentDocument) { }
+    public void onLoadStarted(Tab tab, boolean toDifferentDocument) {}
 
     @Override
-    public void onLoadStopped(Tab tab, boolean toDifferentDocument) { }
+    public void onLoadStopped(Tab tab, boolean toDifferentDocument) {}
 
     @Override
     public void onLoadProgressChanged(Tab tab, float progress) {}
 
     @Override
-    public void onUpdateUrl(Tab tab, String url) { }
+    public void onUpdateUrl(Tab tab, String url) {}
 
     @Override
     public void onDidFailLoad(Tab tab, boolean isMainFrame, int errorCode, String failingUrl) {}
@@ -112,16 +112,16 @@
     public void didFirstVisuallyNonEmptyPaint(Tab tab) {}
 
     @Override
-    public void onDidChangeThemeColor(Tab tab, int color) { }
+    public void onDidChangeThemeColor(Tab tab, int color) {}
 
     @Override
-    public void onDidAttachInterstitialPage(Tab tab) { }
+    public void onDidAttachInterstitialPage(Tab tab) {}
 
     @Override
-    public void onDidDetachInterstitialPage(Tab tab) { }
+    public void onDidDetachInterstitialPage(Tab tab) {}
 
     @Override
-    public void onBackgroundColorChanged(Tab tab, int color) { }
+    public void onBackgroundColorChanged(Tab tab, int color) {}
 
     @Override
     public void webContentsCreated(Tab tab, WebContents sourceWebContents,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Tab.java
similarity index 91%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Tab.java
index 3aa292a..8466575 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -65,17 +65,6 @@
     WindowAndroid getWindowAndroid();
 
     /**
-     * Update the attachment state to Window(Activity).
-     * @param window A new {@link WindowAndroid} to attach the tab to. If {@code null},
-     *        the tab is being detached. See {@link ReparentingTask#detach()} for details.
-     * @param tabDelegateFactory The new delegate factory this tab should be using. Can be
-     *        {@code null} even when {@code window} is not, meaning we simply want to swap out
-     *        {@link WindowAndroid} for this tab and keep using the current delegate factory.
-     */
-    void updateAttachment(
-            @Nullable WindowAndroid window, @Nullable TabDelegateFactory tabDelegateFactory);
-
-    /**
      * @return Content view used for rendered web contents. Can be null
      *    if web contents is null.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabAttributeKeys.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabAttributeKeys.java
similarity index 100%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/TabAttributeKeys.java
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabAttributeKeys.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabAttributes.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabAttributes.java
similarity index 100%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/TabAttributes.java
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabAttributes.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabCreationState.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabCreationState.java
similarity index 100%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/TabCreationState.java
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabCreationState.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabHidingType.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabHidingType.java
similarity index 100%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/TabHidingType.java
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabHidingType.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabLifecycle.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabLifecycle.java
similarity index 100%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/TabLifecycle.java
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabLifecycle.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabObserver.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabObserver.java
similarity index 97%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/TabObserver.java
rename to chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabObserver.java
index ec45486..54cb7b3e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabObserver.java
+++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabObserver.java
@@ -9,7 +9,6 @@
 
 import androidx.annotation.Nullable;
 
-import org.chromium.chrome.browser.TabLoadStatus;
 import org.chromium.components.find_in_page.FindMatchRectsDetails;
 import org.chromium.components.find_in_page.FindNotificationDetails;
 import org.chromium.content_public.browser.LoadUrlParams;
@@ -25,9 +24,12 @@
      * Called when a {@link Tab} finished initialization. The {@link TabState} contains,
      * if not {@code null}, various states that a Tab should restore itself from.
      * @param tab The notifying {@link Tab}.
-     * @param tabState {@link TabState} to restore tab's state from if not {@code null}.
+     * @param appId ID of the external app that opened this tab.
+     * @param hasThemeColor {@code true} if the tab has a theme color set. {@code null}
+     *        if theme color info is not available from TabState.
+     * @param themeColor Theme color.
      */
-    void onInitialized(Tab tab, TabState tabState);
+    void onInitialized(Tab tab, String appId, @Nullable Boolean hasThemeColor, int themeColor);
 
     /**
      * Called when a {@link Tab} is shown.
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
index c2c5675..8f8c04f 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
@@ -31,6 +31,7 @@
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/color_palette.h"
 #include "ui/gfx/font.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/paint_vector_icon.h"
@@ -78,6 +79,7 @@
 constexpr autofill::PopupItemId kItemTypesUsingLeadingIcons[] = {
     autofill::PopupItemId::POPUP_ITEM_ID_SHOW_ACCOUNT_CARDS,
     autofill::PopupItemId::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY,
+    autofill::PopupItemId::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_EMPTY,
     autofill::PopupItemId::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN,
     autofill::PopupItemId::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_RE_SIGNIN,
     autofill::PopupItemId::
@@ -132,6 +134,10 @@
     return gfx::CreateVectorIcon(vector_icons::kSettingsIcon, kIconSize,
                                  gfx::kChromeIconGrey);
   }
+  if (icon_str == "empty") {
+    return gfx::CreateVectorIcon(omnibox::kHttpIcon, kIconSize,
+                                 gfx::kChromeIconGrey);
+  }
   if (icon_str == "google") {
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     return gfx::CreateVectorIcon(kGoogleGLogoIcon, kIconSize,
@@ -1097,6 +1103,7 @@
       case autofill::PopupItemId::POPUP_ITEM_ID_SCAN_CREDIT_CARD:
       case autofill::PopupItemId::POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO:
       case autofill::PopupItemId::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY:
+      case autofill::PopupItemId::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_EMPTY:
       case autofill::PopupItemId::POPUP_ITEM_ID_HIDE_AUTOFILL_SUGGESTIONS:
       case autofill::PopupItemId::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN:
       case autofill::PopupItemId::
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc
index 8f32702..0d06389 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views_unittest.cc
@@ -47,6 +47,7 @@
     {autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN, 1},
     {autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_RE_SIGNIN, 1},
     {autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE, 1},
+    {autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_EMPTY, 1},
 };
 
 class TestAXEventObserver : public views::AXEventObserver {
diff --git a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc
index fe80ab0a..350aa98 100644
--- a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc
+++ b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc
@@ -4,7 +4,9 @@
 
 #include "chrome/browser/ui/views/passwords/account_chooser_dialog_view.h"
 
+#include <algorithm>
 #include <memory>
+#include <utility>
 
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
@@ -54,6 +56,7 @@
     CredentialsItemView* credential_view =
         new CredentialsItemView(button_listener, titles.first, titles.second,
                                 form.get(), loader_factory);
+    credential_view->SetStoreIndicatorIcon(form->in_store);
     ChromeLayoutProvider* layout_provider = ChromeLayoutProvider::Get();
     gfx::Insets insets =
         layout_provider->GetInsetsMetric(views::INSETS_DIALOG_SUBSECTION);
diff --git a/chrome/browser/ui/views/passwords/credentials_item_view.cc b/chrome/browser/ui/views/passwords/credentials_item_view.cc
index eec0539f..1236aa40b 100644
--- a/chrome/browser/ui/views/passwords/credentials_item_view.cc
+++ b/chrome/browser/ui/views/passwords/credentials_item_view.cc
@@ -4,17 +4,22 @@
 
 #include "chrome/browser/ui/views/passwords/credentials_item_view.h"
 
+#include <algorithm>
+#include <memory>
+#include <utility>
+
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
 #include "chrome/grit/theme_resources.h"
-#include "components/autofill/core/common/password_form.h"
 #include "third_party/skia/include/core/SkPath.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/border.h"
 #include "ui/views/bubble/tooltip_icon.h"
 #include "ui/views/controls/image_view.h"
@@ -64,6 +69,9 @@
           views::BoxLayout::Orientation::kHorizontal));
   layout->set_cross_axis_alignment(
       views::BoxLayout::CrossAxisAlignment::kCenter);
+  layout->set_between_child_spacing(
+      ChromeLayoutProvider::Get()->GetDistanceMetric(
+          views::DISTANCE_RELATED_LABEL_HORIZONTAL));
   // Create an image-view for the avatar. Make sure it ignores events so that
   // the parent can receive the events instead.
   auto image_view = std::make_unique<CircularImageView>();
@@ -94,12 +102,6 @@
             views::BoxLayout::Orientation::kVertical));
     text_layout->set_cross_axis_alignment(
         views::BoxLayout::CrossAxisAlignment::kStart);
-    text_container->SetProperty(
-        views::kMarginsKey,
-        gfx::Insets(0,
-                    ChromeLayoutProvider::Get()->GetDistanceMetric(
-                        views::DISTANCE_RELATED_LABEL_HORIZONTAL),
-                    0, 0));
     layout->SetFlexForView(text_container, 1);
   }
 
@@ -133,6 +135,24 @@
 
 CredentialsItemView::~CredentialsItemView() = default;
 
+void CredentialsItemView::SetStoreIndicatorIcon(
+    autofill::PasswordForm::Store store) {
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+  if (store == autofill::PasswordForm::Store::kAccountStore &&
+      !store_indicator_icon_view_) {
+    store_indicator_icon_view_ =
+        AddChildView(std::make_unique<views::ImageView>());
+    store_indicator_icon_view_->set_can_process_events_within_subtree(false);
+    store_indicator_icon_view_->SetImage(
+        gfx::CreateVectorIcon(kGoogleGLogoIcon, gfx::kPlaceholderColor));
+  } else if (store == autofill::PasswordForm::Store::kProfileStore &&
+             store_indicator_icon_view_) {
+    RemoveChildView(store_indicator_icon_view_);
+    store_indicator_icon_view_ = nullptr;
+  }
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
+}
+
 void CredentialsItemView::UpdateAvatar(const gfx::ImageSkia& image) {
   image_view_->SetImage(ScaleImageForAccountAvatar(image));
 }
diff --git a/chrome/browser/ui/views/passwords/credentials_item_view.h b/chrome/browser/ui/views/passwords/credentials_item_view.h
index f8452ee..e5a3a7b 100644
--- a/chrome/browser/ui/views/passwords/credentials_item_view.h
+++ b/chrome/browser/ui/views/passwords/credentials_item_view.h
@@ -7,14 +7,13 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "build/branding_buildflags.h"
+#include "build/buildflag.h"
 #include "chrome/browser/ui/passwords/account_avatar_fetcher.h"
+#include "components/autofill/core/common/password_form.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/style/typography.h"
 
-namespace autofill {
-struct PasswordForm;
-}
-
 namespace gfx {
 class ImageSkia;
 }
@@ -44,6 +43,10 @@
                       int lower_text_style = views::style::STYLE_SECONDARY);
   ~CredentialsItemView() override;
 
+  // If |store| is kAccountStore and the build is official, adds a G logo icon
+  // to the view. If |store| is kProfileStore, removes any existing icon.
+  void SetStoreIndicatorIcon(autofill::PasswordForm::Store store);
+
   const autofill::PasswordForm* form() const { return form_; }
 
   // AccountAvatarFetcherDelegate:
@@ -58,6 +61,13 @@
   const autofill::PasswordForm* form_;
 
   views::ImageView* image_view_;
+
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+  // Optional right-aligned icon to distinguish account store credentials and
+  // profile store ones.
+  views::ImageView* store_indicator_icon_view_ = nullptr;
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
+
   views::Label* upper_label_ = nullptr;
   views::Label* lower_label_ = nullptr;
   views::ImageView* info_icon_ = nullptr;
diff --git a/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.cc b/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.cc
index 1461b4a..1593912e 100644
--- a/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.cc
@@ -40,6 +40,7 @@
 #include "chrome/browser/ui/views/web_apps/web_app_menu_button.h"
 #include "chrome/browser/ui/views/web_apps/web_app_origin_text.h"
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
+#include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h"
 #include "chrome/common/chrome_features.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/content_settings/core/common/features.h"
@@ -646,33 +647,38 @@
   params.page_action_icon_delegate = this;
   page_action_icon_controller_->Init(params, this);
 
-  // Extensions toolbar area with pinned extensions is lower priority than, for
-  // example, the menu button or other toolbar buttons, and pinned extensions
-  // should hide before other toolbar buttons.
-  constexpr int kLowPriorityFlexOrder = 2;
-  if (base::FeatureList::IsEnabled(features::kExtensionsToolbarMenu)) {
-    extensions_container_ =
-        AddChildView(std::make_unique<ExtensionsToolbarContainer>(
-            browser_view_->browser(),
-            ExtensionsToolbarContainer::DisplayMode::kCompact));
-    extensions_container_->SetProperty(
-        views::kFlexBehaviorKey,
-        views::FlexSpecification(
-            extensions_container_->animating_layout_manager()
-                ->GetDefaultFlexRule())
-            .WithOrder(kLowPriorityFlexOrder));
-    views::SetHitTestComponent(extensions_container_,
-                               static_cast<int>(HTCLIENT));
-  } else {
-    browser_actions_container_ =
-        AddChildView(std::make_unique<BrowserActionsContainer>(
-            browser_view_->browser(), nullptr, this, false /* interactive */));
-    browser_actions_container_->SetProperty(
-        views::kFlexBehaviorKey,
-        views::FlexSpecification(browser_actions_container_->GetFlexRule())
-            .WithOrder(kLowPriorityFlexOrder));
-    views::SetHitTestComponent(browser_actions_container_,
-                               static_cast<int>(HTCLIENT));
+  // Do not create the extensions or browser actions container if it is a
+  // System Web App.
+  if (!web_app::IsSystemWebApp(browser_view_->browser())) {
+    // Extensions toolbar area with pinned extensions is lower priority than,
+    // for example, the menu button or other toolbar buttons, and pinned
+    // extensions should hide before other toolbar buttons.
+    constexpr int kLowPriorityFlexOrder = 2;
+    if (base::FeatureList::IsEnabled(features::kExtensionsToolbarMenu)) {
+      extensions_container_ =
+          AddChildView(std::make_unique<ExtensionsToolbarContainer>(
+              browser_view_->browser(),
+              ExtensionsToolbarContainer::DisplayMode::kCompact));
+      extensions_container_->SetProperty(
+          views::kFlexBehaviorKey,
+          views::FlexSpecification(
+              extensions_container_->animating_layout_manager()
+                  ->GetDefaultFlexRule())
+              .WithOrder(kLowPriorityFlexOrder));
+      views::SetHitTestComponent(extensions_container_,
+                                 static_cast<int>(HTCLIENT));
+    } else {
+      browser_actions_container_ =
+          AddChildView(std::make_unique<BrowserActionsContainer>(
+              browser_view_->browser(), nullptr, this,
+              false /* interactive */));
+      browser_actions_container_->SetProperty(
+          views::kFlexBehaviorKey,
+          views::FlexSpecification(browser_actions_container_->GetFlexRule())
+              .WithOrder(kLowPriorityFlexOrder));
+      views::SetHitTestComponent(browser_actions_container_,
+                                 static_cast<int>(HTCLIENT));
+    }
   }
 
   if (app_controller->HasTitlebarMenuButton()) {
diff --git a/chrome/browser/ui/web_applications/app_browser_controller_browsertest.cc b/chrome/browser/ui/web_applications/app_browser_controller_browsertest.cc
index f010830..602d877 100644
--- a/chrome/browser/ui/web_applications/app_browser_controller_browsertest.cc
+++ b/chrome/browser/ui/web_applications/app_browser_controller_browsertest.cc
@@ -223,6 +223,12 @@
   InstallAndLaunchMockPopup();
   EXPECT_EQ(BrowserList::GetInstance()->size(), 2u);
 }
+
+IN_PROC_BROWSER_TEST_F(AppBrowserControllerBrowserTest,
+                       NoExtensionsContainerExists) {
+  InstallAndLaunchMockPopup();
+  EXPECT_EQ(app_browser_->window()->GetExtensionsContainer(), nullptr);
+}
 #endif
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
index 90fb512..08661ca9 100644
--- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
@@ -703,8 +703,8 @@
   if (GetCurrentScreen() != ErrorScreenView::kScreenId) {
     error_screen_->SetUIState(NetworkError::UI_STATE_SIGNIN);
     error_screen_->SetParentScreen(kScreenId);
-    error_screen_->SetHideCallback(base::Bind(&EnrollmentScreenHandler::DoShow,
-                                              weak_ptr_factory_.GetWeakPtr()));
+    error_screen_->SetHideCallback(base::BindOnce(
+        &EnrollmentScreenHandler::DoShow, weak_ptr_factory_.GetWeakPtr()));
     error_screen_->Show();
     histogram_helper_->OnErrorShow(error_screen_->GetErrorState());
   }
diff --git a/chrome/browser/ui/webui/discards/discards.mojom b/chrome/browser/ui/webui/discards/discards.mojom
index d4d0aba..b834549 100644
--- a/chrome/browser/ui/webui/discards/discards.mojom
+++ b/chrome/browser/ui/webui/discards/discards.mojom
@@ -104,7 +104,12 @@
 
   url.mojom.Url main_frame_url;
 
-  // TODO(siggi): Estimate data.
+  // This field is a dictionary of values, where each value is generated by
+  // a performance_manager::NodeDataDescriber implementation and keyed by the
+  // name it registered with. The intent is for each describer to describe
+  // private node-related or node-attached data in some way, to allow presenting
+  // otherwise hidden state in the chrome://discards/graph view.
+  string description_json;
 };
 
 // Represents the momentary state of a Frame node.
@@ -115,6 +120,9 @@
   int64 page_id;
   int64 parent_frame_id;
   int64 process_id;
+
+  // See PageInfo::description_json.
+  string description_json;
 };
 
 // Represents the momentary state of a Process node.
@@ -123,6 +131,9 @@
 
   mojo_base.mojom.ProcessId pid;
   uint64 private_footprint_kb;
+
+  // See PageInfo::description_json.
+  string description_json;
 };
 
 // Represents the momentary state of a Worker node.
@@ -135,6 +146,9 @@
   array<int64> client_frame_ids;
   array<int64> client_worker_ids;
   array<int64> child_worker_ids;
+
+  // See PageInfo::description_json.
+  string description_json;
 };
 
 // Used to transport favicon data.
diff --git a/chrome/browser/ui/webui/discards/graph_dump_impl.cc b/chrome/browser/ui/webui/discards/graph_dump_impl.cc
index c5033d7..93b84c32 100644
--- a/chrome/browser/ui/webui/discards/graph_dump_impl.cc
+++ b/chrome/browser/ui/webui/discards/graph_dump_impl.cc
@@ -9,6 +9,7 @@
 
 #include "base/base64.h"
 #include "base/bind.h"
+#include "base/json/json_string_value_serializer.h"
 #include "base/macros.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/task/post_task.h"
@@ -19,6 +20,8 @@
 #include "components/favicon/core/favicon_service.h"
 #include "components/favicon_base/favicon_callback.h"
 #include "components/performance_manager/public/graph/graph.h"
+#include "components/performance_manager/public/graph/node_data_describer.h"
+#include "components/performance_manager/public/graph/node_data_describer_registry.h"
 #include "components/performance_manager/public/performance_manager.h"
 #include "components/performance_manager/public/web_contents_proxy.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -35,6 +38,16 @@
   return performance_manager::Node::GetSerializationId(node);
 }
 
+// Best effort convert |value| to a string.
+std::string ToJSON(const base::Value& value) {
+  std::string result;
+  JSONStringValueSerializer serializer(&result);
+  if (serializer.Serialize(value))
+    return result;
+
+  return std::string();
+}
+
 }  // namespace
 
 class DiscardsGraphDumpImpl::FaviconRequestHelper {
@@ -372,6 +385,8 @@
   frame_info->page_id = GetSerializationId(page);
 
   frame_info->url = frame->GetURL();
+  frame_info->description_json = ToJSON(
+      graph_->GetNodeDataDescriberRegistry()->DescribeFrameNodeData(frame));
 
   if (created)
     change_subscriber_->FrameCreated(std::move(frame_info));
@@ -388,6 +403,9 @@
 
   page_info->id = GetSerializationId(page_node);
   page_info->main_frame_url = page_node->GetMainFrameUrl();
+  page_info->description_json = ToJSON(
+      graph_->GetNodeDataDescriberRegistry()->DescribePageNodeData(page_node));
+
   if (created)
     change_subscriber_->PageCreated(std::move(page_info));
   else
@@ -405,6 +423,9 @@
   process_info->pid = process->GetProcessId();
   process_info->private_footprint_kb = process->GetPrivateFootprintKb();
 
+  process_info->description_json = ToJSON(
+      graph_->GetNodeDataDescriberRegistry()->DescribeProcessNodeData(process));
+
   if (created)
     change_subscriber_->ProcessCreated(std::move(process_info));
   else
@@ -435,6 +456,9 @@
     worker_info->child_worker_ids.push_back(GetSerializationId(child_worker));
   }
 
+  worker_info->description_json = ToJSON(
+      graph_->GetNodeDataDescriberRegistry()->DescribeWorkerNodeData(worker));
+
   if (created)
     change_subscriber_->WorkerCreated(std::move(worker_info));
   else
diff --git a/chrome/browser/ui/webui/discards/graph_dump_impl.h b/chrome/browser/ui/webui/discards/graph_dump_impl.h
index d70ccaf..b137b89 100644
--- a/chrome/browser/ui/webui/discards/graph_dump_impl.h
+++ b/chrome/browser/ui/webui/discards/graph_dump_impl.h
@@ -92,6 +92,10 @@
   // Ignored.
   void OnHadFormInteractionChanged(
       const performance_manager::FrameNode* frame_node) override {}
+  // Ignored.
+  void OnFirstContentfulPaint(
+      const performance_manager::FrameNode* frame_node,
+      base::TimeDelta time_since_navigation_start) override {}
 
   // PageNodeObserver implementation:
   void OnPageNodeAdded(const performance_manager::PageNode* page_node) override;
diff --git a/chrome/browser/ui/webui/discards/graph_dump_impl_unittest.cc b/chrome/browser/ui/webui/discards/graph_dump_impl_unittest.cc
index f1b2e7d..147d095c 100644
--- a/chrome/browser/ui/webui/discards/graph_dump_impl_unittest.cc
+++ b/chrome/browser/ui/webui/discards/graph_dump_impl_unittest.cc
@@ -8,11 +8,14 @@
 #include <set>
 #include <utility>
 
+#include "base/json/json_reader.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "base/test/bind_test_util.h"
 #include "base/time/time.h"
 #include "chrome/browser/ui/webui/discards/discards.mojom.h"
+#include "components/performance_manager/public/graph/node_data_describer.h"
+#include "components/performance_manager/public/graph/node_data_describer_registry.h"
 #include "components/performance_manager/test_support/graph_impl.h"
 #include "components/performance_manager/test_support/mock_graphs.h"
 #include "content/public/test/browser_task_environment.h"
@@ -26,7 +29,7 @@
 
 using performance_manager::NodeBase;
 
-const std::string kHtmlMimeType = "text/html";
+const char kHtmlMimeType[] = "text/html";
 
 class TestChangeStream : public discards::mojom::GraphChangeStream {
  public:
@@ -139,6 +142,31 @@
   performance_manager::TestGraphImpl graph_;
 };
 
+class TestNodeDataDescriber : public performance_manager::NodeDataDescriber {
+ public:
+  // NodeDataDescriber implementations:
+  base::Value DescribeFrameNodeData(
+      const performance_manager::FrameNode* node) const override {
+    return base::Value("frame");
+  }
+  base::Value DescribePageNodeData(
+      const performance_manager::PageNode* node) const override {
+    return base::Value("page");
+  }
+  base::Value DescribeProcessNodeData(
+      const performance_manager::ProcessNode* node) const override {
+    return base::Value("process");
+  }
+  base::Value DescribeSystemNodeData(
+      const performance_manager::SystemNode* node) const override {
+    return base::Value("system");
+  }
+  base::Value DescribeWorkerNodeData(
+      const performance_manager::WorkerNode* node) const override {
+    return base::Value("worker");
+  }
+};
+
 }  // namespace
 
 TEST_F(DiscardsGraphDumpImplTest, ChangeStream) {
@@ -175,6 +203,9 @@
   impl->BindWithGraph(&graph_, graph_dump_remote.BindNewPipeAndPassReceiver());
   graph_.PassToGraph(std::move(impl));
 
+  TestNodeDataDescriber describer;
+  graph_.GetNodeDataDescriberRegistry()->RegisterDescriber(&describer, "test");
+
   TestChangeStream change_stream;
   graph_dump_remote->SubscribeToChanges(change_stream.GetRemote());
 
@@ -186,11 +217,22 @@
 
   EXPECT_EQ(2u, change_stream.process_map().size());
   for (const auto& kv : change_stream.process_map()) {
-    EXPECT_NE(0u, kv.second->id);
+    const auto* process_info = kv.second.get();
+    EXPECT_NE(0u, process_info->id);
+    EXPECT_EQ(base::JSONReader::Read("{\"test\":\"process\"}"),
+              base::JSONReader::Read(process_info->description_json));
   }
 
   EXPECT_EQ(3u, change_stream.frame_map().size());
+  for (const auto& kv : change_stream.frame_map()) {
+    EXPECT_EQ(base::JSONReader::Read("{\"test\":\"frame\"}"),
+              base::JSONReader::Read(kv.second->description_json));
+  }
   EXPECT_EQ(1u, change_stream.worker_map().size());
+  for (const auto& kv : change_stream.worker_map()) {
+    EXPECT_EQ(base::JSONReader::Read("{\"test\":\"worker\"}"),
+              base::JSONReader::Read(kv.second->description_json));
+  }
 
   // Count the top-level frames as we go.
   size_t top_level_frames = 0;
@@ -218,6 +260,8 @@
     const auto& page = kv.second;
     EXPECT_NE(0u, page->id);
     EXPECT_EQ(kExampleUrl, page->main_frame_url);
+    EXPECT_EQ(base::JSONReader::Read("{\"test\":\"page\"}"),
+              base::JSONReader::Read(kv.second->description_json));
   }
 
   // Test change notifications.
@@ -249,4 +293,6 @@
   EXPECT_EQ(nullptr, graph_.TakeFromGraph(impl_raw));
 
   worker->RemoveClientFrame(mock_graph.frame.get());
+
+  graph_.GetNodeDataDescriberRegistry()->UnregisterDescriber(&describer);
 }
diff --git a/chrome/browser/upboarding/query_tiles/android/javatests/src/org/chromium/chrome/browser/query_tiles/QueryTileSectionTest.java b/chrome/browser/upboarding/query_tiles/android/javatests/src/org/chromium/chrome/browser/query_tiles/QueryTileSectionTest.java
index edf01c1..0a5615d8 100644
--- a/chrome/browser/upboarding/query_tiles/android/javatests/src/org/chromium/chrome/browser/query_tiles/QueryTileSectionTest.java
+++ b/chrome/browser/upboarding/query_tiles/android/javatests/src/org/chromium/chrome/browser/query_tiles/QueryTileSectionTest.java
@@ -8,11 +8,8 @@
 import static android.support.test.espresso.assertion.ViewAssertions.matches;
 import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
 
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.support.test.espresso.action.ViewActions;
 import android.support.test.filters.SmallTest;
 
 import org.junit.After;
@@ -22,7 +19,6 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.Callback;
-import org.chromium.base.ContextUtils;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -32,8 +28,6 @@
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.NewTabPageTestUtils;
 import org.chromium.chrome.test.util.browser.Features;
-import org.chromium.content_public.browser.test.util.Criteria;
-import org.chromium.content_public.browser.test.util.CriteriaHelper;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -44,8 +38,6 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class QueryTileSectionTest {
-    private static final String SEARCH_URL_PATTERN = "https://www.google.com/search?q=";
-
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
 
@@ -66,35 +58,13 @@
     @Features.EnableFeatures(ChromeFeatureList.QUERY_TILES)
     public void testSimpleTest() throws Exception {
         onView(withId(R.id.query_tiles)).check(matches(isDisplayed()));
-        onView(withText("Tile 1")).check(matches(isDisplayed()));
-    }
-
-    @Test
-    @SmallTest
-    @Features.EnableFeatures(ChromeFeatureList.QUERY_TILES)
-    public void testLeafLevelTileLoadsSearchResultsPage() throws Exception {
-        onView(withId(R.id.query_tiles)).check(matches(isDisplayed()));
-        onView(withText("Tile 1")).perform(ViewActions.click());
-        onView(withText("Tile 1_1")).check(matches(isDisplayed())).perform(ViewActions.click());
-        waitForSearchResultsPage(mActivityTestRule.getActivity().getActivityTab());
-    }
-
-    private static void waitForSearchResultsPage(final Tab tab) {
-        CriteriaHelper.pollUiThread(new Criteria("The SRP was never loaded.") {
-            @Override
-            public boolean isSatisfied() {
-                return tab.getUrl().getValidSpecOrEmpty().contains(SEARCH_URL_PATTERN);
-            }
-        });
     }
 
     private static class TestTileProvider implements TileProvider {
         private List<Tile> mTiles = new ArrayList<>();
 
         private TestTileProvider() {
-            List<Tile> children = new ArrayList<>();
-            children.add(new Tile("tile1_1", "Tile 1_1", "Tile 1_1", "Tile 1_1 Query", null));
-            Tile tile = new Tile("1", "Tile 1", "Tile 1", "Tile 1 Query", children);
+            Tile tile = new Tile("1", "Tile 1", "Tile 1", "Tile 1", null);
             mTiles.add(tile);
         }
 
@@ -105,12 +75,7 @@
 
         @Override
         public void getVisuals(String id, Callback<List<Bitmap>> callback) {
-            List<Bitmap> bitmapList = new ArrayList<>();
-            Bitmap bitmap = BitmapFactory.decodeResource(
-                    ContextUtils.getApplicationContext().getResources(),
-                    R.drawable.chrome_sync_logo);
-            bitmapList.add(bitmap);
-            callback.onResult(bitmapList);
+            callback.onResult(null);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/common/channel_info_posix.cc b/chrome/common/channel_info_posix.cc
index 1632dce..88b20489b 100644
--- a/chrome/common/channel_info_posix.cc
+++ b/chrome/common/channel_info_posix.cc
@@ -70,6 +70,13 @@
 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
 std::string GetDesktopName(base::Environment* env) {
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+  // Google Chrome packaged as a snap is a special case: the application name
+  // is always "google-chrome", regardless of the channel (channels are built
+  // in to snapd, switching between them or doing parallel installs does not
+  // require distinct application names).
+  std::string snap_name;
+  if (env->GetVar("SNAP_NAME", &snap_name) && snap_name == "google-chrome")
+    return "google-chrome.desktop";
   version_info::Channel product_channel(GetChannel());
   switch (product_channel) {
     case version_info::Channel::DEV:
diff --git a/chrome/installer/linux/snap/build.sh b/chrome/installer/linux/snap/build.sh
index f811aac..ce37c98 100755
--- a/chrome/installer/linux/snap/build.sh
+++ b/chrome/installer/linux/snap/build.sh
@@ -53,6 +53,14 @@
 process_template "${SCRIPTDIR}/chrome.launcher.in" "${LAUNCHER_SCRIPT}"
 chmod +x "${LAUNCHER_SCRIPT}"
 process_template "${SCRIPTDIR}/snapcraft.yaml.in" "${TMPFILEDIR}/snapcraft.yaml"
+if [ "$SNAPNAME" = "google-chrome" ]; then
+  LOGO="product_logo_256"
+  if [ "$CHANNEL" = "beta" ]; then
+    sed -i -e "s:$LOGO.png:$LOGO_beta.png:" "${TMPFILEDIR}/snapcraft.yaml"
+  elif [ "$CHANNEL" = "unstable" ]; then
+    sed -i -e "s:$LOGO.png:$LOGO_dev.png:" "${TMPFILEDIR}/snapcraft.yaml"
+  fi
+fi
 
 cd "${TMPFILEDIR}"
 
diff --git a/chrome/installer/util/lzma_util.cc b/chrome/installer/util/lzma_util.cc
index f20c13d..5dce9b6 100644
--- a/chrome/installer/util/lzma_util.cc
+++ b/chrome/installer/util/lzma_util.cc
@@ -18,7 +18,6 @@
 #include "base/logging.h"
 #include "base/optional.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/win/windows_version.h"
 
 extern "C" {
 #include "third_party/lzma_sdk/7z.h"
@@ -370,12 +369,12 @@
         // Unmap the target file from the process's address space.
         mapped_file.reset();
         last_folder_index = -1;
-        // Flush to avoid an interesting bug in Windows 7 through Windows 10
-        // 1809; see
-        // https://randomascii.wordpress.com/2018/02/25/compiler-bug-linker-bug-windows-kernel-bug/
-        // for details.
-        if (base::win::GetVersion() < base::win::Version::WIN10_RS5)
-          target_file.Flush();
+        // Flush to avoid odd behavior, such as the bug in Windows 7 through
+        // Windows 10 1809 for PE files described in
+        // https://randomascii.wordpress.com/2018/02/25/compiler-bug-linker-bug-windows-kernel-bug/.
+        // We've also observed oddly empty files on other Windows versions, so
+        // this is unconditional.
+        target_file.Flush();
       }
     }
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index a4a9d562..6ff4045 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2963,7 +2963,7 @@
   testonly = true
   data_deps = [ "//testing:run_perf_test" ]
   if (build_dawn_tests) {
-    data_deps += [ "//third_party/dawn:dawn_perf_tests_temp_group" ]
+    data_deps += [ "//third_party/dawn/src/tests:dawn_perf_tests" ]
   }
 }
 
@@ -5425,6 +5425,7 @@
       "../browser/supervised_user/child_accounts/family_info_fetcher_unittest.cc",
       "../browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc",
       "../browser/supervised_user/kids_management_url_checker_client_unittest.cc",
+      "../browser/supervised_user/supervised_user_model_type_controller_unittest.cc",
       "../browser/supervised_user/supervised_user_pref_store_unittest.cc",
       "../browser/supervised_user/supervised_user_service_unittest.cc",
       "../browser/supervised_user/supervised_user_settings_service_unittest.cc",
diff --git a/chrome/test/android/BUILD.gn b/chrome/test/android/BUILD.gn
index b95c647..57f385f8 100644
--- a/chrome/test/android/BUILD.gn
+++ b/chrome/test/android/BUILD.gn
@@ -208,6 +208,7 @@
     "//chrome/android/third_party/compositor_animator:compositor_animator_java",
     "//chrome/browser/flags:java",
     "//chrome/browser/preferences:java",
+    "//chrome/browser/tab:java",
     "//chrome/browser/ui/android/appmenu:java",
     "//chrome/browser/ui/android/appmenu:test_support_java",
     "//chrome/browser/ui/android/favicon:java",
diff --git a/chrome/test/data/ad_tagging/create_frame.js b/chrome/test/data/ad_tagging/create_frame.js
index 02314ad..ff0fb5cf 100644
--- a/chrome/test/data/ad_tagging/create_frame.js
+++ b/chrome/test/data/ad_tagging/create_frame.js
@@ -65,16 +65,21 @@
   document.body.appendChild(frame);
   frame.contentWindow.stop();
 
-  // We load the scripts in frame_factory.html to allow subframe creation.
+  // We load the scripts in frame_factory.html to allow subframe creation. We
+  // set the async attribute to false to ensure that these scripts are loaded in
+  // insertion order.
   let script1 = document.createElement('script');
+  script1.async = false;
   script1.src = 'create_frame.js';
   frame.contentDocument.head.appendChild(script1);
 
   let script2 = document.createElement('script');
+  script1.async = false;
   script2.src = 'ad_script.js';
   frame.contentDocument.head.appendChild(script2);
 
   let script3 = document.createElement('script');
+  script1.async = false;
   script3.src = 'ad_script_2.js';
   // Set title so we know when all scripts have loaded.
   script3.onload = function() {
diff --git a/chrome/test/data/content_index/content_index.js b/chrome/test/data/content_index/content_index.js
index 637c4d3..04d49086 100644
--- a/chrome/test/data/content_index/content_index.js
+++ b/chrome/test/data/content_index/content_index.js
@@ -22,7 +22,7 @@
     icons: [{
       src: '/anchor_download_test.png',
     }],
-    launchUrl: '/content_index/content_index.html?launch',
+    url: '/content_index/content_index.html?launch',
   });
 }
 
diff --git a/chrome/test/data/origin_policy_browsertest/OWNERS b/chrome/test/data/origin_policy_browsertest/OWNERS
index cc8f52f4..41bfb92e 100644
--- a/chrome/test/data/origin_policy_browsertest/OWNERS
+++ b/chrome/test/data/origin_policy_browsertest/OWNERS
@@ -1 +1 @@
-file://third_party/blink/common/origin_policy/OWNERS
+file://services/network/origin_policy/OWNERS
diff --git a/chrome/test/origin_policy/OWNERS b/chrome/test/origin_policy/OWNERS
index b0812f6..9f5e5e7 100644
--- a/chrome/test/origin_policy/OWNERS
+++ b/chrome/test/origin_policy/OWNERS
@@ -1,2 +1,2 @@
-file://third_party/blink/common/origin_policy/OWNERS
+file://services/network/origin_policy/OWNERS
 # COMPONENT: Blink>SecurityFeature
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn
index 05c97d1..295598b 100644
--- a/chrome/updater/BUILD.gn
+++ b/chrome/updater/BUILD.gn
@@ -215,7 +215,10 @@
 
       deps += [ "//chrome/updater/win:updater_tests" ]
 
-      data_deps = [ "//chrome/updater/win:updater" ]
+      data_deps = [
+        "//chrome/updater/win:updater",
+        "//chrome/updater/win/installer",
+      ]
     }
 
     if (is_mac) {
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc
index a763b94d..8453215 100644
--- a/chrome/updater/test/integration_tests.cc
+++ b/chrome/updater/test/integration_tests.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/updater/test/integration_tests.h"
 
+#include "base/test/task_environment.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -22,15 +23,12 @@
     ExpectClean();
     Clean();
   }
+
+ private:
+  base::test::TaskEnvironment environment_;
 };
 
-// TODO(crbug.com/1063064): Fix the test on Windows.
-#if defined(OS_WIN)
-#define MAYBE_InstallUninstall DISABLED_InstallUninstall
-#else
-#define MAYBE_InstallUninstall InstallUninstall
-#endif
-TEST_F(IntegrationTest, MAYBE_InstallUninstall) {
+TEST_F(IntegrationTest, InstallUninstall) {
   Install();
   ExpectInstalled();
   Uninstall();
diff --git a/chrome/updater/test/integration_tests_win.cc b/chrome/updater/test/integration_tests_win.cc
index efe49a3..3035eacd 100644
--- a/chrome/updater/test/integration_tests_win.cc
+++ b/chrome/updater/test/integration_tests_win.cc
@@ -8,6 +8,9 @@
 #include "base/path_service.h"
 #include "base/process/launch.h"
 #include "base/process/process.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
 #include "chrome/updater/updater_version.h"
 #include "chrome/updater/util.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -32,6 +35,15 @@
   if (!process.WaitForExitWithTimeout(base::TimeDelta::FromSeconds(60),
                                       exit_code))
     return false;
+  base::WaitableEvent sleep(base::WaitableEvent::ResetPolicy::MANUAL,
+                            base::WaitableEvent::InitialState::NOT_SIGNALED);
+  // The process will exit before it is done uninstalling: sleep for five
+  // seconds to allow uninstall to complete.
+  base::ThreadPool::PostDelayedTask(
+      FROM_HERE, {base::MayBlock()},
+      base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(&sleep)),
+      base::TimeDelta::FromSeconds(5));
+  sleep.Wait();
   return true;
 }
 
@@ -68,7 +80,7 @@
 
   // Files must not exist on the file system.
 
-  // EXPECT_FALSE(base::PathExists(GetProductPath()));
+  EXPECT_FALSE(base::PathExists(GetProductPath()));
 }
 
 void ExpectInstalled() {
diff --git a/chrome/updater/win/BUILD.gn b/chrome/updater/win/BUILD.gn
index ee66bf8..21949b8 100644
--- a/chrome/updater/win/BUILD.gn
+++ b/chrome/updater/win/BUILD.gn
@@ -2,7 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/util/process_version.gni")
 import("//chrome/process_version_rc_template.gni")
+import("//chrome/updater/branding.gni")
 import("//testing/test.gni")
 
 # This target builds the updater executable, its installer, and unittests.
@@ -33,9 +35,16 @@
   data_deps = [ ":uninstall.cmd" ]
 }
 
-copy("uninstall.cmd") {
-  sources = [ "setup/uninstall.cmd" ]
-  outputs = [ "$target_gen_dir/uninstall.cmd" ]
+process_version("uninstall.cmd") {
+  template_file = "setup/uninstall.cmd"
+  output = "$target_gen_dir/uninstall.cmd"
+  process_only = true
+  extra_args = [
+    "-e",
+    "PRODUCT_FULLNAME=\"$updater_product_full_name\"",
+    "-e",
+    "COMPANY_SHORTNAME=\"$updater_company_short_name\"",
+  ]
 }
 
 process_version_rc_template("version_resources") {
diff --git a/chrome/updater/win/setup/uninstall.cmd b/chrome/updater/win/setup/uninstall.cmd
index bbaf5ce6c..32457c98 100644
--- a/chrome/updater/win/setup/uninstall.cmd
+++ b/chrome/updater/win/setup/uninstall.cmd
@@ -1,9 +1,10 @@
-rem Deletes the script's parent directory if \AppData\Local\ChromeUpdater\ is

-rem anywhere in the directory path. Sleeps 3 seconds and tries 3 times to

-rem delete the directory.

+rem Deletes the script's parent directory if

+rem \AppData\Local\@COMPANY_SHORTNAME@\@PRODUCT_FULLNAME@\ is anywhere in the

+rem directory path.  Sleeps 3 seconds and tries 3 times to delete the

+rem directory.

 @echo off

 set Directory=%~dp0

-@echo %Directory% | FindStr /R \\AppData\\Local\\Google\\GoogleUpdater\\ > nul

+@echo %Directory% | FindStr /R \\AppData\\Local\\@COMPANY_SHORTNAME@\\@PRODUCT_FULLNAME@\\ > nul

 IF %ERRORLEVEL% NEQ 0 exit 1

 @echo Deleting "%Directory%"...

 for /L %%G IN (1,1,3) do (

diff --git a/chromecast/browser/DEPS b/chromecast/browser/DEPS
index 74768e0..7fd9bbee 100644
--- a/chromecast/browser/DEPS
+++ b/chromecast/browser/DEPS
@@ -16,6 +16,7 @@
   "+components/cdm/browser",
   "+components/crash",
   "+components/download/public/common",
+  "+components/exo",
   "+components/heap_profiling",
   "+components/keyed_service",
   "+components/network_hints",
diff --git a/chromecast/browser/ui/aura/accessibility/ax_tree_source_aura.cc b/chromecast/browser/ui/aura/accessibility/ax_tree_source_aura.cc
index 6ca2402..c1d2a7a 100644
--- a/chromecast/browser/ui/aura/accessibility/ax_tree_source_aura.cc
+++ b/chromecast/browser/ui/aura/accessibility/ax_tree_source_aura.cc
@@ -7,6 +7,9 @@
 #include "chromecast/browser/accessibility/accessibility_manager.h"
 #include "chromecast/browser/cast_browser_process.h"
 #include "chromecast/browser/ui/aura/accessibility/automation_manager_aura.h"
+#include "components/exo/fullscreen_shell_surface.h"
+#include "components/exo/shell_surface_util.h"
+#include "components/exo/surface.h"
 #include "ui/accessibility/ax_action_data.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/accessibility/ax_tree_data.h"
@@ -14,17 +17,20 @@
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/views/accessibility/ax_aura_obj_wrapper.h"
+#include "ui/views/accessibility/ax_view_obj_wrapper.h"
 
 AXTreeSourceAura::AXTreeSourceAura(views::AXAuraObjWrapper* root,
                                    const ui::AXTreeID& tree_id,
                                    views::AXAuraObjCache* cache)
-    : AXTreeSourceViews(root, tree_id, cache) {}
+    : AXTreeSourceViews(root, tree_id, cache), cache_(cache) {}
 
 AXTreeSourceAura::~AXTreeSourceAura() = default;
 
 bool AXTreeSourceAura::GetTreeData(ui::AXTreeData* tree_data) const {
   AXTreeSourceViews::GetTreeData(tree_data);
 
+  // TODO(b/1069055) : This is a temporary solution to override the
+  // superclass method which does not set the correct focus_id.
   aura::Window* root_window =
       chromecast::shell::CastBrowserProcess::GetInstance()
           ->accessibility_manager()
@@ -35,8 +41,37 @@
         aura::client::GetFocusClient(root_window);
     if (focus_client) {
       aura::Window* window = focus_client->GetFocusedWindow();
-      tree_data->focus_id =
-          AutomationManagerAura::GetInstance()->GetIDFromWindow(window);
+      tree_data->focus_id = ui::AXNode::kInvalidAXID;
+
+      // Search for the full screen shell surface that holds the child
+      // tree for our UI. This is the node that should receive focus.
+      if (window) {
+        std::stack<aura::Window*> stack;
+        stack.push(window);
+        while (!stack.empty()) {
+          aura::Window* top = stack.top();
+          stack.pop();
+          DCHECK(top);
+
+          exo::Surface* surface = exo::GetShellMainSurface(top);
+          if (surface) {
+            views::Widget* widget =
+                views::Widget::GetWidgetForNativeWindow(top);
+            if (widget) {
+              exo::FullscreenShellSurface* full_screen_shell_surface =
+                  static_cast<exo::FullscreenShellSurface*>(
+                      widget->widget_delegate());
+              tree_data->focus_id = cache_->GetID(full_screen_shell_surface);
+              break;
+            }
+          }
+          for (aura::Window* child : top->children())
+            stack.push(child);
+        }
+        if (tree_data->focus_id == -1) {
+          LOG(ERROR) << "Could not find node to focus in desktop tree.";
+        }
+      }
     }
   }
   return true;
diff --git a/chromecast/browser/ui/aura/accessibility/ax_tree_source_aura.h b/chromecast/browser/ui/aura/accessibility/ax_tree_source_aura.h
index 1e78bf57..7f774aa5 100644
--- a/chromecast/browser/ui/aura/accessibility/ax_tree_source_aura.h
+++ b/chromecast/browser/ui/aura/accessibility/ax_tree_source_aura.h
@@ -25,6 +25,8 @@
                      ui::AXNodeData* out_data) const override;
 
  private:
+  views::AXAuraObjCache* cache_;
+
   DISALLOW_COPY_AND_ASSIGN(AXTreeSourceAura);
 };
 
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 59c33e9..83c6789 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-13038.0.0
\ No newline at end of file
+13039.0.0
\ No newline at end of file
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc
index 910e60b0..73124fc7 100644
--- a/chromeos/constants/chromeos_features.cc
+++ b/chromeos/constants/chromeos_features.cc
@@ -154,6 +154,10 @@
 const base::Feature kEduCoexistence{"EduCoexistence",
                                     base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables parent consent logging in EDU account addition flow.
+const base::Feature kEduCoexistenceConsentLog{
+    "EduCoexistenceConsentLog", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // If enabled, emoji suggestion will be shown when user type "space".
 const base::Feature kEmojiSuggestAddition{"EmojiSuggestAddition",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chromeos/constants/chromeos_features.h b/chromeos/constants/chromeos_features.h
index bfbef5a7..249ff9548 100644
--- a/chromeos/constants/chromeos_features.h
+++ b/chromeos/constants/chromeos_features.h
@@ -80,6 +80,8 @@
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kEduCoexistence;
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
+extern const base::Feature kEduCoexistenceConsentLog;
+COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kExoPointerLock;
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const base::Feature kFilesNG;
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const base::Feature kMojoDBusRelay;
diff --git a/chromeos/services/cros_healthd/public/cpp/service_connection_unittest.cc b/chromeos/services/cros_healthd/public/cpp/service_connection_unittest.cc
index 4e1fbb4..875150ea 100644
--- a/chromeos/services/cros_healthd/public/cpp/service_connection_unittest.cc
+++ b/chromeos/services/cros_healthd/public/cpp/service_connection_unittest.cc
@@ -117,9 +117,9 @@
   return mojom::CpuResult::NewCpuInfo(std::move(cpu_info));
 }
 
-mojom::TimezoneInfoPtr MakeTimezoneInfo() {
-  return mojom::TimezoneInfo::New("MST7MDT,M3.2.0,M11.1.0" /* posix */,
-                                  "America/Denver" /* region */);
+mojom::TimezoneResultPtr MakeTimezoneResult() {
+  return mojom::TimezoneResult::NewTimezoneInfo(mojom::TimezoneInfo::New(
+      "MST7MDT,M3.2.0,M11.1.0" /* posix */, "America/Denver" /* region */));
 }
 
 mojom::MemoryInfoPtr MakeMemoryInfo() {
@@ -138,11 +138,11 @@
   return backlight_info;
 }
 
-base::Optional<std::vector<mojom::FanInfoPtr>> MakeFanInfo() {
-  std::vector<mojom::FanInfoPtr> fan_info;
-  fan_info.push_back(mojom::FanInfo::New(1200 /* speed_rpm */));
-  fan_info.push_back(mojom::FanInfo::New(2650 /* speed_rpm */));
-  return fan_info;
+mojom::FanResultPtr MakeFanResult() {
+  std::vector<mojom::FanInfoPtr> fan_vector;
+  fan_vector.push_back(mojom::FanInfo::New(1200 /* speed_rpm */));
+  fan_vector.push_back(mojom::FanInfo::New(2650 /* speed_rpm */));
+  return mojom::FanResult::NewFanInfo(std::move(fan_vector));
 }
 
 mojom::TelemetryInfoPtr MakeTelemetryInfo() {
@@ -150,9 +150,9 @@
       MakeBatteryInfo() /* battery_info */,
       MakeNonRemovableBlockDeviceInfo() /* block_device_info */,
       MakeCachedVpdInfo() /* vpd_info */, MakeCpuResult() /* cpu_result */,
-      MakeTimezoneInfo() /* timezone_info */,
+      MakeTimezoneResult() /* timezone_result */,
       MakeMemoryInfo() /* memory_info */,
-      MakeBacklightInfo() /* backlight_info */, MakeFanInfo() /* fan_info */
+      MakeBacklightInfo() /* backlight_info */, MakeFanResult() /* fan_result */
   );
 }
 
diff --git a/chromeos/services/cros_healthd/public/mojom/cros_healthd_probe.mojom b/chromeos/services/cros_healthd/public/mojom/cros_healthd_probe.mojom
index d22fb65..8f42697 100644
--- a/chromeos/services/cros_healthd/public/mojom/cros_healthd_probe.mojom
+++ b/chromeos/services/cros_healthd/public/mojom/cros_healthd_probe.mojom
@@ -38,6 +38,8 @@
   kFileReadError,
   // An error parsing data into a consumable form.
   kParseError,
+  // An error using a system utility.
+  kSystemUtilityError,
 };
 
 // Structure that contains error information for a telemetry probe.
@@ -131,6 +133,15 @@
   uint32 max_clock_speed_khz;
 };
 
+// Timezone probe result. Can either be populated with the TimezoneInfo or an
+// error retrieving the information.
+union TimezoneResult {
+  // Valid TimezoneInfo.
+  TimezoneInfo timezone_info;
+  // The error that occurred attempting to retrieve the TimezoneInfo.
+  ProbeError error;
+};
+
 // Timezone information.
 struct TimezoneInfo {
   // The timezone of the device in POSIX standard.
@@ -162,6 +173,15 @@
   uint32 brightness;
 };
 
+// Fan probe result. Can either be populated with the FanInfo or an error
+// retrieving the information
+union FanResult {
+  // A list of valid FanInfo.
+  array<FanInfo> fan_info;
+  // The error that occurred attempting to retrieve the FanInfo.
+  ProbeError error;
+};
+
 // Fan information.
 struct FanInfo {
   // Fan speed in RPM.
@@ -191,7 +211,7 @@
   CpuResult? cpu_result;
   // Information about the device's timezone. Only present when kTimezone was
   // included in the categories input to ProbeTelemetryInfo.
-  TimezoneInfo? timezone_info;
+  TimezoneResult? timezone_result;
   // Information about the system's memory. Only present when kMemory was
   // included in the categories input to ProbeTelemetryInfo.
   MemoryInfo? memory_info;
@@ -200,5 +220,5 @@
   array<BacklightInfo>? backlight_info;
   // Information about each of the device's fans. Only present when kFan was
   // included in the categories input to ProbeTelemetryInfo.
-  array<FanInfo>? fan_info;
+  FanResult? fan_result;
 };
diff --git a/components/autofill/core/browser/address_rewriter.cc b/components/autofill/core/browser/address_rewriter.cc
index 1b85a50..030a5ab 100644
--- a/components/autofill/core/browser/address_rewriter.cc
+++ b/components/autofill/core/browser/address_rewriter.cc
@@ -57,7 +57,7 @@
                           CompiledRuleVector* compiled_rules) {
   base::StringPiece data = data_string;
   re2::RE2::Options options;
-  options.set_utf8(true);
+  options.set_encoding(RE2::Options::EncodingUTF8);
   options.set_word_boundary(true);
 
   size_t token_end = 0;
diff --git a/components/autofill/core/browser/geo/autofill_country.cc b/components/autofill/core/browser/geo/autofill_country.cc
index 4eb8f2b..961b1dc 100644
--- a/components/autofill/core/browser/geo/autofill_country.cc
+++ b/components/autofill/core/browser/geo/autofill_country.cc
@@ -25,13 +25,28 @@
 
 AutofillCountry::AutofillCountry(const std::string& country_code,
                                  const std::string& locale) {
-  auto result =
-      CountryDataMap::GetInstance()->country_data().find(country_code);
-  DCHECK(result != CountryDataMap::GetInstance()->country_data().end());
-  const CountryData& data = result->second;
+  CountryDataMap* country_data_map = CountryDataMap::GetInstance();
 
-  country_code_ = country_code;
-  name_ = l10n_util::GetDisplayNameForCountry(country_code, locale);
+  // If the country code is an alias (e.g. "GB" for "UK") expand the country
+  // code.
+  country_code_ = country_data_map->HasCountryCodeAlias(country_code)
+                      ? country_data_map->GetCountryCodeForAlias(country_code)
+                      : country_code;
+
+  // If there is no entry in the |CountryDataMap| for the
+  // |country_code_for_country_data| use the country code  derived from the
+  // locale. This reverts to US.
+  country_data_map->HasCountryData(country_code_)
+      ? country_code_
+      : CountryCodeForLocale(locale);
+
+  // Acquire the country address data.
+  const CountryData& data = country_data_map->GetCountryData(country_code_);
+
+  // Translate the country name by the supplied local.
+  name_ = l10n_util::GetDisplayNameForCountry(country_code_, locale);
+
+  // Get the localized strings associate with the address fields.
   postal_code_label_ = l10n_util::GetStringUTF16(data.postal_code_label_id);
   state_label_ = l10n_util::GetStringUTF16(data.state_label_id);
   address_required_fields_ = data.address_required_fields;
diff --git a/components/autofill/core/browser/geo/autofill_country_unittest.cc b/components/autofill/core/browser/geo/autofill_country_unittest.cc
index 8f3994d..94315c1 100644
--- a/components/autofill/core/browser/geo/autofill_country_unittest.cc
+++ b/components/autofill/core/browser/geo/autofill_country_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/android/build_info.h"
 #endif
 
+using autofill::CountryDataMap;
 using base::ASCIIToUTF16;
 
 namespace autofill {
@@ -30,6 +31,11 @@
   EXPECT_EQ("US", united_states_es.country_code());
   EXPECT_EQ(ASCIIToUTF16("Estados Unidos"), united_states_es.name());
 
+  AutofillCountry great_britain_uk_alias("UK", "en_GB");
+  EXPECT_EQ("GB", great_britain_uk_alias.country_code());
+  EXPECT_EQ("GB", great_britain_uk_alias.country_code());
+  EXPECT_EQ(ASCIIToUTF16("United Kingdom"), great_britain_uk_alias.name());
+
   AutofillCountry canada_en("CA", "en_US");
   EXPECT_EQ("CA", canada_en.country_code());
   EXPECT_EQ(ASCIIToUTF16("Canada"), canada_en.name());
@@ -74,4 +80,27 @@
   }
 }
 
+// Test alias mappings for falsely existing country codes.
+TEST(AutofillCountryTest, AliasMappingsForCountryData) {
+  CountryDataMap* country_data_map = CountryDataMap::GetInstance();
+
+  // There should be country data for the "GB".
+  EXPECT_TRUE(country_data_map->HasCountryData("GB"));
+
+  // Check the correctness of the alias definitions.
+  EXPECT_TRUE(country_data_map->HasCountryCodeAlias("UK"));
+  EXPECT_FALSE(country_data_map->HasCountryCodeAlias("does_not_exist"));
+
+  // Query not existing mapping.
+  auto expected_country_code = std::string();
+  auto actual_country_code =
+      country_data_map->GetCountryCodeForAlias("does_not_exist");
+  EXPECT_EQ(expected_country_code, actual_country_code);
+
+  // GB should map the UK.
+  expected_country_code = "GB";
+  actual_country_code = country_data_map->GetCountryCodeForAlias("UK");
+  EXPECT_EQ(expected_country_code, actual_country_code);
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/geo/country_data.cc b/components/autofill/core/browser/geo/country_data.cc
index 1105e78..e00e620 100644
--- a/components/autofill/core/browser/geo/country_data.cc
+++ b/components/autofill/core/browser/geo/country_data.cc
@@ -19,6 +19,17 @@
   CountryData country_data;
 };
 
+// Alias definitions record for CountryData requests.  A request for
+// |country_code_alias| is served with the |CountryData| for
+// |country_code_target|.
+struct StaticCountryCodeAliasData {
+  char country_code_alias[3];
+  char country_code_target[3];
+};
+
+// Alias definitions.
+const StaticCountryCodeAliasData kCountryCodeAliases[] = {{"UK", "GB"}};
+
 // Maps country codes to localized label string identifiers. Keep this sorted
 // by country code.
 // This list is comprized of countries appearing in both
@@ -790,7 +801,7 @@
   return country_codes;
 }
 
-std::map<std::string, CountryData> GetCountryData() {
+std::map<std::string, CountryData> GetCountryDataMap() {
   std::map<std::string, CountryData> country_data;
   // Add all the countries we have explicit data for.
   for (const auto& static_data : kCountryData) {
@@ -813,6 +824,18 @@
   return country_data;
 }
 
+std::map<std::string, std::string> GetCountryCodeAliasMap() {
+  std::map<std::string, std::string> country_code_aliases;
+  // Create mappings for the aliases defined in |kCountryCodeAliases|.
+  for (const auto& static_alias_data : kCountryCodeAliases) {
+    // Insert the alias.
+    country_code_aliases.insert(
+        std::make_pair(std::string(static_alias_data.country_code_alias),
+                       std::string(static_alias_data.country_code_target)));
+  }
+  return country_code_aliases;
+}
+
 }  // namespace
 
 // static
@@ -821,8 +844,38 @@
 }
 
 CountryDataMap::CountryDataMap()
-    : country_data_(GetCountryData()), country_codes_(GetCountryCodes()) {}
+    : country_data_(GetCountryDataMap()),
+      country_code_aliases_(GetCountryCodeAliasMap()),
+      country_codes_(GetCountryCodes()) {}
 
 CountryDataMap::~CountryDataMap() = default;
 
+bool CountryDataMap::HasCountryData(const std::string& country_code) const {
+  return country_data_.count(country_code) > 0;
+}
+
+const CountryData& CountryDataMap::GetCountryData(
+    const std::string& country_code) const {
+  auto lookup = country_data_.find(country_code);
+  if (lookup != country_data_.end())
+    return lookup->second;
+  // If there is no entry for country_code return the entry for the US.
+  return country_data_.find("US")->second;
+}
+
+bool CountryDataMap::HasCountryCodeAlias(
+    const std::string& country_code_alias) const {
+  return country_code_aliases_.count(country_code_alias) > 0;
+}
+
+const std::string CountryDataMap::GetCountryCodeForAlias(
+    const std::string& country_code_alias) const {
+  auto lookup = country_code_aliases_.find(country_code_alias);
+  if (lookup != country_code_aliases_.end()) {
+    DCHECK(HasCountryData(lookup->second));
+    return lookup->second;
+  }
+  return std::string();
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/geo/country_data.h b/components/autofill/core/browser/geo/country_data.h
index b6a9497..8266102 100644
--- a/components/autofill/core/browser/geo/country_data.h
+++ b/components/autofill/core/browser/geo/country_data.h
@@ -58,10 +58,23 @@
  public:
   static CountryDataMap* GetInstance();
 
-  const std::map<std::string, CountryData>& country_data() {
-    return country_data_;
-  }
+  // Returns true if a |CountryData| entry for the supplied |country_code|
+  // exists.
+  bool HasCountryData(const std::string& country_code) const;
 
+  // Returns true if there is a country code alias for |country_code|.
+  bool HasCountryCodeAlias(const std::string& country_code_alias) const;
+
+  // Returns the country code for a country code alias. If no alias definition
+  // is present return an empty string.
+  const std::string GetCountryCodeForAlias(
+      const std::string& country_code_alias) const;
+
+  // Lookup the |CountryData| for the supplied |country_code|. If no entry
+  // exists, return the data for the US as a best guess.
+  const CountryData& GetCountryData(const std::string& country_code) const;
+
+  // Return a constant reference to a vector of all country codes.
   const std::vector<std::string>& country_codes() { return country_codes_; }
 
  private:
@@ -70,6 +83,7 @@
   friend struct base::DefaultSingletonTraits<CountryDataMap>;
 
   const std::map<std::string, CountryData> country_data_;
+  const std::map<std::string, std::string> country_code_aliases_;
   const std::vector<std::string> country_codes_;
 
   DISALLOW_COPY_AND_ASSIGN(CountryDataMap);
diff --git a/components/autofill/core/browser/ui/popup_item_ids.h b/components/autofill/core/browser/ui/popup_item_ids.h
index 4d7333b..f975bc36 100644
--- a/components/autofill/core/browser/ui/popup_item_ids.h
+++ b/components/autofill/core/browser/ui/popup_item_ids.h
@@ -34,6 +34,7 @@
   POPUP_ITEM_ID_ACCOUNT_STORAGE_PASSWORD_ENTRY = -22,
   POPUP_ITEM_ID_ACCOUNT_STORAGE_USERNAME_ENTRY = -23,
   POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_RE_SIGNIN = -24,
+  POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_EMPTY = -25,
 };
 
 }  // namespace autofill
diff --git a/components/os_crypt/key_storage_libsecret.cc b/components/os_crypt/key_storage_libsecret.cc
index 975a69e..a0aa3d0 100644
--- a/components/os_crypt/key_storage_libsecret.cc
+++ b/components/os_crypt/key_storage_libsecret.cc
@@ -19,14 +19,6 @@
 const char kApplicationName[] = "chromium";
 #endif
 
-// Deprecated in M55 (crbug.com/639298)
-const SecretSchema kKeystoreSchemaV1 = {
-    "chrome_libsecret_os_crypt_password",
-    SECRET_SCHEMA_NONE,
-    {
-        {nullptr, SECRET_SCHEMA_ATTRIBUTE_STRING},
-    }};
-
 const SecretSchema kKeystoreSchemaV2 = {
     "chrome_libsecret_os_crypt_password_v2",
     SECRET_SCHEMA_DONT_MATCH_NAME,
@@ -106,9 +98,6 @@
 
   SecretValue* password_libsecret = ToSingleSecret(helper.results());
   if (!password_libsecret) {
-    std::string password = Migrate();
-    if (!password.empty())
-      return password;
     return AddRandomPasswordInLibsecret();
   }
   AnalyseKeyHistory(helper.results());
@@ -124,52 +113,3 @@
     LibsecretLoader::EnsureKeyringUnlocked();
   return loaded;
 }
-
-std::string KeyStorageLibsecret::Migrate() {
-  LibsecretAttributesBuilder attrs;
-
-  // Detect old entry.
-  LibsecretLoader::SearchHelper helper;
-  helper.Search(&kKeystoreSchemaV1, attrs.Get(),
-                SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS);
-  if (!helper.success())
-    return std::string();
-
-  SecretValue* password_libsecret = ToSingleSecret(helper.results());
-  if (!password_libsecret)
-    return std::string();
-
-  VLOG(1) << "OSCrypt detected a deprecated password in Libsecret.";
-  std::string password(
-      LibsecretLoader::secret_value_get_text(password_libsecret));
-  LibsecretLoader::secret_value_unref(password_libsecret);
-
-  // Create new entry.
-  GError* error = nullptr;
-  bool success = LibsecretLoader::secret_password_store_sync(
-      &kKeystoreSchemaV2, nullptr, KeyStorageLinux::kKey, password.c_str(),
-      nullptr, &error, "application", kApplicationName, nullptr);
-  if (error) {
-    VLOG(1) << "Failed to store migrated password. " << error->message;
-    g_error_free(error);
-    return std::string();
-  }
-  if (!success) {
-    VLOG(1) << "Failed to store migrated password.";
-    return std::string();
-  }
-
-  // Delete old entry.
-  // Even if deletion failed, we have to use the password that we created.
-  success = LibsecretLoader::secret_password_clear_sync(
-      &kKeystoreSchemaV1, nullptr, &error, nullptr);
-  if (error) {
-    VLOG(1) << "OSCrypt failed to delete deprecated password. "
-            << error->message;
-    g_error_free(error);
-  }
-
-  VLOG(1) << "OSCrypt migrated from deprecated password.";
-
-  return password;
-}
diff --git a/components/os_crypt/key_storage_libsecret.h b/components/os_crypt/key_storage_libsecret.h
index 31cf0c7..3679633a 100644
--- a/components/os_crypt/key_storage_libsecret.h
+++ b/components/os_crypt/key_storage_libsecret.h
@@ -25,12 +25,6 @@
  private:
   std::string AddRandomPasswordInLibsecret();
 
-  // TODO(crbug.com/639298) Older Chromium releases stored passwords with a
-  // problematic schema. Detect password entries with the old schema and migrate
-  // them to the new schema. Returns the migrated password or an empty string if
-  // none we migrated.
-  std::string Migrate();
-
   DISALLOW_COPY_AND_ASSIGN(KeyStorageLibsecret);
 };
 
diff --git a/components/os_crypt/key_storage_libsecret_unittest.cc b/components/os_crypt/key_storage_libsecret_unittest.cc
index b2e1bf8..60749878 100644
--- a/components/os_crypt/key_storage_libsecret_unittest.cc
+++ b/components/os_crypt/key_storage_libsecret_unittest.cc
@@ -14,13 +14,6 @@
 
 namespace {
 
-const SecretSchema kKeystoreSchemaV1 = {
-    "chrome_libsecret_os_crypt_password",
-    SECRET_SCHEMA_NONE,
-    {
-        {nullptr, SECRET_SCHEMA_ATTRIBUTE_STRING},
-    }};
-
 const SecretSchema kKeystoreSchemaV2 = {
     "chrome_libsecret_os_crypt_password_v2",
     SECRET_SCHEMA_DONT_MATCH_NAME,
@@ -41,8 +34,7 @@
  public:
   void Reset() {
     mapping_.clear();
-    ClearV1Password();
-    ClearV2Password();
+    ClearPassword();
     for (GObject* o : objects_returned_to_caller_) {
       ASSERT_EQ(o->ref_count, 1u);
       g_object_unref(o);
@@ -50,31 +42,18 @@
     objects_returned_to_caller_.clear();
   }
 
-  void ClearV1Password() {
-    if (v1_password_) {
-      ASSERT_EQ(v1_password_->ref_count, 1u);
-      g_object_unref(v1_password_);
-      v1_password_ = nullptr;
-    }
-  }
-  void ClearV2Password() {
-    if (v2_password_) {
-      ASSERT_EQ(v2_password_->ref_count, 1u);
-      g_object_unref(v2_password_);
-      v2_password_ = nullptr;
+  void ClearPassword() {
+    if (password_) {
+      ASSERT_EQ(password_->ref_count, 1u);
+      g_object_unref(password_);
+      password_ = nullptr;
     }
   }
 
-  void SetV1Password(const std::string& password) {
-    ASSERT_FALSE(v1_password_);
-    v1_password_ = static_cast<GObject*>(g_object_new(G_TYPE_OBJECT, nullptr));
-    mapping_[v1_password_] = password;
-  }
-
-  void SetV2Password(const std::string& password) {
-    ASSERT_FALSE(v2_password_);
-    v2_password_ = static_cast<GObject*>(g_object_new(G_TYPE_OBJECT, nullptr));
-    mapping_[v2_password_] = password;
+  void SetPassword(const std::string& password) {
+    ASSERT_FALSE(password_);
+    password_ = static_cast<GObject*>(g_object_new(G_TYPE_OBJECT, nullptr));
+    mapping_[password_] = password;
   }
 
   GObject* MakeTempObject(const std::string& value) {
@@ -92,13 +71,11 @@
     return mapping_[static_cast<GObject*>(opaque_id)].c_str();
   }
 
-  GObject* v1_password() { return v1_password_; }
-  GObject* v2_password() { return v2_password_; }
+  GObject* password() { return password_; }
 
   std::unordered_map<GObject*, std::string> mapping_;
   std::vector<GObject*> objects_returned_to_caller_;
-  GObject* v1_password_ = nullptr;
-  GObject* v2_password_ = nullptr;
+  GObject* password_ = nullptr;
 };
 base::LazyInstance<MockPasswordStore>::Leaky g_password_store =
     LAZY_INSTANCE_INITIALIZER;
@@ -137,11 +114,6 @@
                                                 GCancellable* cancellable,
                                                 GError** error);
 
-  static gboolean mock_secret_password_clear_sync(const SecretSchema* schema,
-                                                  GCancellable* cancellable,
-                                                  GError** error,
-                                                  ...);
-
   static SecretValue* mock_secret_item_get_secret(SecretItem* item);
 
   static guint64 mock_secret_item_get_created(SecretItem* item);
@@ -168,7 +140,7 @@
     return true;
 
   EXPECT_STREQ(kKeystoreSchemaV2.name, schema->name);
-  g_password_store.Pointer()->SetV2Password(password);
+  g_password_store.Pointer()->SetPassword(password);
   return true;
 }
 
@@ -185,24 +157,16 @@
     SecretSearchFlags flags,
     GCancellable* cancellable,
     GError** error) {
-  bool is_known_schema = strcmp(schema->name, kKeystoreSchemaV2.name) == 0 ||
-                         strcmp(schema->name, kKeystoreSchemaV1.name) == 0;
-  EXPECT_TRUE(is_known_schema);
+  EXPECT_STREQ(kKeystoreSchemaV2.name, schema->name);
 
   EXPECT_TRUE(flags & SECRET_SEARCH_UNLOCK);
   EXPECT_TRUE(flags & SECRET_SEARCH_LOAD_SECRETS);
 
   GObject* item = nullptr;
   MockPasswordStore* store = g_password_store.Pointer();
-  if (strcmp(schema->name, kKeystoreSchemaV2.name) == 0) {
-    GObject* password = store->v2_password();
-    if (password)
-      item = store->MakeTempObject(store->GetString(password));
-  } else if (strcmp(schema->name, kKeystoreSchemaV1.name) == 0) {
-    GObject* password = store->v1_password();
-    if (password)
-      item = store->MakeTempObject(store->GetString(password));
-  }
+  GObject* password = store->password();
+  if (password)
+    item = store->MakeTempObject(store->GetString(password));
 
   if (!item) {
     return nullptr;
@@ -215,18 +179,6 @@
 }
 
 // static
-gboolean MockLibsecretLoader::mock_secret_password_clear_sync(
-    const SecretSchema* schema,
-    GCancellable* cancellable,
-    GError** error,
-    ...) {
-  // We would only delete entries in the deprecated schema.
-  EXPECT_STREQ(kKeystoreSchemaV1.name, schema->name);
-  g_password_store.Pointer()->ClearV1Password();
-  return true;
-}
-
-// static
 SecretValue* MockLibsecretLoader::mock_secret_item_get_secret(
     SecretItem* item) {
   // Add a ref to make sure that the caller unrefs with secret_value_unref.
@@ -254,9 +206,6 @@
   secret_service_search_sync =
       &MockLibsecretLoader::mock_secret_service_search_sync;
   secret_item_get_secret = &MockLibsecretLoader::mock_secret_item_get_secret;
-  // Used by Migrate()
-  secret_password_clear_sync =
-      &MockLibsecretLoader::mock_secret_password_clear_sync;
   secret_item_get_created = &MockLibsecretLoader::mock_secret_item_get_created;
   secret_item_get_modified =
       &MockLibsecretLoader::mock_secret_item_get_modified;
@@ -290,7 +239,7 @@
 TEST_F(LibsecretTest, LibsecretRepeats) {
   KeyStorageLibsecret libsecret;
   MockLibsecretLoader::ResetForOSCrypt();
-  g_password_store.Pointer()->SetV2Password("initial password");
+  g_password_store.Pointer()->SetPassword("initial password");
   std::string password = libsecret.GetKey();
   EXPECT_FALSE(password.empty());
   std::string password_repeat = libsecret.GetKey();
@@ -306,13 +255,4 @@
   EXPECT_NE(password, password_new);
 }
 
-TEST_F(LibsecretTest, LibsecretMigratesFromSchemaV1ToV2) {
-  KeyStorageLibsecret libsecret;
-  MockLibsecretLoader::ResetForOSCrypt();
-  g_password_store.Pointer()->SetV1Password("swallow");
-  g_password_store.Pointer()->ClearV2Password();
-  std::string password = libsecret.GetKey();
-  EXPECT_EQ("swallow", password);
-}
-
 }  // namespace
diff --git a/components/password_manager/content/browser/content_password_manager_driver.cc b/components/password_manager/content/browser/content_password_manager_driver.cc
index 7929c2d..b896caf4 100644
--- a/components/password_manager/content/browser/content_password_manager_driver.cc
+++ b/components/password_manager/content/browser/content_password_manager_driver.cc
@@ -112,6 +112,7 @@
 }
 
 void ContentPasswordManagerDriver::InformNoSavedCredentials() {
+  GetPasswordAutofillManager()->OnNoCredentialsFound();
   GetPasswordAutofillAgent()->InformNoSavedCredentials();
 }
 
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc
index 311a692..d6b0a90 100644
--- a/components/password_manager/core/browser/login_database.cc
+++ b/components/password_manager/core/browser/login_database.cc
@@ -392,12 +392,60 @@
          "here.";
 }
 
+// Callback called upon each migration step of the logins table. It's used to
+// inject custom schema migration logic not covered by the generic
+// SQLTableBuilder migration. |new_version| indicates how far
+// SQLTableBuilder is in the migration process.
+bool LoginsTablePostMigrationStepCallback(sql::Database* db,
+                                          unsigned new_version) {
+  // In version 26, the primary key of the logins table became an
+  // AUTOINCREMENT field. Since SQLite doesn't allow changing the column type,
+  // the only way is to actually create a temp table with the primary key
+  // properly set as an AUTOINCREMENT field, and move the data there. The code
+  // has been adjusted such that newly created tables have the primary key
+  // properly set as AUTOINCREMENT.
+  if (new_version == 26) {
+    // This statement creates the logins database similar to version 26 with
+    // the primary key column set to AUTOINCREMENT.
+    const char temp_table_create_statement_version_26[] =
+        "CREATE TABLE logins_temp (origin_url VARCHAR NOT NULL,action_url "
+        "VARCHAR,username_element VARCHAR,username_value "
+        "VARCHAR,password_element VARCHAR,password_value BLOB,submit_element "
+        "VARCHAR,signon_realm VARCHAR NOT NULL,preferred INTEGER NOT "
+        "NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT "
+        "NULL,scheme INTEGER NOT NULL,password_type INTEGER,times_used "
+        "INTEGER,form_data BLOB,date_synced INTEGER,display_name "
+        "VARCHAR,icon_url VARCHAR,federation_url VARCHAR,skip_zero_click "
+        "INTEGER,generation_upload_status INTEGER,possible_username_pairs "
+        "BLOB,id INTEGER PRIMARY KEY AUTOINCREMENT,date_last_used "
+        "INTEGER,UNIQUE (origin_url, username_element, username_value, "
+        "password_element, signon_realm))";
+    const char move_data_statement[] =
+        "INSERT INTO logins_temp SELECT * from logins";
+    const char drop_table_statement[] = "DROP TABLE logins";
+    const char rename_table_statement[] =
+        "ALTER TABLE logins_temp RENAME TO logins";
+
+    sql::Transaction transaction(db);
+    if (!(transaction.Begin() &&
+          db->Execute(temp_table_create_statement_version_26) &&
+          db->Execute(move_data_statement) &&
+          db->Execute(drop_table_statement) &&
+          db->Execute(rename_table_statement) && transaction.Commit())) {
+      return false;
+    }
+  }
+  return true;
+}
+
 // Call this after having called InitializeBuilders(), to migrate the database
 // from the current version to kCurrentVersionNumber.
 bool MigrateLogins(unsigned current_version,
                    SQLTableBuilders builders,
                    sql::Database* db) {
-  if (!builders.logins->MigrateFrom(current_version, db))
+  if (!builders.logins->MigrateFrom(
+          current_version, db,
+          base::BindRepeating(&LoginsTablePostMigrationStepCallback)))
     return false;
 
   if (!builders.sync_entities_metadata->MigrateFrom(current_version, db))
@@ -453,45 +501,6 @@
       return false;
   }
 
-  // In version 26, the primary key of the logins table became an AUTOINCREMENT
-  // field. Since SQLite doesn't allow changing the column type, the only way is
-  // to actually create a temp table with the primary key propely set as an
-  // AUTOINCREMENT field, and move the data there. The code has been adjusted
-  // such that newly created tables have the primary key properly set as
-  // AUTOINCREMENT.
-  if (current_version < 26) {
-    // This statement creates the logins database similar to version 26 with the
-    // primary key column set to AUTOINCREMENT.
-    std::string temp_table_create_statement_version_26 =
-        "CREATE TABLE logins_temp (origin_url VARCHAR NOT NULL,action_url "
-        "VARCHAR,username_element VARCHAR,username_value "
-        "VARCHAR,password_element VARCHAR,password_value BLOB,submit_element "
-        "VARCHAR,signon_realm VARCHAR NOT NULL,preferred INTEGER NOT "
-        "NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT "
-        "NULL,scheme INTEGER NOT NULL,password_type INTEGER,times_used "
-        "INTEGER,form_data BLOB,date_synced INTEGER,display_name "
-        "VARCHAR,icon_url VARCHAR,federation_url VARCHAR,skip_zero_click "
-        "INTEGER,generation_upload_status INTEGER,possible_username_pairs "
-        "BLOB,id INTEGER PRIMARY KEY AUTOINCREMENT,date_last_used "
-        "INTEGER,UNIQUE (origin_url, username_element, username_value, "
-        "password_element, signon_realm))";
-    std::string move_data_statement =
-        "INSERT INTO logins_temp SELECT * from logins";
-    std::string drop_table_statement = "DROP TABLE logins";
-    std::string rename_table_statement =
-        "ALTER TABLE logins_temp RENAME TO logins";
-
-    sql::Transaction transaction(db);
-    if (!(transaction.Begin() &&
-          db->Execute(temp_table_create_statement_version_26.c_str()) &&
-          db->Execute(move_data_statement.c_str()) &&
-          db->Execute(drop_table_statement.c_str()) &&
-          db->Execute(rename_table_statement.c_str()) &&
-          transaction.Commit())) {
-      return false;
-    }
-  }
-
   return true;
 }
 
diff --git a/components/password_manager/core/browser/password_autofill_manager.cc b/components/password_manager/core/browser/password_autofill_manager.cc
index 9690704d..3dc0b88 100644
--- a/components/password_manager/core/browser/password_autofill_manager.cc
+++ b/components/password_manager/core/browser/password_autofill_manager.cc
@@ -260,6 +260,16 @@
   return suggestion;
 }
 
+// Entry showing the empty state (i.e. no passwords found in account-storage).
+autofill::Suggestion CreateAccountStorageEmptyEntry() {
+  autofill::Suggestion suggestion(
+      l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_NO_ACCOUNT_STORE_MATCHES));
+  suggestion.frontend_id =
+      autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_EMPTY;
+  suggestion.icon = "empty";
+  return suggestion;
+}
+
 bool ContainsOtherThanManagePasswords(
     const std::vector<autofill::Suggestion> suggestions) {
   return std::any_of(suggestions.begin(), suggestions.end(),
@@ -278,6 +288,15 @@
                      });
 }
 
+bool HasLoadingSuggestion(base::span<const autofill::Suggestion> suggestions,
+                          autofill::PopupItemId item_id) {
+  return std::any_of(suggestions.begin(), suggestions.end(),
+                     [&item_id](const autofill::Suggestion& suggestion) {
+                       return suggestion.frontend_id == item_id &&
+                              suggestion.is_loading;
+                     });
+}
+
 std::vector<autofill::Suggestion> SetUnlockLoadingState(
     base::span<const autofill::Suggestion> suggestions,
     autofill::PopupItemId unlock_item,
@@ -329,6 +348,7 @@
                                                   int identifier) {
   ClearPreviewedForm();
   if (identifier == autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY ||
+      identifier == autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_EMPTY ||
       identifier == autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY ||
       identifier == autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN ||
       identifier ==
@@ -375,7 +395,9 @@
     metrics_util::LogPasswordDropdownItemSelected(
         PasswordDropdownSelectedOption::kGenerate,
         password_client_->IsIncognito());
-  } else if (identifier == autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY) {
+  } else if (identifier == autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY ||
+             identifier ==
+                 autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_EMPTY) {
     password_client_->NavigateToManagePasswordsPage(
         ManagePasswordsReferrer::kPasswordDropdown);
     metrics_util::LogContextOfShowAllSavedPasswordsAccepted(
@@ -461,7 +483,6 @@
 
   if (!autofill_client_ || autofill_client_->GetPopupSuggestions().empty())
     return;
-  // TODO(https://crbug.com/1043963): Add empty state.
   UpdatePopup(BuildSuggestions(base::string16(),
                                ForPasswordField(AreSuggestionForPasswordField(
                                    autofill_client_->GetPopupSuggestions())),
@@ -469,6 +490,15 @@
                                ShowPasswordSuggestions(true)));
 }
 
+void PasswordAutofillManager::OnNoCredentialsFound() {
+  if (!autofill_client_ ||
+      !HasLoadingSuggestion(
+          autofill_client_->GetPopupSuggestions(),
+          autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN))
+    return;
+  UpdatePopup({CreateAccountStorageEmptyEntry()});
+}
+
 void PasswordAutofillManager::DeleteFillData() {
   fill_data_.reset();
   if (autofill_client_) {
@@ -586,6 +616,7 @@
   for (const auto& suggestion : suggestions) {
     switch (suggestion.frontend_id) {
       case autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY:
+      case autofill::PopupItemId::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_EMPTY:
         metrics_util::LogContextOfShowAllSavedPasswordsShown(
             metrics_util::ShowAllSavedPasswordsContext::kPassword);
         continue;
@@ -720,6 +751,8 @@
     if (unlock_item ==
         autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE) {
       password_client_->GeneratePassword();
+      autofill_client_->HideAutofillPopup(
+          autofill::PopupHidingReason::kAcceptSuggestion);
     }
     return;
   }
diff --git a/components/password_manager/core/browser/password_autofill_manager.h b/components/password_manager/core/browser/password_autofill_manager.h
index 06075c8d..db91791 100644
--- a/components/password_manager/core/browser/password_autofill_manager.h
+++ b/components/password_manager/core/browser/password_autofill_manager.h
@@ -94,6 +94,10 @@
   // Called when main frame navigates. Not called for in-page navigations.
   void DidNavigateMainFrame();
 
+  // Called if no suggestions were found. Assumed to be mutually exclusive with
+  // |OnAddPasswordFillData|.
+  void OnNoCredentialsFound();
+
   // A public version of FillSuggestion(), only for use in tests.
   bool FillSuggestionForTest(const base::string16& username);
 
diff --git a/components/password_manager/core/browser/password_autofill_manager_unittest.cc b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
index 24470d9..8312aa9 100644
--- a/components/password_manager/core/browser/password_autofill_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
@@ -789,6 +789,9 @@
       });
   EXPECT_CALL(*client.GetPasswordFeatureManager(),
               SetAccountStorageOptIn(true));
+  EXPECT_CALL(
+      autofill_client,
+      HideAutofillPopup(autofill::PopupHidingReason::kAcceptSuggestion));
   EXPECT_CALL(client, GeneratePassword());
 
   password_autofill_manager_->DidAcceptSuggestion(
@@ -796,6 +799,39 @@
       autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN_AND_GENERATE, 1);
 }
 
+// Test that the popup shows an empty state if opted-into an empty store.
+TEST_F(PasswordAutofillManagerTest, SuccessfullOptInMayShowEmptyState) {
+  TestPasswordManagerClient client;
+  NiceMock<MockAutofillClient> autofill_client;
+  InitializePasswordAutofillManager(&client, &autofill_client);
+  client.SetAccountStorageOptIn(true);
+  const CoreAccountId kAliceId = client.identity_test_env()
+                                     .SetUnconsentedPrimaryAccount(kAliceEmail)
+                                     .account_id;
+  testing::Mock::VerifyAndClearExpectations(&autofill_client);
+
+  // Only the unlock button was available. After being clicked, it's in a
+  // loading state which the DeleteFillData() call will end.
+  Suggestion unlock_suggestion(
+      /*label=*/"Unlock passwords and fill", /*value=*/"", /*icon=*/"",
+      /*fronend_id=*/
+      autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN);
+  unlock_suggestion.is_loading = Suggestion::IsLoading(true);
+  EXPECT_CALL(autofill_client, GetPopupSuggestions)
+      .WillRepeatedly(Return(std::vector<Suggestion>{unlock_suggestion}));
+  EXPECT_CALL(autofill_client,
+              HideAutofillPopup(autofill::PopupHidingReason::kStaleData));
+  EXPECT_CALL(
+      autofill_client,
+      UpdatePopup(
+          SuggestionVectorIdsAre(ElementsAreArray(
+              {autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_EMPTY})),
+          PopupType::kPasswords));
+
+  password_autofill_manager_->DeleteFillData();
+  password_autofill_manager_->OnNoCredentialsFound();
+}
+
 // Test that the popup is updated once "opt in and fill" is clicked".
 TEST_F(PasswordAutofillManagerTest,
        AddOnFillDataAfterOptInAndFillPopulatesPopup) {
@@ -813,10 +849,11 @@
   base::string16 additional_username(base::ASCIIToUTF16("bar.foo@example.com"));
   new_data.additional_logins[additional_username] = additional;
   EXPECT_CALL(autofill_client, GetPopupSuggestions())
-      .Times(2)
       .WillRepeatedly(Return(CreateTestSuggestions(
           /*has_opt_in_and_fill=*/false, /*has_opt_in_and_generate*/ false,
           /*has_re_signin=*/false)));
+  EXPECT_CALL(autofill_client,
+              HideAutofillPopup(autofill::PopupHidingReason::kStaleData));
   EXPECT_CALL(
       autofill_client,
       UpdatePopup(
@@ -825,6 +862,8 @@
                autofill::POPUP_ITEM_ID_PASSWORD_ENTRY,
                autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY}))),
           PopupType::kPasswords));
+
+  password_autofill_manager_->DeleteFillData();
   password_autofill_manager_->OnAddPasswordFillData(new_data);
 }
 
diff --git a/components/password_manager/core/browser/sql_table_builder.cc b/components/password_manager/core/browser/sql_table_builder.cc
index 36455d6..274789a7b 100644
--- a/components/password_manager/core/browser/sql_table_builder.cc
+++ b/components/password_manager/core/browser/sql_table_builder.cc
@@ -196,11 +196,17 @@
   return ++sealed_version_;
 }
 
-bool SQLTableBuilder::MigrateFrom(unsigned old_version,
-                                  sql::Database* db) const {
+bool SQLTableBuilder::MigrateFrom(
+    unsigned old_version,
+    sql::Database* db,
+    const base::RepeatingCallback<bool(sql::Database*, unsigned)>&
+        post_migration_step_callback) const {
   for (; old_version < sealed_version_; ++old_version) {
     if (!MigrateToNextFrom(old_version, db))
       return false;
+    if (post_migration_step_callback &&
+        !post_migration_step_callback.Run(db, old_version + 1))
+      return false;
   }
 
   return true;
diff --git a/components/password_manager/core/browser/sql_table_builder.h b/components/password_manager/core/browser/sql_table_builder.h
index 1c8f46c6..838b958 100644
--- a/components/password_manager/core/browser/sql_table_builder.h
+++ b/components/password_manager/core/browser/sql_table_builder.h
@@ -1,6 +1,6 @@
-// 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.
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
 #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SQL_TABLE_BUILDER_H_
 #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SQL_TABLE_BUILDER_H_
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "base/bind_helpers.h"
 #include "base/macros.h"
 #include "base/strings/string_piece.h"
 
@@ -87,7 +88,17 @@
   // Assuming that the database connected through |db| contains a table called
   // |table_name_| in a state described by version |old_version|, migrates it to
   // the current version, which must be sealed. Returns true on success.
-  bool MigrateFrom(unsigned old_version, sql::Database* db) const;
+  // |post_migration_step_callback| is executed after each migration step in to
+  // allow the calling site to inject custom logic to run upon each migration
+  // step from |old_version| to the current version. The passed parameter
+  // corresponds to database to be migrated and the new version number that has
+  // been reached after the migration step. |post_migration_step_callback|
+  // returns true on success, otherwise the migration is aborted.
+  bool MigrateFrom(
+      unsigned old_version,
+      sql::Database* db,
+      const base::RepeatingCallback<bool(sql::Database*, unsigned)>&
+          post_migration_step_callback = base::NullCallback()) const;
 
   // If |db| connects to a database where table |table_name_| already exists,
   // this is a no-op and returns true. Otherwise, |table_name_| is created in a
diff --git a/components/password_manager/core/browser/sql_table_builder_unittest.cc b/components/password_manager/core/browser/sql_table_builder_unittest.cc
index 80c4408..d35786da 100644
--- a/components/password_manager/core/browser/sql_table_builder_unittest.cc
+++ b/components/password_manager/core/browser/sql_table_builder_unittest.cc
@@ -7,11 +7,13 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/macros.h"
+#include "base/test/mock_callback.h"
 #include "sql/database.h"
 #include "sql/statement.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using ::testing::Return;
 using ::testing::UnorderedElementsAre;
 
 namespace password_manager {
@@ -310,4 +312,26 @@
       std::string::npos);
 }
 
+TEST_F(SQLTableBuilderTest, MigrateFromWithSuccessfulCallback) {
+  EXPECT_EQ(0u, builder()->SealVersion());
+  EXPECT_EQ(1u, builder()->SealVersion());
+
+  base::MockCallback<base::RepeatingCallback<bool(sql::Database*, unsigned)>>
+      migation_callback;
+
+  EXPECT_CALL(migation_callback, Run(db(), 1u)).WillOnce(Return(true));
+  EXPECT_TRUE(builder()->MigrateFrom(0, db(), migation_callback.Get()));
+}
+
+TEST_F(SQLTableBuilderTest, MigrateFromWithUnsuccessfulCallback) {
+  EXPECT_EQ(0u, builder()->SealVersion());
+  EXPECT_EQ(1u, builder()->SealVersion());
+
+  base::MockCallback<base::RepeatingCallback<bool(sql::Database*, unsigned)>>
+      migation_callback;
+
+  EXPECT_CALL(migation_callback, Run(db(), 1u)).WillOnce(Return(false));
+  EXPECT_FALSE(builder()->MigrateFrom(0, db(), migation_callback.Get()));
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager_strings.grdp b/components/password_manager_strings.grdp
index c2ab7de..18c1a4d 100644
--- a/components/password_manager_strings.grdp
+++ b/components/password_manager_strings.grdp
@@ -43,6 +43,9 @@
   <message name="IDS_PASSWORD_MANAGER_RE_SIGNIN_ACCOUNT_STORE" desc="A menu item informing signed-out users to sign-in again to use account-stored passwords.">
     Sign in to use passwords stored in your Google account
   </message>
+  <message name="IDS_PASSWORD_MANAGER_NO_ACCOUNT_STORE_MATCHES" desc="The menu item indicating that the account store doesn't contain passwords for the current site.">
+    No password match. Manage all saved passwords.
+  </message>
   <if expr="not use_titlecase">
     <message name="IDS_PASSWORD_MANAGER_MANAGE_PASSWORDS" desc="The menu item in the password field drop down that opens the list of saved passwords.">
       Manage passwords…
diff --git a/components/password_manager_strings_grdp/IDS_PASSWORD_MANAGER_NO_ACCOUNT_STORE_MATCHES.png.sha1 b/components/password_manager_strings_grdp/IDS_PASSWORD_MANAGER_NO_ACCOUNT_STORE_MATCHES.png.sha1
new file mode 100644
index 0000000..8f714ef
--- /dev/null
+++ b/components/password_manager_strings_grdp/IDS_PASSWORD_MANAGER_NO_ACCOUNT_STORE_MATCHES.png.sha1
@@ -0,0 +1 @@
+5a36eba8302b1aca1911d2a2873ecbc09363d290
\ No newline at end of file
diff --git a/components/performance_manager/graph/frame_node_impl.cc b/components/performance_manager/graph/frame_node_impl.cc
index 6eb3db5..bd2d47c 100644
--- a/components/performance_manager/graph/frame_node_impl.cc
+++ b/components/performance_manager/graph/frame_node_impl.cc
@@ -87,15 +87,22 @@
   is_ad_frame_.SetAndMaybeNotify(this, true);
 }
 
+void FrameNodeImpl::SetHadFormInteraction() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  document_.had_form_interaction.SetAndMaybeNotify(this, true);
+}
+
 void FrameNodeImpl::OnNonPersistentNotificationCreated() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   for (auto* observer : GetObservers())
     observer->OnNonPersistentNotificationCreated(this);
 }
 
-void FrameNodeImpl::SetHadFormInteraction() {
+void FrameNodeImpl::OnFirstContentfulPaint(
+    base::TimeDelta time_since_navigation_start) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  document_.had_form_interaction.SetAndMaybeNotify(this, true);
+  for (auto* observer : GetObservers())
+    observer->OnFirstContentfulPaint(this, time_since_navigation_start);
 }
 
 const RenderFrameHostProxy& FrameNodeImpl::GetRenderFrameHostProxy() const {
diff --git a/components/performance_manager/graph/frame_node_impl.h b/components/performance_manager/graph/frame_node_impl.h
index 2ac334d..0fd7658 100644
--- a/components/performance_manager/graph/frame_node_impl.h
+++ b/components/performance_manager/graph/frame_node_impl.h
@@ -77,8 +77,10 @@
   void SetHasNonEmptyBeforeUnload(bool has_nonempty_beforeunload) override;
   void SetOriginTrialFreezePolicy(mojom::InterventionPolicy policy) override;
   void SetIsAdFrame() override;
-  void OnNonPersistentNotificationCreated() override;
   void SetHadFormInteraction() override;
+  void OnNonPersistentNotificationCreated() override;
+  void OnFirstContentfulPaint(
+      base::TimeDelta time_since_navigation_start) override;
   const RenderFrameHostProxy& GetRenderFrameHostProxy() const override;
 
   // Partial FrameNodbase::TimeDelta time_since_navigatione implementation:
diff --git a/components/performance_manager/graph/frame_node_impl_unittest.cc b/components/performance_manager/graph/frame_node_impl_unittest.cc
index 4c1c0d3..baf144f0 100644
--- a/components/performance_manager/graph/frame_node_impl_unittest.cc
+++ b/components/performance_manager/graph/frame_node_impl_unittest.cc
@@ -137,10 +137,11 @@
   MOCK_METHOD1(OnIsAdFrameChanged, void(const FrameNode*));
   MOCK_METHOD1(OnFrameIsHoldingWebLockChanged, void(const FrameNode*));
   MOCK_METHOD1(OnFrameIsHoldingIndexedDBLockChanged, void(const FrameNode*));
-  MOCK_METHOD1(OnNonPersistentNotificationCreated, void(const FrameNode*));
   MOCK_METHOD2(OnPriorityAndReasonChanged,
                void(const FrameNode*, const PriorityAndReason& previous_value));
   MOCK_METHOD1(OnHadFormInteractionChanged, void(const FrameNode*));
+  MOCK_METHOD1(OnNonPersistentNotificationCreated, void(const FrameNode*));
+  MOCK_METHOD2(OnFirstContentfulPaint, void(const FrameNode*, base::TimeDelta));
 
   void SetCreatedFrameNode(const FrameNode* frame_node) {
     created_frame_node_ = frame_node;
@@ -340,6 +341,21 @@
   graph()->RemoveFrameNodeObserver(&obs);
 }
 
+TEST_F(FrameNodeImplTest, FirstContentfulPaint) {
+  auto process = CreateNode<ProcessNodeImpl>();
+  auto page = CreateNode<PageNodeImpl>();
+  auto frame_node = CreateFrameNodeAutoId(process.get(), page.get());
+
+  MockObserver obs;
+  graph()->AddFrameNodeObserver(&obs);
+
+  base::TimeDelta fcp = base::TimeDelta::FromMilliseconds(1364);
+  EXPECT_CALL(obs, OnFirstContentfulPaint(frame_node.get(), fcp));
+  frame_node->OnFirstContentfulPaint(fcp);
+
+  graph()->RemoveFrameNodeObserver(&obs);
+}
+
 TEST_F(FrameNodeImplTest, PublicInterface) {
   auto process = CreateNode<ProcessNodeImpl>();
   auto page = CreateNode<PageNodeImpl>();
diff --git a/components/performance_manager/public/graph/frame_node.h b/components/performance_manager/public/graph/frame_node.h
index d3d49d9..bf74cc4 100644
--- a/components/performance_manager/public/graph/frame_node.h
+++ b/components/performance_manager/public/graph/frame_node.h
@@ -230,6 +230,15 @@
   virtual void OnNonPersistentNotificationCreated(
       const FrameNode* frame_node) = 0;
 
+  // Invoked when the frame has had a first contentful paint, as defined here:
+  // https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint
+  // This may not fire for all frames, depending on if the load is interrupted
+  // or if the content is even visible. It will fire at most once for a given
+  // frame. It will only fire for main-frame nodes.
+  virtual void OnFirstContentfulPaint(
+      const FrameNode* frame_node,
+      base::TimeDelta time_since_navigation_start) = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(FrameNodeObserver);
 };
@@ -263,6 +272,9 @@
   void OnHadFormInteractionChanged(const FrameNode* frame_node) override {}
   void OnNonPersistentNotificationCreated(
       const FrameNode* frame_node) override {}
+  void OnFirstContentfulPaint(
+      const FrameNode* frame_node,
+      base::TimeDelta time_since_navigation_start) override {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ObserverDefaultImpl);
diff --git a/components/performance_manager/public/mojom/coordination_unit.mojom b/components/performance_manager/public/mojom/coordination_unit.mojom
index 1cf95e6..7bdcdf1 100644
--- a/components/performance_manager/public/mojom/coordination_unit.mojom
+++ b/components/performance_manager/public/mojom/coordination_unit.mojom
@@ -49,7 +49,18 @@
   SetIsAdFrame();
 
   // Event signals.
+
+  // Called when the associated frame has caused a non-persistent notification
+  // to be created.
   OnNonPersistentNotificationCreated();
+
+  // Invoked when the frame associated with this document has had a first
+  // contentful paint, as defined here:
+  // https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint
+  // This may not fire for all frames, depending on if the load is interrupted
+  // or if the content is even visible. It will fire at most once for a given
+  // frame. It will only fire for main-frame nodes.
+  OnFirstContentfulPaint(mojo_base.mojom.TimeDelta time_since_navigation_start);
 };
 
 interface ProcessCoordinationUnit {
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 73e17c8..feb6533 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -3226,7 +3226,7 @@
       'tags': ['local-data-access'],
       'desc': '''Configures the directory that <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will use for storing user data.
 
-      If you set this policy, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will use the provided directory regardless whether the user has specified the '--user-data-dir' flag or not. To avoid data loss or other unexpected errors this policy should not be set to a volume's root directory or to a directory used for other purposes, because <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> manages its contents.
+      If you set this policy, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will use the provided directory regardless whether the user has specified the '--user-data-dir' flag or not. To avoid data loss or other unexpected errors this policy should not be set to a directory used for other purposes, because <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> manages its contents.
 
       See https://www.chromium.org/administrators/policy-list-3/user-data-directory-variables for a list of variables that can be used.
 
@@ -11747,7 +11747,7 @@
           'caption': '''Disable all variations''',
         },
       ],
-      'supported_on': ['chrome.*:82-'],
+      'supported_on': ['chrome.*:83-'],
       'features': {
         'dynamic_refresh': True,
         'per_profile': False,
@@ -11792,7 +11792,7 @@
           'caption': '''Disable all variations''',
         },
       ],
-      'supported_on': ['chrome_os:82-'],
+      'supported_on': ['chrome_os:83-'],
       'features': {
         'dynamic_refresh': True,
         'per_profile': False,
diff --git a/components/policy/tools/template_writers/writers/ios_app_config_writer.py b/components/policy/tools/template_writers/writers/ios_app_config_writer.py
index e280a80..f82ee54 100755
--- a/components/policy/tools/template_writers/writers/ios_app_config_writer.py
+++ b/components/policy/tools/template_writers/writers/ios_app_config_writer.py
@@ -54,7 +54,7 @@
         'string-enum-list': 'stringArray',
         'main': 'boolean',
         'list': 'stringArray',
-        'dict': None,
+        'dict': 'string',
     }
 
   def GetTemplateText(self):
diff --git a/components/policy/tools/template_writers/writers/ios_app_config_writer_unittest.py b/components/policy/tools/template_writers/writers/ios_app_config_writer_unittest.py
index 71e85c1..df741e3 100755
--- a/components/policy/tools/template_writers/writers/ios_app_config_writer_unittest.py
+++ b/components/policy/tools/template_writers/writers/ios_app_config_writer_unittest.py
@@ -125,9 +125,10 @@
 
   def testDictPolicy(self):
     policy_json = self._GetTestPolicyTemplate('DictPolicy', 'dict')
-    # Dict policies are not supported by the appconfig.xml format and should not
-    # be present in the output.
-    expected = self._GetExpectedOutput('83.0.4089.0', None)
+    # Dict policies are not supported by the appconfig.xml format, therefore
+    # they are treated as JSON strings.
+    expected = self._GetExpectedOutput('83.0.4089.0',
+                                       '<string keyName="DictPolicy"/>')
     output = self.GetOutput(policy_json, {
         '_google_chrome': '1',
         'version': '83.0.4089.0'
diff --git a/components/safe_browsing/content/triggers/ad_popup_trigger_unittest.cc b/components/safe_browsing/content/triggers/ad_popup_trigger_unittest.cc
index 56fb756..5515555e 100644
--- a/components/safe_browsing/content/triggers/ad_popup_trigger_unittest.cc
+++ b/components/safe_browsing/content/triggers/ad_popup_trigger_unittest.cc
@@ -17,7 +17,6 @@
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_renderer_host.h"
-#include "testing/gmock/include/gmock/gmock-generated-function-mockers.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/components/safe_browsing/content/triggers/ad_sampler_trigger_unittest.cc b/components/safe_browsing/content/triggers/ad_sampler_trigger_unittest.cc
index 6b3eca6..208eed2 100644
--- a/components/safe_browsing/content/triggers/ad_sampler_trigger_unittest.cc
+++ b/components/safe_browsing/content/triggers/ad_sampler_trigger_unittest.cc
@@ -15,7 +15,6 @@
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_renderer_host.h"
-#include "testing/gmock/include/gmock/gmock-generated-function-mockers.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/components/sync/driver/model_type_controller.cc b/components/sync/driver/model_type_controller.cc
index d70ec097..4aaa6184 100644
--- a/components/sync/driver/model_type_controller.cc
+++ b/components/sync/driver/model_type_controller.cc
@@ -260,6 +260,12 @@
   delegate_->RecordMemoryUsageAndCountsHistograms();
 }
 
+ModelTypeControllerDelegate*
+ModelTypeController::GetDelegateForTransportModeForTest() {
+  auto it = delegate_map_.find(SyncMode::kTransportOnly);
+  return it != delegate_map_.end() ? it->second.get() : nullptr;
+}
+
 void ModelTypeController::ReportModelError(SyncError::ErrorType error_type,
                                            const ModelError& error) {
   DCHECK(CalledOnValidThread());
diff --git a/components/sync/driver/model_type_controller.h b/components/sync/driver/model_type_controller.h
index feba0a8..b940ec7 100644
--- a/components/sync/driver/model_type_controller.h
+++ b/components/sync/driver/model_type_controller.h
@@ -61,6 +61,8 @@
   void GetStatusCounters(StatusCountersCallback callback) override;
   void RecordMemoryUsageAndCountsHistograms() override;
 
+  ModelTypeControllerDelegate* GetDelegateForTransportModeForTest();
+
  protected:
   // Subclasses that use this constructor must call InitModelTypeController().
   explicit ModelTypeController(ModelType type);
diff --git a/components/sync/driver/profile_sync_service.cc b/components/sync/driver/profile_sync_service.cc
index 44a6eb1..589ca3d 100644
--- a/components/sync/driver/profile_sync_service.cc
+++ b/components/sync/driver/profile_sync_service.cc
@@ -1471,8 +1471,13 @@
 }
 
 ModelTypeSet ProfileSyncService::GetModelTypesForTransportOnlyMode() const {
-  ModelTypeSet allowed_types = {USER_CONSENTS, SECURITY_EVENTS,
-                                SHARING_MESSAGE};
+  ModelTypeSet allowed_types = {
+      SECURITY_EVENTS,
+      SHARING_MESSAGE,
+      SUPERVISED_USER_SETTINGS,
+      SUPERVISED_USER_WHITELISTS,
+      USER_CONSENTS,
+  };
 
   if (autofill_enable_account_wallet_storage_) {
     if (!GetUserSettings()->IsUsingSecondaryPassphrase() ||
diff --git a/components/sync/driver/profile_sync_service_unittest.cc b/components/sync/driver/profile_sync_service_unittest.cc
index 18070e02..707d53c 100644
--- a/components/sync/driver/profile_sync_service_unittest.cc
+++ b/components/sync/driver/profile_sync_service_unittest.cc
@@ -21,6 +21,7 @@
 #include "components/signin/public/identity_manager/identity_test_environment.h"
 #include "components/signin/public/identity_manager/identity_test_utils.h"
 #include "components/signin/public/identity_manager/primary_account_mutator.h"
+#include "components/sync/base/model_type.h"
 #include "components/sync/base/pref_names.h"
 #include "components/sync/base/user_demographics.h"
 #include "components/sync/base/user_selectable_type.h"
@@ -71,6 +72,7 @@
   void Configure(ModelTypeSet desired_types,
                  const ConfigureContext& context) override {
     state_ = CONFIGURED;
+    desired_types_ = desired_types;
     DCHECK(!configure_called_.is_null());
     configure_called_.Run(context.reason);
   }
@@ -79,13 +81,14 @@
   void ResetDataTypeErrors() override {}
   void PurgeForMigration(ModelTypeSet undesired_types) override {}
   void Stop(ShutdownReason reason) override {}
-  ModelTypeSet GetActiveDataTypes() const override { return ModelTypeSet(); }
+  ModelTypeSet GetActiveDataTypes() const override { return desired_types_; }
   bool IsNigoriEnabled() const override { return true; }
   State state() const override { return state_; }
 
  private:
   ConfigureCalled configure_called_;
   State state_;
+  ModelTypeSet desired_types_;
 };
 
 ACTION_P(ReturnNewFakeDataTypeManager, configure_called) {
@@ -177,8 +180,11 @@
   void CreateService(ProfileSyncService::StartBehavior behavior) {
     DCHECK(!service_);
 
+    // Include a regular controller and a transport-mode controller.
     DataTypeController::TypeVector controllers;
     controllers.push_back(std::make_unique<FakeDataTypeController>(BOOKMARKS));
+    controllers.push_back(
+        std::make_unique<FakeDataTypeController>(SUPERVISED_USER_SETTINGS));
 
     std::unique_ptr<SyncClientMock> sync_client =
         profile_sync_service_bundle_.CreateSyncClientMock();
@@ -199,8 +205,11 @@
   void CreateServiceWithLocalSyncBackend() {
     DCHECK(!service_);
 
+    // Include a regular controller and a transport-mode controller.
     DataTypeController::TypeVector controllers;
     controllers.push_back(std::make_unique<FakeDataTypeController>(BOOKMARKS));
+    controllers.push_back(
+        std::make_unique<FakeDataTypeController>(SUPERVISED_USER_SETTINGS));
 
     std::unique_ptr<SyncClientMock> sync_client =
         profile_sync_service_bundle_.CreateSyncClientMock();
@@ -421,6 +430,27 @@
   EXPECT_EQ(kLastSyncedTime, sync_prefs.GetLastSyncedTime());
 }
 
+TEST_F(ProfileSyncServiceTest, ModelTypesForTransportMode) {
+  CreateService(ProfileSyncService::AUTO_START);
+  SignIn();
+  InitializeForNthSync();
+
+  // Disable sync-the-feature.
+  service()->GetUserSettings()->SetSyncRequested(false);
+  ASSERT_FALSE(service()->IsSyncFeatureActive());
+  ASSERT_FALSE(service()->IsSyncFeatureEnabled());
+
+  // Sync-the-transport is still active.
+  ASSERT_EQ(SyncService::TransportState::ACTIVE,
+            service()->GetTransportState());
+
+  // ModelTypes for sync-the-feature are not configured.
+  EXPECT_FALSE(service()->GetActiveDataTypes().Has(BOOKMARKS));
+
+  // ModelTypes for sync-the-transport are configured.
+  EXPECT_TRUE(service()->GetActiveDataTypes().Has(SUPERVISED_USER_SETTINGS));
+}
+
 // Verify that the SetSetupInProgress function call updates state
 // and notifies observers.
 TEST_F(ProfileSyncServiceTest, SetupInProgress) {
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn
index 66b9a70..90af920 100644
--- a/components/viz/common/BUILD.gn
+++ b/components/viz/common/BUILD.gn
@@ -123,8 +123,8 @@
 
     deps = [
       "//base",
+      "//third_party/dawn/src/dawn:dawn_proc",
       "//third_party/dawn/src/dawn:dawncpp",
-      "//third_party/dawn/src/dawn:libdawn_proc",
       "//third_party/dawn/src/dawn_native",
     ]
   }
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index 596e298c..3af9363 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -413,8 +413,8 @@
     public_deps += [ "//third_party/dawn/src/dawn:dawn_headers" ]
 
     deps += [
+      "//third_party/dawn/src/dawn:dawn_proc",
       "//third_party/dawn/src/dawn:dawncpp",
-      "//third_party/dawn/src/dawn:libdawn_proc",
       "//third_party/dawn/src/dawn_native",
     ]
   }
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc
index 8c82bbc..43d34c09 100644
--- a/components/viz/service/display/surface_aggregator.cc
+++ b/components/viz/service/display/surface_aggregator.cc
@@ -988,9 +988,13 @@
   // If the current frame has copy requests or cached render passes, then
   // aggregate the entire thing, as otherwise parts of the copy requests may be
   // ignored and we could cache partially drawn render pass.
+  // If there are pixel-moving backdrop filters then the damage rect might be
+  // expanded later, so we can't drop quads that are outside the current damage
+  // rect safely.
   const bool ignore_undamaged =
       aggregate_only_damaged_ && !has_copy_requests_ &&
-      !has_cached_render_passes_ && !moved_pixel_passes_.count(dest_pass->id);
+      !has_cached_render_passes_ && !has_pixel_moving_backdrop_filter_ &&
+      !moved_pixel_passes_.count(dest_pass->id);
   // Damage rect in the quad space of the current shared quad state.
   // TODO(jbauman): This rect may contain unnecessary area if
   // transform isn't axis-aligned.
@@ -1247,6 +1251,7 @@
   base::AutoReset<bool> reset_is_visited(&current_pass_entry->is_visited, true);
   RenderPass* render_pass = current_pass_entry->render_pass;
   if (current_pass_entry->has_pixel_moving_backdrop_filter) {
+    has_pixel_moving_backdrop_filter_ = true;
     // If the render pass has a backdrop filter that moves pixels, its entire
     // bounds, with proper transform applied, may be added to the damage
     // rect if it intersects.
@@ -1799,6 +1804,7 @@
 
   valid_surfaces_.clear();
   has_cached_render_passes_ = false;
+  has_pixel_moving_backdrop_filter_ = false;
   damage_ranges_.clear();
   damage_rects_union_of_surfaces_on_top_ = gfx::Rect();
   new_surfaces_.clear();
diff --git a/components/viz/service/display/surface_aggregator.h b/components/viz/service/display/surface_aggregator.h
index eae92812..6da752f 100644
--- a/components/viz/service/display/surface_aggregator.h
+++ b/components/viz/service/display/surface_aggregator.h
@@ -408,6 +408,11 @@
   // passes. This is valid during Aggregate after PrewalkTree is called.
   bool has_cached_render_passes_;
 
+  // True if any RenderPasses in the aggregated frame have a backdrop filter
+  // that moves pixels. This is valid during Aggregate after PrewalkTree is
+  // called.
+  bool has_pixel_moving_backdrop_filter_ = false;
+
   // For each FrameSinkId, contains a vector of SurfaceRanges that will damage
   // the display if they're damaged.
   base::flat_map<FrameSinkId, std::vector<SurfaceRange>> damage_ranges_;
diff --git a/components/viz/service/display/surface_aggregator_unittest.cc b/components/viz/service/display/surface_aggregator_unittest.cc
index ba0162e..0a3f1ae 100644
--- a/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/components/viz/service/display/surface_aggregator_unittest.cc
@@ -4285,7 +4285,8 @@
   }
 
   // Render passes with pixel-moving filters will increase the damage only if
-  // the damage of the contents will overlap the render pass.
+  // the damage of the contents will overlap the render pass. Since one of the
+  // render passes has a pixel-moving backdrop filter no quads are ignored.
   {
     int root_pass_ids[] = {1, 2};
     const gfx::Size pass_with_filter_size(5, 5);
@@ -4332,7 +4333,7 @@
     EXPECT_EQ(1u, aggregated_pass_list[0]->quad_list.size());
 
     EXPECT_EQ(gfx::Rect(1, 1), aggregated_pass_list[1]->damage_rect);
-    EXPECT_EQ(0u, aggregated_pass_list[1]->quad_list.size());
+    EXPECT_EQ(1u, aggregated_pass_list[1]->quad_list.size());
 
     // First render pass draw quad overlaps with damage rect and has background
     // filter, so it should be damaged. SurfaceDrawQuad is after background
@@ -4342,7 +4343,8 @@
   }
 
   // If the render pass with background filters does not intersect the damage
-  // rect, the damage won't be expanded to cover the render pass.
+  // rect, the damage won't be expanded to cover the render pass. Since one of
+  // the render passes has a pixel-moving backdrop filter no quads are ignored.
   {
     int root_pass_ids[] = {1, 2};
     const gfx::Size pass_with_filter_size(5, 5);
@@ -4384,7 +4386,7 @@
 
     // Pass 0 has background blur filter but does NOT overlap with damage rect.
     EXPECT_EQ(gfx::Rect(), aggregated_pass_list[0]->damage_rect);
-    EXPECT_EQ(0u, aggregated_pass_list[0]->quad_list.size());
+    EXPECT_EQ(1u, aggregated_pass_list[0]->quad_list.size());
 
     EXPECT_EQ(gfx::Rect(1, 1, 3, 3), aggregated_pass_list[1]->damage_rect);
     EXPECT_EQ(1u, aggregated_pass_list[1]->quad_list.size());
@@ -4393,7 +4395,7 @@
     // drawn. SurfaceDrawQuad is after background filter, so corresponding
     // RenderPassDrawQuad should be drawn.
     EXPECT_EQ(gfx::Rect(6, 6, 3, 3), aggregated_pass_list[2]->damage_rect);
-    EXPECT_EQ(1u, aggregated_pass_list[2]->quad_list.size());
+    EXPECT_EQ(2u, aggregated_pass_list[2]->quad_list.size());
   }
 }
 
diff --git a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm
index c7fb942..50972ce 100644
--- a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm
+++ b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm
@@ -120,6 +120,78 @@
          base::ClampToRange(static_cast<int>(lroundf(255.0f * b)), 0, 255);
 }
 
+// TODO(bokan): Added temporarily to debug https://crbug.com/1039833.
+// Needed only in temporary method below.
+CommandDispatcher* GetCommandDispatcher(NSWindow* theWindow) {
+  if ([theWindow conformsToProtocol:@protocol(CommandDispatchingWindow)]) {
+    return [static_cast<NSObject<CommandDispatchingWindow>*>(theWindow)
+        commandDispatcher];
+  }
+  return nil;
+}
+
+// TODO(bokan): Added temporarily to debug https://crbug.com/1039833.
+// Returns a string with class names of each ancestor view of this one
+// (inclusive).
+std::string GetViewHierarchyString(NSView* thisView) {
+  std::string ret = "";
+  NSView* view = thisView;
+  while (view) {
+    ret += base::SysNSStringToUTF8(NSStringFromClass([view class])) + "->";
+    view = [view superview];
+  }
+
+  return ret;
+}
+
+// TODO(bokan): Added temporarily to debug https://crbug.com/1039833.
+// Returns a string with information about all the app's windows and current
+// event redispatch state of this window and the event's window.
+std::string GetWindowInfoString(NSWindow* thisWindow, NSEvent* theEvent) {
+  std::string windowInfoStr = "[";
+  NSArray* windows = [NSApp windows];
+  bool foundEventWindow = false;
+  for (unsigned int i = 0; i < [windows count]; ++i) {
+    NSWindow* window = windows[i];
+    if (thisWindow == window)
+      windowInfoStr += "SELF-";
+    if ([NSApp keyWindow] == window)
+      windowInfoStr += "KEY-";
+    if ([NSApp mainWindow] == window)
+      windowInfoStr += "MAIN-";
+    if ([theEvent windowNumber] == [window windowNumber]) {
+      foundEventWindow = true;
+      windowInfoStr += "EVENT-";
+    }
+
+    std::string className =
+        base::SysNSStringToUTF8(NSStringFromClass([window class]));
+    NSRect rect = [window frame];
+    windowInfoStr += base::StringPrintf(
+        "%ld<%s - %dx%d>, ", static_cast<long>([window windowNumber]),
+        className.c_str(), static_cast<int>(NSWidth(rect)),
+        static_cast<int>(NSHeight(rect)));
+  }
+  windowInfoStr += "]";
+
+  if (!foundEventWindow)
+    windowInfoStr += base::StringPrintf(
+        " Event: %ld", static_cast<long>([theEvent windowNumber]));
+
+  windowInfoStr += base::StringPrintf(
+      " isRedispatch[this:%d event:%d]",
+      GetCommandDispatcher(thisWindow) == nil
+          ? -1
+          : static_cast<int>(
+                [GetCommandDispatcher(thisWindow) isRedispatchingKeyEvent]),
+      GetCommandDispatcher([theEvent window]) == nil
+          ? -1
+          : static_cast<int>([GetCommandDispatcher([theEvent window])
+                isRedispatchingKeyEvent]));
+
+  return windowInfoStr;
+}
+
 // Extract underline information from an attributed string. Mostly copied from
 // third_party/WebKit/Source/WebKit/mac/WebView/WebHTMLView.mm
 void ExtractUnderlines(NSAttributedString* string,
@@ -921,6 +993,16 @@
 
 - (void)keyEvent:(NSEvent*)theEvent wasKeyEquivalent:(BOOL)equiv {
   TRACE_EVENT0("browser", "RenderWidgetHostViewCocoa::keyEvent");
+  // TODO(bokan): Added temporarily to debug https://crbug.com/1039833.
+  static auto* windowInfoKey = base::debug::AllocateCrashKeyString(
+      "window-info", base::debug::CrashKeySize::Size256);
+  static auto* viewInfoKey = base::debug::AllocateCrashKeyString(
+      "view-info", base::debug::CrashKeySize::Size256);
+  base::debug::ScopedCrashKeyString scopedKeyWindow(
+      windowInfoKey, GetWindowInfoString([self window], theEvent));
+  base::debug::ScopedCrashKeyString scopedKeyView(viewInfoKey,
+                                                  GetViewHierarchyString(self));
+
   NSEventType eventType = [theEvent type];
   NSEventModifierFlags modifierFlags = [theEvent modifierFlags];
   int keyCode = [theEvent keyCode];
diff --git a/content/browser/renderer_host/input/fling_controller.cc b/content/browser/renderer_host/input/fling_controller.cc
index ff74cc7..58b13bd5 100644
--- a/content/browser/renderer_host/input/fling_controller.cc
+++ b/content/browser/renderer_host/input/fling_controller.cc
@@ -407,13 +407,27 @@
     return false;
   }
 
+  gfx::Vector2dF velocity_from_gfs(
+      fling_start_event.data.fling_start.velocity_x,
+      fling_start_event.data.fling_start.velocity_y);
+
+  float max_velocity_from_gfs =
+      std::max(fabs(velocity_from_gfs.x()), fabs(velocity_from_gfs.y()));
+  float max_velocity = std::max(fabs(current_fling_parameters_.velocity.x()),
+                                fabs(current_fling_parameters_.velocity.y()));
+
+  // Scale the default bound multiplier to compute the maximum scroll distance a
+  // fling can travel based on physics based fling curve.
+  float boost_multiplier = max_velocity / max_velocity_from_gfs;
+
   fling_curve_ = std::unique_ptr<blink::WebGestureCurve>(
       ui::WebGestureCurveImpl::CreateFromDefaultPlatformCurve(
           current_fling_parameters_.source_device,
           current_fling_parameters_.velocity,
           gfx::Vector2dF() /*initial_offset*/, false /*on_main_thread*/,
           GetContentClient()->browser()->ShouldUseMobileFlingCurve(),
-          current_fling_parameters_.global_point, root_widget_viewport_size));
+          current_fling_parameters_.global_point, boost_multiplier,
+          root_widget_viewport_size));
   return true;
 }
 
diff --git a/content/browser/renderer_host/input/fling_controller_unittest.cc b/content/browser/renderer_host/input/fling_controller_unittest.cc
index 95d1771..f8067cb 100644
--- a/content/browser/renderer_host/input/fling_controller_unittest.cc
+++ b/content/browser/renderer_host/input/fling_controller_unittest.cc
@@ -6,13 +6,17 @@
 
 #include "base/rand_util.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "base/test/task_environment.h"
 #include "build/build_config.h"
+#include "build/chromecast_buildflags.h"
 #include "content/browser/renderer_host/input/gesture_event_queue.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/events/blink/fling_booster.h"
+#include "ui/events/gestures/physics_based_fling_curve.h"
 
 #if defined(OS_WIN)
 #include "ui/display/win/test/scoped_screen_win.h"
@@ -21,6 +25,7 @@
 using blink::WebGestureEvent;
 using blink::WebInputEvent;
 using blink::WebMouseWheelEvent;
+using ui::PhysicsBasedFlingCurve;
 
 namespace {
 constexpr double kFrameDelta = 1000.0 / 60.0;
@@ -702,4 +707,134 @@
   EXPECT_FALSE(FlingInProgress());
 }
 
+class FlingControllerWithPhysicsBasedFlingTest : public FlingControllerTest {
+ public:
+  // testing::Test
+  FlingControllerWithPhysicsBasedFlingTest() {
+    scoped_feature_list_.InitAndEnableFeature(
+        features::kExperimentalFlingAnimation);
+  }
+
+  ~FlingControllerWithPhysicsBasedFlingTest() override = default;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  DISALLOW_COPY_AND_ASSIGN(FlingControllerWithPhysicsBasedFlingTest);
+};
+
+INSTANTIATE_TEST_SUITE_P(All,
+                         FlingControllerWithPhysicsBasedFlingTest,
+                         testing::Bool());
+
+// Ensure the bounding distance for boosted physics based flings is increased
+// by a factor of the boost_multiplier and default multiplier
+TEST_P(FlingControllerWithPhysicsBasedFlingTest,
+       ControllerBoostsTouchscreenFling) {
+  // We use a velocity of 4500 in this test because it yields a scroll delta
+  // that is greater than viewport * boost_multiplier * kDefaultBoundsMultiplier
+
+  // Android and Chromecast use Mobile fling curve so they are ignored
+  // for this test
+  bool use_mobile_fling_curve = false;
+#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMECAST)
+  use_mobile_fling_curve = true;
+#endif
+  if (use_mobile_fling_curve)
+    return;
+
+  SimulateFlingStart(blink::WebGestureDevice::kTouchscreen,
+                     gfx::Vector2dF(4500, 0));
+  EXPECT_TRUE(FlingInProgress());
+  // Fling progress must send GSU events.
+  AdvanceTime();
+  ProgressFling(NowTicks());
+  ASSERT_EQ(WebInputEvent::kGestureScrollUpdate, last_sent_gesture_.GetType());
+  EXPECT_EQ(WebGestureEvent::InertialPhaseState::kMomentum,
+            last_sent_gesture_.data.scroll_update.inertial_phase);
+  EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f);
+
+  // Now cancel the fling.
+  SimulateFlingCancel(blink::WebGestureDevice::kTouchscreen);
+  EXPECT_FALSE(FlingInProgress());
+
+  // The second GFS can be boosted so it should boost the just deactivated
+  // fling. To test that the correct bounds scale is used, the scroll delta
+  // is accumulated after each frame.
+  SimulateFlingStart(blink::WebGestureDevice::kTouchscreen,
+                     gfx::Vector2dF(4500, 0));
+  EXPECT_TRUE(FlingInProgress());
+  if (NeedsBeginFrameForFlingProgress())
+    ProgressFling(NowTicks());
+  float total_scroll_delta = last_sent_gesture_.data.scroll_update.delta_x;
+  while (true) {
+    if (last_sent_gesture_.GetType() == WebInputEvent::kGestureScrollEnd) {
+      break;
+    }
+    AdvanceTime();
+    ProgressFling(NowTicks());
+    total_scroll_delta += last_sent_gesture_.data.scroll_update.delta_x;
+  }
+
+  // We expect the scroll delta to be the viewport * [boost_multiplier = 2] *
+  // multiplier
+  float expected_delta =
+      2 * PhysicsBasedFlingCurve::default_bounds_multiplier_for_testing() *
+      GetRootWidgetViewportSize().width();
+  EXPECT_EQ(ceilf(total_scroll_delta), roundf(expected_delta));
+}
+
+// Ensure that once a fling finishes, the next fling has a boost_multiplier of 1
+TEST_P(FlingControllerWithPhysicsBasedFlingTest,
+       ControllerDoesntBoostFinishedFling) {
+  // Android and Chromecast use Mobile fling curve so they are ignored
+  // for this test
+  bool use_mobile_fling_curve = false;
+#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMECAST)
+  use_mobile_fling_curve = true;
+#endif
+  if (use_mobile_fling_curve)
+    return;
+  SimulateFlingStart(blink::WebGestureDevice::kTouchscreen,
+                     gfx::Vector2dF(1000, 0), /*wait_before_processing=*/true);
+  EXPECT_TRUE(FlingInProgress());
+  AdvanceTime();
+  ProgressFling(NowTicks());
+
+  // Fast forward so that the fling ends.
+  double time_to_advance_ms = 1000.0;
+  AdvanceTime(time_to_advance_ms);
+  ProgressFling(NowTicks());
+  ASSERT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType())
+      << "Unexpected Last Sent Gesture: "
+      << WebInputEvent::GetName(last_sent_gesture_.GetType());
+  EXPECT_EQ(fling_controller_->CurrentFlingVelocity().x(), 0);
+  EXPECT_FALSE(FlingInProgress());
+
+  // Now send a new fling, ensure boost_multiplier is 1
+  AdvanceTime();
+  SimulateFlingCancel(blink::WebGestureDevice::kTouchscreen);
+
+  SimulateFlingStart(blink::WebGestureDevice::kTouchscreen,
+                     gfx::Vector2dF(10000, 0));
+  EXPECT_TRUE(FlingInProgress());
+  if (NeedsBeginFrameForFlingProgress())
+    ProgressFling(NowTicks());
+  float total_scroll_delta = last_sent_gesture_.data.scroll_update.delta_x;
+  while (true) {
+    if (last_sent_gesture_.GetType() == WebInputEvent::kGestureScrollEnd) {
+      break;
+    }
+    AdvanceTime();
+    ProgressFling(NowTicks());
+    total_scroll_delta += last_sent_gesture_.data.scroll_update.delta_x;
+  }
+
+  // We expect the scroll delta to be the viewport * [boost_multiplier = 1] *
+  // multiplier
+  float expected_delta =
+      PhysicsBasedFlingCurve::default_bounds_multiplier_for_testing() *
+      GetRootWidgetViewportSize().width();
+  EXPECT_EQ(ceilf(total_scroll_delta), roundf(expected_delta));
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/input/web_input_event_builders_mac.mm b/content/browser/renderer_host/input/web_input_event_builders_mac.mm
index cfc2815..d03a597 100644
--- a/content/browser/renderer_host/input/web_input_event_builders_mac.mm
+++ b/content/browser/renderer_host/input/web_input_event_builders_mac.mm
@@ -35,6 +35,7 @@
 
 #include <stdint.h>
 
+#include "base/debug/dump_without_crashing.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
@@ -235,19 +236,35 @@
 
 blink::WebKeyboardEvent WebKeyboardEventBuilder::Build(NSEvent* event,
                                                        bool record_debug_uma) {
+  // TODO(bokan) Temporary to debug crbug.com/1039833.
+  // It's assumed that some clients may fall into a bad state and produce these
+  // bad timestamps on lots of subsequent events. To prevent sending an
+  // overwhelming amount of crash reports stop after sending 5.
+  static int dump_without_crashing_throttle = 5;
+
   ui::ComputeEventLatencyOS(event);
   base::TimeTicks now = ui::EventTimeForNow();
   base::TimeTicks hardware_timestamp =
       ui::EventTimeStampFromSeconds([event timestamp]);
   if (record_debug_uma) {
     if (ui::EventTypeFromNative(event) == ui::ET_KEY_PRESSED) {
+      base::TimeDelta diff = now - hardware_timestamp;
       UMA_HISTOGRAM_CUSTOM_TIMES(
           now > hardware_timestamp
               ? "Event.Latency.OS_NO_VALIDATION.POSITIVE.KEY_PRESSED"
               : "Event.Latency.OS_NO_VALIDATION.NEGATIVE.KEY_PRESSED",
-          (now - hardware_timestamp).magnitude(),
-          base::TimeDelta::FromMilliseconds(1),
+          diff.magnitude(), base::TimeDelta::FromMilliseconds(1),
           base::TimeDelta::FromSeconds(60), 50);
+
+      // TODO(bokan) Temporary to debug crbug.com/1039833. We've seen in UMA
+      // that we often receive key press events with the OS timestamp differing
+      // from the current timestamp by many seconds. Try to capture a few crash
+      // reports from the wild to see if we can find some pattern.
+      if (diff.magnitude() > base::TimeDelta::FromSeconds(5) &&
+          dump_without_crashing_throttle > 0) {
+        --dump_without_crashing_throttle;
+        base::debug::DumpWithoutCrashing();
+      }
     }
   }
   ui::DomCode dom_code = ui::DomCodeFromNSEvent(event);
diff --git a/content/browser/speech/tts_platform_fuzzer.cc b/content/browser/speech/tts_platform_fuzzer.cc
deleted file mode 100644
index d60a85c..0000000
--- a/content/browser/speech/tts_platform_fuzzer.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/bind.h"
-#include "build/build_config.h"
-#include "content/public/browser/tts_platform.h"
-
-#if defined(OS_WIN)
-#include <objbase.h>
-#endif
-
-namespace content {
-
-// Entry point for LibFuzzer.
-extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) {
-  int utterance_id = 0;
-  std::string utterance;
-  std::string lang;
-  VoiceData voice;
-  UtteranceContinuousParameters params;
-  params.pitch = 1.0;
-  params.rate = 1.0;
-  params.volume = 0.1;
-
-#if defined(OS_WIN)
-  static bool initialized = false;
-  if (!initialized) {
-    initialized = true;
-    CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
-  }
-#endif
-
-  // First byte gives us the utterance ID.
-  size_t i = 0;
-  if (i < size)
-    utterance_id = data[i++];
-
-  // Decide whether we want to fuzz the language, rate, pitch,
-  // voice name, and all that. Half the time we'll just leave
-  // those empty and fuzz only the utterance, otherwise it's
-  // possible the fuzzer would never spend any effort fuzzing
-  // utteranes.
-  if (i < size && (data[i++] % 2 == 0)) {
-    // The next few bytes determine the language. Ensure that
-    // we frequently get some common real languages but allow
-    // arbitrary strings up to 10 characters.
-    if (i < size) {
-      int lang_choice = data[i++];
-      switch (lang_choice) {
-        case 0:
-          lang = "";
-          break;
-        case 1:
-          lang = "en";
-          break;
-        case 2:
-          lang = "fr";
-          break;
-        case 3:
-          lang = "es";
-          break;
-        default:
-          int lang_len = 1 + (lang_choice - 4) % 10;
-          for (int j = 0; j < lang_len; j++) {
-            if (i < size)
-              lang.append(1, data[i++]);
-          }
-      }
-    }
-
-    // Set native_voice_identifier
-    if (i < size) {
-      int voice_len = data[i++] % 10;
-      for (int j = 0; j < voice_len; j++) {
-        if (i < size)
-          voice.native_voice_identifier.append(1, data[i++]);
-      }
-    }
-
-    // Set rate, pitch.
-    if (i + 4 <= size) {
-      params.rate = *reinterpret_cast<const float*>(&data[i]);
-      i += 4;
-    }
-    if (i + 4 <= size) {
-      params.pitch = *reinterpret_cast<const float*>(&data[i]);
-      i += 4;
-    }
-  }
-
-  // The rest of the data becomes the utterance.
-  while (i < size)
-    utterance.append(1, data[i++]);
-
-  TtsPlatform* tts = TtsPlatform::GetInstance();
-  CHECK(tts->PlatformImplAvailable());
-
-  VLOG(1) << "id=" << utterance_id << " lang='" << lang << "'"
-          << " voice='" << voice.native_voice_identifier << "'"
-          << " pitch=" << params.pitch << " rate=" << params.rate
-          << " volume=" << params.volume << " utterance='" << utterance << "'";
-
-  tts->StopSpeaking();
-  tts->Speak(utterance_id, utterance, lang, voice, params,
-             base::BindOnce([](bool success) {}));
-
-  return 0;
-}
-
-}  // namespace content
diff --git a/content/renderer/input/widget_input_handler_manager.h b/content/renderer/input/widget_input_handler_manager.h
index 7f913af..bb202cb 100644
--- a/content/renderer/input/widget_input_handler_manager.h
+++ b/content/renderer/input/widget_input_handler_manager.h
@@ -243,8 +243,10 @@
 
   // Control of UMA. We emit one UMA metric per navigation telling us
   // whether any non-move input arrived before we starting updating the page or
-  // displaying content to the user.
-  bool have_emitted_uma_ = false;
+  // displaying content to the user. It must be atomic because navigation can
+  // occur on the renderer thread (resetting this) coincident with the UMA
+  // being sent on the compositor thread.
+  std::atomic<bool> have_emitted_uma_{false};
 
 #if defined(OS_ANDROID)
   std::unique_ptr<SynchronousCompositorProxyRegistry>
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc
index b5a203b..0ef62c4 100644
--- a/content/renderer/loader/web_url_loader_impl.cc
+++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -61,6 +61,7 @@
 #include "net/ssl/ssl_info.h"
 #include "services/network/public/cpp/http_raw_request_response_info.h"
 #include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/mojom/trust_tokens.mojom-shared.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
 #include "third_party/blink/public/common/features.h"
@@ -1021,6 +1022,19 @@
     return WebURLError(*status.blocked_by_response_reason,
                        status.resolve_error_info, has_copy_in_cache, url);
   }
+
+  if (status.trust_token_operation_status !=
+      network::mojom::TrustTokenOperationStatus::kOk) {
+    DCHECK(status.error_code == net::ERR_TRUST_TOKEN_OPERATION_CACHE_HIT ||
+           status.error_code == net::ERR_TRUST_TOKEN_OPERATION_FAILED)
+        << "Unexpected error code on Trust Token operation failure (or cache "
+           "hit): "
+        << status.error_code;
+
+    return WebURLError(status.error_code, status.trust_token_operation_status,
+                       url);
+  }
+
   return WebURLError(status.error_code, status.extended_error_code,
                      status.resolve_error_info, has_copy_in_cache,
                      WebURLError::IsWebSecurityViolation::kFalse, url);
diff --git a/content/test/data/content_index/test.html b/content/test/data/content_index/test.html
index ab036b5..4f6bdb1 100644
--- a/content/test/data/content_index/test.html
+++ b/content/test/data/content_index/test.html
@@ -18,7 +18,7 @@
           description: 'Description!',
           category: 'article',
           icons,
-          launchUrl: '/content_index/test.html',
+          url: '/content_index/test.html',
         });
         sendResultToTest('ok');
       } catch (e) {
diff --git a/content/test/fuzzer/BUILD.gn b/content/test/fuzzer/BUILD.gn
index 2f22106..38d1079e 100644
--- a/content/test/fuzzer/BUILD.gn
+++ b/content/test/fuzzer/BUILD.gn
@@ -161,42 +161,6 @@
   ]
 }
 
-# Note: this compiles and runs on Mac but may cause
-# system instability; if you try it out, close other
-# programs and then reboot afterwards. It should be
-# possible to make it work on Linux if you use the
-# --enable-speech-dispatcher flag.
-if (is_win) {
-  fuzzer_test("tts_platform_fuzzer") {
-    sources = [
-      "../../browser/speech/mock_tts_controller.cc",
-      "../../browser/speech/tts_mac.mm",
-      "../../browser/speech/tts_platform_fuzzer.cc",
-      "../../browser/speech/tts_platform_impl.cc",
-      "../../browser/speech/tts_platform_impl.h",
-      "../../browser/speech/tts_win.cc",
-      "../../public/browser/tts_controller.h",
-      "../../public/browser/tts_platform.h",
-      "//content/common/content_export.h",
-    ]
-
-    # Don't try to link the code that calls GetContentClient(), because
-    # then we'd need to link in most of //content.
-    defines = [ "NO_CONTENT_CLIENT" ]
-
-    # TODO(https://crbug.com/927728): Refactor target to not require this.
-    check_includes = false
-
-    deps = [
-      "//base",
-      "//base/test:test_support",
-      "//third_party/webrtc_overrides:webrtc_component",
-      "//ui/base",
-      "//url:url",
-    ]
-  }
-}
-
 fuzzer_test("speech_audio_encoder_fuzzer") {
   sources = [
     "../../browser/speech/audio_buffer.cc",
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index f9b8ec5..4b2f106 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -415,8 +415,8 @@
 
   if (use_dawn) {
     deps += [
+      "//third_party/dawn/src/dawn:dawn_proc",
       "//third_party/dawn/src/dawn:dawncpp",
-      "//third_party/dawn/src/dawn:libdawn_proc",
       "//third_party/dawn/src/dawn_native",
     ]
   }
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index 96cbd52..bc5929c 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -390,8 +390,8 @@
   if (skia_use_dawn) {
     deps += [
       "//components/viz/common:dawn_context_provider",
+      "//third_party/dawn/src/dawn:dawn_proc",
       "//third_party/dawn/src/dawn:dawncpp",
-      "//third_party/dawn/src/dawn:libdawn_proc",
     ]
   }
 
diff --git a/ios/chrome/app/application_delegate/metrics_mediator_unittest.mm b/ios/chrome/app/application_delegate/metrics_mediator_unittest.mm
index a0ac288..92a014f4 100644
--- a/ios/chrome/app/application_delegate/metrics_mediator_unittest.mm
+++ b/ios/chrome/app/application_delegate/metrics_mediator_unittest.mm
@@ -13,7 +13,6 @@
 #import "ios/chrome/browser/main/test_browser.h"
 #import "ios/chrome/browser/metrics/previous_session_info.h"
 #import "ios/chrome/browser/metrics/previous_session_info_private.h"
-#import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/main/browser_interface_provider.h"
 #import "ios/chrome/browser/ui/main/scene_state.h"
 #import "ios/chrome/browser/ui/main/test/fake_scene_state.h"
diff --git a/ios/chrome/app/application_delegate/url_opener_unittest.mm b/ios/chrome/app/application_delegate/url_opener_unittest.mm
index 58c9c2b..7fe1cc1 100644
--- a/ios/chrome/app/application_delegate/url_opener_unittest.mm
+++ b/ios/chrome/app/application_delegate/url_opener_unittest.mm
@@ -12,7 +12,6 @@
 #include "ios/chrome/app/application_delegate/startup_information.h"
 #include "ios/chrome/app/startup/chrome_app_startup_parameters.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
-#import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/main/test/stub_browser_interface.h"
 #import "ios/chrome/browser/ui/main/test/stub_browser_interface_provider.h"
 #import "ios/chrome/browser/url_loading/url_loading_params.h"
diff --git a/ios/chrome/app/chrome_overlay_window.mm b/ios/chrome/app/chrome_overlay_window.mm
index 64d55b6..08e2c0f 100644
--- a/ios/chrome/app/chrome_overlay_window.mm
+++ b/ios/chrome/app/chrome_overlay_window.mm
@@ -9,7 +9,6 @@
 #import "ios/chrome/browser/metrics/drag_and_drop_recorder.h"
 #import "ios/chrome/browser/metrics/size_class_recorder.h"
 #import "ios/chrome/browser/metrics/user_interface_style_recorder.h"
-#import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/util/ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/app/tab_opener_unittest.mm b/ios/chrome/app/tab_opener_unittest.mm
index 16d393b8..2b7e450 100644
--- a/ios/chrome/app/tab_opener_unittest.mm
+++ b/ios/chrome/app/tab_opener_unittest.mm
@@ -9,7 +9,6 @@
 #include "ios/chrome/app/application_delegate/startup_information.h"
 #import "ios/chrome/app/application_delegate/tab_opening.h"
 #import "ios/chrome/app/application_delegate/url_opener.h"
-#import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/main/scene_controller.h"
 #import "ios/chrome/browser/ui/main/scene_state.h"
 #import "ios/testing/scoped_block_swizzler.h"
diff --git a/ios/chrome/browser/metrics/BUILD.gn b/ios/chrome/browser/metrics/BUILD.gn
index 1851a2f..b59b1aeb 100644
--- a/ios/chrome/browser/metrics/BUILD.gn
+++ b/ios/chrome/browser/metrics/BUILD.gn
@@ -180,7 +180,6 @@
     "//components/google/core/common",
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state",
-    "//ios/chrome/browser/tabs",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/web_state_list",
     "//ios/web",
diff --git a/ios/chrome/browser/metrics/new_tab_page_uma.mm b/ios/chrome/browser/metrics/new_tab_page_uma.mm
index a7e776f..a9466a2 100644
--- a/ios/chrome/browser/metrics/new_tab_page_uma.mm
+++ b/ios/chrome/browser/metrics/new_tab_page_uma.mm
@@ -8,8 +8,6 @@
 #include "components/google/core/common/google_util.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
-#import "ios/chrome/browser/tabs/tab_model.h"
-#import "ios/chrome/browser/tabs/tab_model_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/web/public/web_state.h"
 #include "url/gurl.h"
diff --git a/ios/chrome/browser/passwords/BUILD.gn b/ios/chrome/browser/passwords/BUILD.gn
index 22915a1..a0c27c5 100644
--- a/ios/chrome/browser/passwords/BUILD.gn
+++ b/ios/chrome/browser/passwords/BUILD.gn
@@ -69,6 +69,7 @@
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/infobars",
     "//ios/chrome/browser/infobars:public",
+    "//ios/chrome/browser/main:public",
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/ssl",
     "//ios/chrome/browser/sync/glue",
diff --git a/ios/chrome/browser/passwords/password_controller.h b/ios/chrome/browser/passwords/password_controller.h
index d617746..a2ab586 100644
--- a/ios/chrome/browser/passwords/password_controller.h
+++ b/ios/chrome/browser/passwords/password_controller.h
@@ -15,6 +15,7 @@
 #import "ios/web/public/web_state_observer_bridge.h"
 
 @protocol ApplicationCommands;
+class Browser;
 @class NotifyUserAutoSigninViewController;
 @protocol PasswordBreachCommands;
 @protocol PasswordFormFiller;
@@ -70,6 +71,9 @@
 // Delegate used by this PasswordController to show UI on BVC.
 @property(weak, nonatomic) id<PasswordControllerDelegate> delegate;
 
+// The browser.
+@property(nonatomic, assign) Browser* browser;
+
 // |webState| should not be nil.
 - (instancetype)initWithWebState:(web::WebState*)webState;
 
diff --git a/ios/chrome/browser/passwords/password_controller.mm b/ios/chrome/browser/passwords/password_controller.mm
index e21e05f..c09657cd 100644
--- a/ios/chrome/browser/passwords/password_controller.mm
+++ b/ios/chrome/browser/passwords/password_controller.mm
@@ -46,6 +46,7 @@
 #include "ios/chrome/browser/infobars/infobar_ios.h"
 #include "ios/chrome/browser/infobars/infobar_manager_impl.h"
 #import "ios/chrome/browser/infobars/infobar_type.h"
+#import "ios/chrome/browser/main/browser.h"
 #include "ios/chrome/browser/passwords/credential_manager.h"
 #import "ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.h"
 #import "ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.h"
@@ -864,10 +865,9 @@
            object:nil];
 
   // TODO(crbug.com/886583): add eg tests
-  // TODO(crbug.com/1029346): add browser value.
   self.actionSheetCoordinator = [[ActionSheetCoordinator alloc]
       initWithBaseViewController:self.baseViewController
-                         browser:nil
+                         browser:self.browser
                            title:@""
                          message:@""
                             rect:self.baseViewController.view.frame
diff --git a/ios/chrome/browser/passwords/password_tab_helper.h b/ios/chrome/browser/passwords/password_tab_helper.h
index 3f97d4b..d78821177 100644
--- a/ios/chrome/browser/passwords/password_tab_helper.h
+++ b/ios/chrome/browser/passwords/password_tab_helper.h
@@ -9,10 +9,9 @@
 #include "ios/web/public/web_state_observer.h"
 #import "ios/web/public/web_state_user_data.h"
 
-@protocol ApplicationCommands;
+class Browser;
 @protocol FormSuggestionProvider;
 @class PasswordController;
-@protocol PasswordBreachCommands;
 @protocol PasswordControllerDelegate;
 @protocol PasswordFormFiller;
 @protocol PasswordsUiDelegate;
@@ -35,13 +34,12 @@
   // Sets the BaseViewController from which to present UI.
   void SetBaseViewController(UIViewController* baseViewController);
 
-  // Sets the PasswordController dispatcher.
-  void SetDispatcher(
-      id<ApplicationCommands, PasswordBreachCommands> dispatcher);
-
   // Sets the PasswordController delegate.
   void SetPasswordControllerDelegate(id<PasswordControllerDelegate> delegate);
 
+  // Sets the Browser.
+  void SetBrowser(Browser* browser);
+
   // Returns an object that can provide suggestions from the PasswordController.
   // May return nil.
   id<FormSuggestionProvider> GetSuggestionProvider();
diff --git a/ios/chrome/browser/passwords/password_tab_helper.mm b/ios/chrome/browser/passwords/password_tab_helper.mm
index 17184721..633a3ca 100644
--- a/ios/chrome/browser/passwords/password_tab_helper.mm
+++ b/ios/chrome/browser/passwords/password_tab_helper.mm
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#import "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/passwords/password_controller.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -28,16 +29,15 @@
   controller_.baseViewController = baseViewController;
 }
 
-void PasswordTabHelper::SetDispatcher(
-    id<ApplicationCommands, PasswordBreachCommands> dispatcher) {
-  controller_.dispatcher = dispatcher;
-}
-
 void PasswordTabHelper::SetPasswordControllerDelegate(
     id<PasswordControllerDelegate> delegate) {
   controller_.delegate = delegate;
 }
 
+void PasswordTabHelper::SetBrowser(Browser* browser) {
+  controller_.browser = browser;
+}
+
 id<FormSuggestionProvider> PasswordTabHelper::GetSuggestionProvider() {
   return controller_.suggestionProvider;
 }
diff --git a/ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h b/ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h
index 82b9431..789b969 100644
--- a/ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h
+++ b/ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h
@@ -33,12 +33,6 @@
 // |-executeCancelHandler|) has occurred.
 @property(nonatomic, copy) ProceduralBlock noInteractionAction;
 
-// TODO(crbug.com/1029346): Remove this init after migrate away from downstream
-// AlertCoordinator use.
-- (instancetype)initWithBaseViewController:(UIViewController*)viewController
-                                     title:(NSString*)title
-                                   message:(NSString*)message;
-
 // Init a coordinator for displaying a alert on this view controller.
 - (instancetype)initWithBaseViewController:(UIViewController*)viewController
                                    browser:(Browser*)browser
diff --git a/ios/chrome/browser/ui/alert_coordinator/alert_coordinator.mm b/ios/chrome/browser/ui/alert_coordinator/alert_coordinator.mm
index 27958b1..33493ee 100644
--- a/ios/chrome/browser/ui/alert_coordinator/alert_coordinator.mm
+++ b/ios/chrome/browser/ui/alert_coordinator/alert_coordinator.mm
@@ -43,17 +43,6 @@
 @synthesize rawCancelAction = _rawCancelAction;
 @synthesize message = _message;
 
-// TODO(crbug.com/1029346): Remove this init after migrate away from downstream
-// AlertCoordinator use.
-- (instancetype)initWithBaseViewController:(UIViewController*)viewController
-                                     title:(NSString*)title
-                                   message:(NSString*)message {
-  return [self initWithBaseViewController:viewController
-                                  browser:nil
-                                    title:title
-                                  message:message];
-}
-
 - (instancetype)initWithBaseViewController:(UIViewController*)viewController
                                    browser:(Browser*)browser
                                      title:(NSString*)title
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
index 1521ad4..52da932 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
@@ -453,7 +453,7 @@
                     editedNodes:editedNodes
                    allowsCancel:NO
                  selectedFolder:self.folder
-                     dispatcher:self.dispatcher];
+                        browser:_browser];
   folderViewController.delegate = self;
   self.folderViewController = folderViewController;
   self.folderViewController.navigationItem.largeTitleDisplayMode =
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h
index ade36301..99e5c31 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h
@@ -9,7 +9,6 @@
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller.h"
 
 @class BookmarkFolderEditorViewController;
-@protocol BrowserCommands;
 class Browser;
 
 namespace bookmarks {
@@ -52,7 +51,7 @@
 + (instancetype)
     folderCreatorWithBookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel
                       parentFolder:(const bookmarks::BookmarkNode*)parentFolder
-                        dispatcher:(id<BrowserCommands>)dispatcher;
+                           browser:(Browser*)browser;
 
 // |bookmarkModel| must not be null and must be loaded.
 // |folder| must not be NULL and be editable.
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm
index 7d81e30..0c0a8ce 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm
@@ -115,14 +115,18 @@
 + (instancetype)folderCreatorWithBookmarkModel:
                     (bookmarks::BookmarkModel*)bookmarkModel
                                   parentFolder:(const BookmarkNode*)parentFolder
-                                    dispatcher:(id<BrowserCommands>)dispatcher {
-  DCHECK(dispatcher);
+                                       browser:(Browser*)browser {
+  DCHECK(browser);
   BookmarkFolderEditorViewController* folderCreator =
       [[self alloc] initWithBookmarkModel:bookmarkModel];
   folderCreator.parentFolder = parentFolder;
   folderCreator.folder = NULL;
+  folderCreator.browser = browser;
   folderCreator.editingExistingFolder = NO;
-  folderCreator.dispatcher = dispatcher;
+  // TODO(crbug.com/1045047): Use HandlerForProtocol after commands protocol
+  // clean up.
+  folderCreator.dispatcher =
+      static_cast<id<BrowserCommands>>(browser->GetCommandDispatcher());
   return folderCreator;
 }
 
@@ -305,7 +309,7 @@
                     editedNodes:editedNodes
                    allowsCancel:NO
                  selectedFolder:self.parentFolder
-                     dispatcher:self.dispatcher];
+                        browser:_browser];
   folderViewController.delegate = self;
   self.folderViewController = folderViewController;
 
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h b/ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h
index bb4cfe0..b2c303f 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h
@@ -11,7 +11,7 @@
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller.h"
 
 @class BookmarkFolderViewController;
-@protocol BrowserCommands;
+class Browser;
 namespace bookmarks {
 class BookmarkModel;
 class BookmarkNode;
@@ -56,7 +56,7 @@
               editedNodes:(const std::set<const bookmarks::BookmarkNode*>&)nodes
              allowsCancel:(BOOL)allowsCancel
            selectedFolder:(const bookmarks::BookmarkNode*)selectedFolder
-               dispatcher:(id<BrowserCommands>)dispatcher;
+                  browser:(Browser*)browser;
 
 // This method changes the currently selected folder and updates the UI. The
 // delegate is not notified of the change.
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.mm
index c21420d..23f425f 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.mm
@@ -79,8 +79,8 @@
 @property(nonatomic, assign, readonly)
     const std::vector<const BookmarkNode*>& folders;
 
-// The dispatcher for this ViewController.
-@property(nonatomic, readonly, weak) id<BrowserCommands> dispatcher;
+// The browser for this ViewController.
+@property(nonatomic, readonly) Browser* browser;
 
 // Reloads the model and the updates |self.tableView| to reflect any model
 // changes.
@@ -115,18 +115,19 @@
                               (const std::set<const BookmarkNode*>&)nodes
                          allowsCancel:(BOOL)allowsCancel
                        selectedFolder:(const BookmarkNode*)selectedFolder
-                           dispatcher:(id<BrowserCommands>)dispatcher {
+                              browser:(Browser*)browser {
   DCHECK(bookmarkModel);
   DCHECK(bookmarkModel->loaded());
+  DCHECK(browser);
   DCHECK(selectedFolder == NULL || selectedFolder->is_folder());
   self = [super initWithStyle:UITableViewStylePlain];
   if (self) {
+    _browser = browser;
     _allowsCancel = allowsCancel;
     _allowsNewFolders = allowsNewFolders;
     _bookmarkModel = bookmarkModel;
     _editedNodes = nodes;
     _selectedFolder = selectedFolder;
-    _dispatcher = dispatcher;
 
     // Set up the bookmark model oberver.
     _modelBridge.reset(
@@ -449,7 +450,7 @@
       [BookmarkFolderEditorViewController
           folderCreatorWithBookmarkModel:self.bookmarkModel
                             parentFolder:self.selectedFolder
-                              dispatcher:self.dispatcher];
+                                 browser:self.browser];
   folderCreator.delegate = self;
   [self.navigationController pushViewController:folderCreator animated:YES];
   self.folderAddController = folderCreator;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
index 713328a..5506458 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
@@ -624,7 +624,7 @@
                                                       editedNodes:nodes
                                                      allowsCancel:YES
                                                    selectedFolder:selectedFolder
-                                                       dispatcher:self.handler];
+                                                          browser:self.browser];
   self.folderSelector.delegate = self;
   UINavigationController* navController = [[BookmarkNavigationController alloc]
       initWithRootViewController:self.folderSelector];
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index 4fccda1..2c59622 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -2549,12 +2549,12 @@
 
   SnapshotTabHelper::FromWebState(webState)->SetDelegate(self);
 
-  // TODO(crbug.com/777557): do not pass the dispatcher to PasswordTabHelper.
+  // TODO(crbug.com/1069763): do not pass the browser to PasswordTabHelper.
   if (PasswordTabHelper* passwordTabHelper =
           PasswordTabHelper::FromWebState(webState)) {
     passwordTabHelper->SetBaseViewController(self);
-    passwordTabHelper->SetDispatcher(self.dispatcher);
     passwordTabHelper->SetPasswordControllerDelegate(self);
+    passwordTabHelper->SetBrowser(self.browser);
   }
 
   if (!IsIPadIdiom()) {
@@ -2604,10 +2604,10 @@
 - (void)uninstallDelegatesForWebState:(web::WebState*)webState {
   DCHECK_EQ(webState->GetDelegate(), _webStateDelegate.get());
 
-  // TODO(crbug.com/777557): do not pass the dispatcher to PasswordTabHelper.
+  // TODO(crbug.com/1069763): do not pass the browser to PasswordTabHelper.
   if (PasswordTabHelper* passwordTabHelper =
           PasswordTabHelper::FromWebState(webState)) {
-    passwordTabHelper->SetDispatcher(nil);
+    passwordTabHelper->SetBrowser(self.browser);
   }
 
   if (!IsIPadIdiom()) {
diff --git a/ios/chrome/browser/ui/settings/google_services/google_services_settings_app_interface.mm b/ios/chrome/browser/ui/settings/google_services/google_services_settings_app_interface.mm
index 26b84ea..0e0b7f8 100644
--- a/ios/chrome/browser/ui/settings/google_services/google_services_settings_app_interface.mm
+++ b/ios/chrome/browser/ui/settings/google_services/google_services_settings_app_interface.mm
@@ -5,7 +5,6 @@
 #import "ios/chrome/browser/ui/settings/google_services/google_services_settings_app_interface.h"
 
 #import "ios/chrome/app/main_controller.h"
-#import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 #import "ios/chrome/test/app/tab_test_util.h"
diff --git a/ios/chrome/browser/url_loading/BUILD.gn b/ios/chrome/browser/url_loading/BUILD.gn
index 3f641faf..86102b08 100644
--- a/ios/chrome/browser/url_loading/BUILD.gn
+++ b/ios/chrome/browser/url_loading/BUILD.gn
@@ -36,7 +36,6 @@
     "//ios/chrome/browser/prerender",
     "//ios/chrome/browser/sessions",
     "//ios/chrome/browser/snapshots",
-    "//ios/chrome/browser/tabs",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/ntp:util",
     "//ios/chrome/browser/web",
@@ -76,7 +75,6 @@
     "//ios/chrome/browser/main:test_support",
     "//ios/chrome/browser/ntp",
     "//ios/chrome/browser/search_engines",
-    "//ios/chrome/browser/tabs",
     "//ios/chrome/browser/web",
     "//ios/chrome/browser/web:web_internal",
     "//ios/chrome/browser/web_state_list",
diff --git a/ios/chrome/browser/url_loading/scene_url_loading_service.mm b/ios/chrome/browser/url_loading/scene_url_loading_service.mm
index c8f8a3e..e179464 100644
--- a/ios/chrome/browser/url_loading/scene_url_loading_service.mm
+++ b/ios/chrome/browser/url_loading/scene_url_loading_service.mm
@@ -7,7 +7,6 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
-#import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/url_loading/url_loading_browser_agent.h"
 #import "ios/chrome/browser/url_loading/url_loading_params.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
diff --git a/ios/chrome/browser/url_loading/url_loading_browser_agent_unittest.mm b/ios/chrome/browser/url_loading/url_loading_browser_agent_unittest.mm
index da2fe86..8a67b94 100644
--- a/ios/chrome/browser/url_loading/url_loading_browser_agent_unittest.mm
+++ b/ios/chrome/browser/url_loading/url_loading_browser_agent_unittest.mm
@@ -14,8 +14,6 @@
 #include "ios/chrome/browser/main/test_browser.h"
 #import "ios/chrome/browser/ntp/new_tab_page_tab_helper.h"
 #import "ios/chrome/browser/ntp/new_tab_page_tab_helper_delegate.h"
-#import "ios/chrome/browser/tabs/tab_helper_util.h"
-#import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/url_loading/scene_url_loading_service.h"
 #import "ios/chrome/browser/url_loading/test_scene_url_loading_service.h"
 #import "ios/chrome/browser/url_loading/url_loading_notifier_browser_agent.h"
diff --git a/media/gpu/chromeos/video_decoder_pipeline.cc b/media/gpu/chromeos/video_decoder_pipeline.cc
index 5ebd3ca..906861b 100644
--- a/media/gpu/chromeos/video_decoder_pipeline.cc
+++ b/media/gpu/chromeos/video_decoder_pipeline.cc
@@ -319,7 +319,7 @@
   DCHECK(!client_reset_cb_);
   DVLOGF(3);
 
-  need_notify_decoder_flushed_ = false;
+  need_apply_new_resolution = false;
   client_reset_cb_ = std::move(closure);
   decoder_->Reset(
       base::BindOnce(&VideoDecoderPipeline::OnResetDone, decoder_weak_this_));
@@ -431,7 +431,7 @@
 
   // After outputting a frame, flush might be completed.
   CallFlushCbIfNeeded(DecodeStatus::OK);
-  CallOnPipelineFlushedIfNeeded();
+  CallApplyResolutionChangeIfNeeded();
 }
 
 bool VideoDecoderPipeline::HasPendingFrames() const {
@@ -468,19 +468,19 @@
 void VideoDecoderPipeline::PrepareChangeResolution() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
   DVLOGF(3);
-  DCHECK(!need_notify_decoder_flushed_);
+  DCHECK(!need_apply_new_resolution);
 
-  need_notify_decoder_flushed_ = true;
-  CallOnPipelineFlushedIfNeeded();
+  need_apply_new_resolution = true;
+  CallApplyResolutionChangeIfNeeded();
 }
 
-void VideoDecoderPipeline::CallOnPipelineFlushedIfNeeded() {
+void VideoDecoderPipeline::CallApplyResolutionChangeIfNeeded() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
   DVLOGF(3);
 
-  if (need_notify_decoder_flushed_ && !HasPendingFrames()) {
-    need_notify_decoder_flushed_ = false;
-    decoder_->OnPipelineFlushed();
+  if (need_apply_new_resolution && !HasPendingFrames()) {
+    need_apply_new_resolution = false;
+    decoder_->ApplyResolutionChange();
   }
 }
 
diff --git a/media/gpu/chromeos/video_decoder_pipeline.h b/media/gpu/chromeos/video_decoder_pipeline.h
index 396055e..030ed90 100644
--- a/media/gpu/chromeos/video_decoder_pipeline.h
+++ b/media/gpu/chromeos/video_decoder_pipeline.h
@@ -59,7 +59,7 @@
     virtual DmabufVideoFramePool* GetVideoFramePool() const = 0;
 
     // After this method is called from |decoder_|, the client needs to call
-    // DecoderInterface::OnPipelineFlushed() when all pending frames are
+    // DecoderInterface::ApplyResolutionChange() when all pending frames are
     // flushed.
     virtual void PrepareChangeResolution() = 0;
 
@@ -114,7 +114,7 @@
   // After DecoderInterface calls |prepare_change_resolution_cb| passed
   // from the constructor, this method is called when the pipeline flushes
   // pending frames.
-  virtual void OnPipelineFlushed() = 0;
+  virtual void ApplyResolutionChange() = 0;
 
  protected:
   // Decoder task runner. All public methods of
@@ -217,8 +217,8 @@
   // i.e. |image_processor_| or |frame_converter_| has pending frames.
   bool HasPendingFrames() const;
 
-  // Call DecoderInterface::OnPipelineFlushed() when we need to.
-  void CallOnPipelineFlushedIfNeeded();
+  // Call DecoderInterface::ApplyResolutionChange() when we need to.
+  void CallApplyResolutionChangeIfNeeded();
 
   // Call |client_flush_cb_| with |status|.
   void CallFlushCbIfNeeded(DecodeStatus status);
@@ -271,8 +271,8 @@
   base::OnceClosure client_reset_cb_;
 
   // True if we need to notify |decoder_| that the pipeline is flushed via
-  // DecoderInterface::OnPipelineFlushed().
-  bool need_notify_decoder_flushed_ = false;
+  // DecoderInterface::ApplyResolutionChange().
+  bool need_apply_new_resolution = false;
 
   // True if the decoder needs bitstream conversion before decoding.
   bool needs_bitstream_conversion_ = false;
diff --git a/media/gpu/v4l2/v4l2_device.cc b/media/gpu/v4l2/v4l2_device.cc
index bc2176e..58f99f4 100644
--- a/media/gpu/v4l2/v4l2_device.cc
+++ b/media/gpu/v4l2/v4l2_device.cc
@@ -886,7 +886,8 @@
 }
 
 std::pair<base::Optional<struct v4l2_format>, int> V4L2Queue::GetFormat() {
-  struct v4l2_format format = {};
+  struct v4l2_format format;
+  memset(&format, 0, sizeof(format));
   format.type = type_;
   if (device_->Ioctl(VIDIOC_G_FMT, &format) != 0) {
     VPQLOGF(2) << "Failed to get format";
diff --git a/media/gpu/v4l2/v4l2_slice_video_decoder.cc b/media/gpu/v4l2/v4l2_slice_video_decoder.cc
index aa5526e..7cd43f2 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decoder.cc
+++ b/media/gpu/v4l2/v4l2_slice_video_decoder.cc
@@ -425,7 +425,7 @@
   client_->PrepareChangeResolution();
 }
 
-void V4L2SliceVideoDecoder::OnPipelineFlushed() {
+void V4L2SliceVideoDecoder::ApplyResolutionChange() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
   DVLOGF(3);
   DCHECK(continue_change_resolution_cb_);
diff --git a/media/gpu/v4l2/v4l2_slice_video_decoder.h b/media/gpu/v4l2/v4l2_slice_video_decoder.h
index 801edede..d5b82bb 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decoder.h
+++ b/media/gpu/v4l2/v4l2_slice_video_decoder.h
@@ -55,7 +55,7 @@
                   const OutputCB& output_cb) override;
   void Reset(base::OnceClosure closure) override;
   void Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) override;
-  void OnPipelineFlushed() override;
+  void ApplyResolutionChange() override;
 
   // V4L2VideoDecoderBackend::Client implementation
   void OnBackendError() override;
diff --git a/media/gpu/vaapi/vaapi_video_decoder.cc b/media/gpu/vaapi/vaapi_video_decoder.cc
index b7f676a..c97f1a0 100644
--- a/media/gpu/vaapi/vaapi_video_decoder.cc
+++ b/media/gpu/vaapi/vaapi_video_decoder.cc
@@ -240,7 +240,7 @@
     case AcceleratedVideoDecoder::kConfigChange:
       // A new set of output buffers is requested. We either didn't have any
       // output buffers yet or encountered a resolution change.
-      // After the pipeline flushes all frames, OnPipelineFlushed() will be
+      // After the pipeline flushes all frames, ApplyResolutionChange() will be
       // called and we can start changing resolution.
       DCHECK(client_);
       SetState(State::kChangingResolution);
@@ -392,7 +392,7 @@
   output_cb_.Run(std::move(video_frame));
 }
 
-void VaapiVideoDecoder::OnPipelineFlushed() {
+void VaapiVideoDecoder::ApplyResolutionChange() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
   DCHECK(state_ == State::kChangingResolution ||
          state_ == State::kWaitingForInput);
diff --git a/media/gpu/vaapi/vaapi_video_decoder.h b/media/gpu/vaapi/vaapi_video_decoder.h
index 01e282d..db186f1 100644
--- a/media/gpu/vaapi/vaapi_video_decoder.h
+++ b/media/gpu/vaapi/vaapi_video_decoder.h
@@ -54,7 +54,7 @@
                   const OutputCB& output_cb) override;
   void Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) override;
   void Reset(base::OnceClosure reset_cb) override;
-  void OnPipelineFlushed() override;
+  void ApplyResolutionChange() override;
 
   // DecodeSurfaceHandler<VASurface> implementation.
   scoped_refptr<VASurface> CreateSurface() override;
diff --git a/printing/BUILD.gn b/printing/BUILD.gn
index 6fce8a07..08997f4 100644
--- a/printing/BUILD.gn
+++ b/printing/BUILD.gn
@@ -331,6 +331,7 @@
     "page_range_unittest.cc",
     "page_setup_unittest.cc",
     "print_settings_conversion_unittest.cc",
+    "print_settings_unittest.cc",
     "printing_test.h",
     "printing_utils_unittest.cc",
     "units_unittest.cc",
diff --git a/printing/print_settings_unittest.cc b/printing/print_settings_unittest.cc
new file mode 100644
index 0000000..295e9cb
--- /dev/null
+++ b/printing/print_settings_unittest.cc
@@ -0,0 +1,42 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "printing/print_settings.h"
+
+#include "base/test/gtest_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace printing {
+
+TEST(PrintSettingsTest, IsColorModelSelected) {
+  {
+    base::Optional<bool> color(IsColorModelSelected(COLOR));
+    ASSERT_TRUE(color.has_value());
+    EXPECT_TRUE(color.value());
+  }
+  {
+    base::Optional<bool> gray(IsColorModelSelected(GRAY));
+    ASSERT_TRUE(gray.has_value());
+    EXPECT_FALSE(gray.value());
+  }
+  {
+    // Test lower bound validity.
+    base::Optional<bool> lower(IsColorModelSelected(UNKNOWN_COLOR_MODEL + 1));
+    EXPECT_TRUE(lower.has_value());
+  }
+  {
+    // Test upper bound validity.
+    base::Optional<bool> upper(IsColorModelSelected(COLOR_MODEL_LAST));
+    EXPECT_TRUE(upper.has_value());
+  }
+}
+
+TEST(PrintSettingsDeathTest, IsColorModelSelectedUnknown) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  EXPECT_DCHECK_DEATH(IsColorModelSelected(UNKNOWN_COLOR_MODEL));
+  EXPECT_DCHECK_DEATH(IsColorModelSelected(UNKNOWN_COLOR_MODEL - 1));
+  EXPECT_DCHECK_DEATH(IsColorModelSelected(COLOR_MODEL_LAST + 1));
+}
+
+}  // namespace printing
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index f8991a6..99cac1d4 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -6608,8 +6608,8 @@
                    mojom::kBrowserProcessId, std::move(factory_params));
   EXPECT_EQ(client->completion_status().error_code,
             net::ERR_TRUST_TOKEN_OPERATION_FAILED);
-  EXPECT_THAT(client->completion_status().trust_token_operation_status,
-              Optional(mojom::TrustTokenOperationStatus::kUnavailable));
+  EXPECT_EQ(client->completion_status().trust_token_operation_status,
+            mojom::TrustTokenOperationStatus::kUnavailable);
 }
 
 }  // namespace
diff --git a/services/network/public/cpp/url_loader_completion_status.h b/services/network/public/cpp/url_loader_completion_status.h
index ef883a9a..f6dfe60 100644
--- a/services/network/public/cpp/url_loader_completion_status.h
+++ b/services/network/public/cpp/url_loader_completion_status.h
@@ -71,7 +71,16 @@
 
   // Optional Trust Tokens (https://github.com/wicg/trust-token-api) error
   // details.
-  base::Optional<mojom::TrustTokenOperationStatus> trust_token_operation_status;
+  //
+  // A non-kOk value denotes that the request failed because a Trust Tokens
+  // operation was attempted and failed for the given reason.
+  //
+  // The status is set to kOk in all other cases. In particular, a value of kOk
+  // does not imply that a Trust Tokens operation was executed successfully
+  // alongside this request, or even that a Trust Tokens operation was
+  // attempted.
+  mojom::TrustTokenOperationStatus trust_token_operation_status =
+      mojom::TrustTokenOperationStatus::kOk;
 
   // Optional SSL certificate info.
   base::Optional<net::SSLInfo> ssl_info;
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index 2664641..da03acd 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -1622,7 +1622,8 @@
     status.proxy_server = url_request_->proxy_server();
     status.resolve_error_info =
         url_request_->response_info().resolve_error_info;
-    status.trust_token_operation_status = trust_token_status_;
+    if (trust_token_status_)
+      status.trust_token_operation_status = *trust_token_status_;
 
     if ((options_ & mojom::kURLLoadOptionSendSSLInfoForCertificateError) &&
         net::IsCertStatusError(url_request_->ssl_info().cert_status)) {
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc
index 2e38c68..2f99c4fe 100644
--- a/services/network/url_loader_unittest.cc
+++ b/services/network/url_loader_unittest.cc
@@ -4965,8 +4965,8 @@
   delete_run_loop.Run();
 
   EXPECT_EQ(client()->completion_status().error_code, net::OK);
-  EXPECT_THAT(client()->completion_status().trust_token_operation_status,
-              Optional(mojom::TrustTokenOperationStatus::kOk));
+  EXPECT_EQ(client()->completion_status().trust_token_operation_status,
+            mojom::TrustTokenOperationStatus::kOk);
   // The page should still have loaded.
   base::FilePath file = GetTestFilePath("simple_page.html");
   std::string expected;
@@ -5020,8 +5020,8 @@
 
   EXPECT_EQ(client()->completion_status().error_code,
             net::ERR_TRUST_TOKEN_OPERATION_CACHE_HIT);
-  EXPECT_THAT(client()->completion_status().trust_token_operation_status,
-              Optional(mojom::TrustTokenOperationStatus::kAlreadyExists));
+  EXPECT_EQ(client()->completion_status().trust_token_operation_status,
+            mojom::TrustTokenOperationStatus::kAlreadyExists);
 
   EXPECT_FALSE(client()->response_head());
   EXPECT_FALSE(client()->response_body().is_valid());
@@ -5062,8 +5062,8 @@
 
   EXPECT_EQ(client()->completion_status().error_code,
             net::ERR_TRUST_TOKEN_OPERATION_FAILED);
-  EXPECT_THAT(client()->completion_status().trust_token_operation_status,
-              Optional(mojom::TrustTokenOperationStatus::kFailedPrecondition));
+  EXPECT_EQ(client()->completion_status().trust_token_operation_status,
+            mojom::TrustTokenOperationStatus::kFailedPrecondition);
 
   EXPECT_FALSE(client()->response_head());
   EXPECT_FALSE(client()->response_body().is_valid());
@@ -5104,8 +5104,8 @@
 
   EXPECT_EQ(client()->completion_status().error_code,
             net::ERR_TRUST_TOKEN_OPERATION_FAILED);
-  EXPECT_THAT(client()->completion_status().trust_token_operation_status,
-              Optional(mojom::TrustTokenOperationStatus::kBadResponse));
+  EXPECT_EQ(client()->completion_status().trust_token_operation_status,
+            mojom::TrustTokenOperationStatus::kBadResponse);
 }
 
 // When URLLoader receives a  request parameterized to perform a Trust Tokens
@@ -5145,8 +5145,8 @@
 
   EXPECT_EQ(client()->completion_status().error_code,
             net::ERR_TRUST_TOKEN_OPERATION_FAILED);
-  EXPECT_THAT(client()->completion_status().trust_token_operation_status,
-              Optional(mojom::TrustTokenOperationStatus::kInternalError));
+  EXPECT_EQ(client()->completion_status().trust_token_operation_status,
+            mojom::TrustTokenOperationStatus::kInternalError);
 }
 
 }  // namespace network
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index 990fd1b..1211bcbc 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -521,8 +521,8 @@
   if (skia_use_dawn) {
     public_deps += [ "//third_party/dawn/src/dawn:dawncpp_headers" ]
     deps += [
+      "//third_party/dawn/src/dawn:dawn_proc",
       "//third_party/dawn/src/dawn:dawncpp",
-      "//third_party/dawn/src/dawn:libdawn_proc",
       "//third_party/dawn/src/dawn_native",
     ]
   }
diff --git a/testing/gmock/BUILD.gn b/testing/gmock/BUILD.gn
index c62825a..0e7cc53 100644
--- a/testing/gmock/BUILD.gn
+++ b/testing/gmock/BUILD.gn
@@ -10,7 +10,6 @@
   testonly = true
   sources = [
     "include/gmock/gmock-actions.h",
-    "include/gmock/gmock-generated-function-mockers.h",
     "include/gmock/gmock-matchers.h",
     "include/gmock/gmock.h",
   ]
diff --git a/testing/gmock/include/gmock/gmock-generated-function-mockers.h b/testing/gmock/include/gmock/gmock-generated-function-mockers.h
deleted file mode 100644
index b9986c7..0000000
--- a/testing/gmock/include/gmock/gmock-generated-function-mockers.h
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// The file/directory layout of Google Test is not yet considered stable. Until
-// it stabilizes, Chromium code will use forwarding headers in testing/gtest
-// and testing/gmock, instead of directly including files in
-// third_party/googletest.
-
-#include "third_party/googletest/src/googlemock/include/gmock/gmock-generated-function-mockers.h"
diff --git a/third_party/blink/public/blink_typemaps.gni b/third_party/blink/public/blink_typemaps.gni
index 397290a7..13192d8 100644
--- a/third_party/blink/public/blink_typemaps.gni
+++ b/third_party/blink/public/blink_typemaps.gni
@@ -12,6 +12,4 @@
   "//services/viz/public/cpp/compositing/returned_resource.typemap",
   "//services/viz/public/cpp/compositing/surface_id.typemap",
   "//services/viz/public/cpp/compositing/surface_info.typemap",
-  "//ui/display/mojom/display_rotation_for_blink.typemap",
-  "//ui/gfx/mojom/gpu_fence_handle_for_blink.typemap",
 ]
diff --git a/third_party/blink/public/common/BUILD.gn b/third_party/blink/public/common/BUILD.gn
index 402f79f2..13ba2da 100644
--- a/third_party/blink/public/common/BUILD.gn
+++ b/third_party/blink/public/common/BUILD.gn
@@ -130,7 +130,6 @@
     "notifications/notification_resources.h",
     "notifications/platform_notification_data.h",
     "oom_intervention/oom_intervention_types.h",
-    "origin_policy/origin_policy.h",
     "origin_trials/origin_trial_policy.h",
     "origin_trials/trial_token.h",
     "origin_trials/trial_token_validator.h",
diff --git a/third_party/blink/public/common/origin_policy/OWNERS b/third_party/blink/public/common/origin_policy/OWNERS
deleted file mode 100644
index cc8f52f4..0000000
--- a/third_party/blink/public/common/origin_policy/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://third_party/blink/common/origin_policy/OWNERS
diff --git a/third_party/blink/public/common/origin_policy/origin_policy.h b/third_party/blink/public/common/origin_policy/origin_policy.h
deleted file mode 100644
index b4ee595..0000000
--- a/third_party/blink/public/common/origin_policy/origin_policy.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_ORIGIN_POLICY_ORIGIN_POLICY_H_
-#define THIRD_PARTY_BLINK_PUBLIC_COMMON_ORIGIN_POLICY_ORIGIN_POLICY_H_
-
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/strings/string_piece.h"
-#include "third_party/blink/public/common/common_export.h"
-#include "url/origin.h"
-
-namespace blink {
-
-class OriginPolicyParser;
-
-class BLINK_COMMON_EXPORT OriginPolicy {
- public:
-  ~OriginPolicy();
-
-  // Create & parse the manifest.
-  static std::unique_ptr<OriginPolicy> From(base::StringPiece);
-
-  struct CSP {
-    std::string policy;
-    bool report_only;
-  };
-  const std::vector<CSP>& GetContentSecurityPolicies() const { return csp_; }
-
-  const std::vector<std::string>& GetFeaturePolicies() const {
-    return features_;
-  }
-
-  const std::set<url::Origin>& GetFirstPartySet() const {
-    return first_party_set_;
-  }
-
- private:
-  friend class OriginPolicyParser;
-
-  OriginPolicy();
-
-  std::vector<CSP> csp_;
-  std::vector<std::string> features_;
-  std::set<url::Origin> first_party_set_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_ORIGIN_POLICY_ORIGIN_POLICY_H_
diff --git a/third_party/blink/public/mojom/feature_policy/document_policy_feature.mojom b/third_party/blink/public/mojom/feature_policy/document_policy_feature.mojom
index bd79dea3..ca03424 100644
--- a/third_party/blink/public/mojom/feature_policy/document_policy_feature.mojom
+++ b/third_party/blink/public/mojom/feature_policy/document_policy_feature.mojom
@@ -6,7 +6,7 @@
 
 // These values map to the features which can be controlled by Document Policy.
 enum DocumentPolicyFeature {
-  kNotFound = 0,
+  kDefault = 0,
   // Controls access to font-display attribute in @font-face CSS rule
   kFontDisplay = 1,
   // Takes a parameter, |bpp|, i.e. byte-per-pixel ratio, that images
diff --git a/third_party/blink/public/platform/DEPS b/third_party/blink/public/platform/DEPS
index 07cfbe0..4a8c2f8 100644
--- a/third_party/blink/public/platform/DEPS
+++ b/third_party/blink/public/platform/DEPS
@@ -45,6 +45,7 @@
     "+services/network/public/mojom/cors.mojom-shared.h",
     "+services/network/public/mojom/fetch_api.mojom-shared.h",
     "+services/network/public/mojom/referrer_policy.mojom-shared.h",
+    "+services/network/public/mojom/trust_tokens.mojom-shared.h",
     "+services/network/public/mojom/web_client_hints_types.mojom-shared.h",
 
     "+services/service_manager/public/mojom",
diff --git a/third_party/blink/public/platform/web_url_error.h b/third_party/blink/public/platform/web_url_error.h
index b7b3a60..c555176 100644
--- a/third_party/blink/public/platform/web_url_error.h
+++ b/third_party/blink/public/platform/web_url_error.h
@@ -36,6 +36,7 @@
 #include "net/dns/public/resolve_error_info.h"
 #include "services/network/public/cpp/blocked_by_response_reason.h"
 #include "services/network/public/cpp/cors/cors_error_status.h"
+#include "services/network/public/mojom/trust_tokens.mojom-shared.h"
 #include "third_party/blink/public/platform/web_url.h"
 
 namespace blink {
@@ -71,6 +72,16 @@
                                     HasCopyInCache,
                                     const WebURL&);
 
+  // Constructs a new error for a request failing due to a Trust Tokens error.
+  // This takes an integer error code in addition to a TrustTokenOperationStatus
+  // because there are multiple Trust Tokens //net error codes.
+  //
+  // |trust_token_operation_error| must be an actual error (i.e., not kOk).
+  BLINK_PLATFORM_EXPORT WebURLError(
+      int reason,
+      network::mojom::TrustTokenOperationStatus trust_token_operation_error,
+      const WebURL& url);
+
   int reason() const { return reason_; }
   int extended_reason() const { return extended_reason_; }
   const net::ResolveErrorInfo& resolve_error_info() const {
@@ -86,6 +97,10 @@
   blocked_by_response_reason() const {
     return blocked_by_response_reason_;
   }
+  network::mojom::TrustTokenOperationStatus trust_token_operation_error()
+      const {
+    return trust_token_operation_error_;
+  }
 
  private:
   // A numeric error code detailing the reason for this error. The value must
@@ -114,6 +129,16 @@
   // More detailed reason for failing the response with
   // ERR_net::ERR_BLOCKED_BY_RESPONSE |error_code|.
   base::Optional<network::BlockedByResponseReason> blocked_by_response_reason_;
+
+  // More detailed reason for failing the response with
+  // net::ERR_TRUST_TOKEN_OPERATION_FAILED or
+  // net::ERR_TRUST_TOKEN_OPERATION_CACHE_HIT.
+  //
+  // A value of kOk means that this request failed for a reason other than a
+  // Trust Tokens operation failure. This does not necessarily mean that a Trust
+  // Tokens operation was executed successfully, or even that one was attempted.
+  network::mojom::TrustTokenOperationStatus trust_token_operation_error_ =
+      network::mojom::TrustTokenOperationStatus::kOk;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.cc b/third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.cc
index 3a5b825..3d314f5 100644
--- a/third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.cc
+++ b/third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.cc
@@ -16,7 +16,8 @@
     const BeginFrameProviderParams& begin_frame_provider_params)
     : begin_frame_provider_(
           MakeGarbageCollected<BeginFrameProvider>(begin_frame_provider_params,
-                                                   this)),
+                                                   this,
+                                                   context)),
       callback_collection_(context),
       context_(context) {}
 
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
index 4aacd0d..89289906 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -449,31 +449,33 @@
 
 DisplayLockContext::ScopedForcedUpdate
 DisplayLockContext::GetScopedForcedUpdate() {
-  if (!is_locked_)
-    return ScopedForcedUpdate(nullptr);
+  ++update_forced_;
+  if (update_forced_ == 1) {
+    TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
+        TRACE_DISABLED_BY_DEFAULT("blink.debug.display_lock"), "LockForced",
+        TRACE_ID_LOCAL(this));
+  }
 
-  DCHECK(!update_forced_);
-  update_forced_ = true;
-  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
-      TRACE_DISABLED_BY_DEFAULT("blink.debug.display_lock"), "LockForced",
-      TRACE_ID_LOCAL(this));
-
-  // Now that the update is forced, we should ensure that style layout, and
-  // prepaint code can reach it via dirty bits. Note that paint isn't a part of
-  // this, since |update_forced_| doesn't force paint to happen. See
-  // ShouldPaint().
-  MarkForStyleRecalcIfNeeded();
-  MarkForLayoutIfNeeded();
-  MarkAncestorsForPrePaintIfNeeded();
+  if (IsLocked()) {
+    // Now that the update is forced, we should ensure that style layout, and
+    // prepaint code can reach it via dirty bits. Note that paint isn't a part
+    // of this, since |update_forced_| doesn't force paint to happen. See
+    // ShouldPaint().
+    MarkForStyleRecalcIfNeeded();
+    MarkForLayoutIfNeeded();
+    MarkAncestorsForPrePaintIfNeeded();
+  }
   return ScopedForcedUpdate(this);
 }
 
 void DisplayLockContext::NotifyForcedUpdateScopeEnded() {
   DCHECK(update_forced_);
-  update_forced_ = false;
-  TRACE_EVENT_NESTABLE_ASYNC_END0(
-      TRACE_DISABLED_BY_DEFAULT("blink.debug.display_lock"), "LockForced",
-      TRACE_ID_LOCAL(this));
+  --update_forced_;
+  if (update_forced_ == 0) {
+    TRACE_EVENT_NESTABLE_ASYNC_END0(
+        TRACE_DISABLED_BY_DEFAULT("blink.debug.display_lock"), "LockForced",
+        TRACE_ID_LOCAL(this));
+  }
 }
 
 void DisplayLockContext::Unlock() {
@@ -605,7 +607,7 @@
   if (IsElementDirtyForLayout()) {
     // Forces the marking of ancestors to happen, even if
     // |DisplayLockContext::ShouldLayout()| returns false.
-    base::AutoReset<bool> scoped_force(&update_forced_, true);
+    base::AutoReset<int> scoped_force(&update_forced_, update_forced_ + 1);
     if (child_layout_was_blocked_) {
       // We've previously blocked a child traversal when doing self-layout for
       // the locked element, so we're marking it with child-needs-layout so that
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.h b/third_party/blink/renderer/core/display_lock/display_lock_context.h
index 870b662..f285130 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.h
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.h
@@ -328,7 +328,8 @@
   // style recalc on them.
   HeapHashSet<Member<Element>> whitespace_reattach_set_;
 
-  bool update_forced_ = false;
+  // If non-zero, then the update has been forced.
+  int update_forced_ = 0;
 
   StyleType blocked_style_traversal_type_ = kStyleUpdateNotRequired;
   // Signifies whether we've blocked a layout tree reattachment on |element_|'s
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
index eb7c5e57..bd0aa6e 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc
@@ -51,8 +51,6 @@
                                                                    reason)) {
       DCHECK(locked_activatable_ancestor->GetDisplayLockContext());
       DCHECK(locked_activatable_ancestor->GetDisplayLockContext()->IsLocked());
-      DCHECK(!locked_activatable_ancestor->GetDisplayLockContext()
-                  ->UpdateForced());
       scoped_forced_update_list_.push_back(
           locked_activatable_ancestor->GetDisplayLockContext()
               ->GetScopedForcedUpdate());
@@ -212,10 +210,8 @@
     auto* ancestor_node = DynamicTo<Element>(ancestor);
     if (!ancestor_node)
       continue;
-    if (auto* context = ancestor_node->GetDisplayLockContext()) {
-      DCHECK(!context->UpdateForced());
+    if (auto* context = ancestor_node->GetDisplayLockContext())
       scoped_update_forced_list_.push_back(context->GetScopedForcedUpdate());
-    }
   }
 }
 
diff --git a/third_party/blink/renderer/core/feature_policy/document_policy_parser.cc b/third_party/blink/renderer/core/feature_policy/document_policy_parser.cc
index fb58514..0d398fe 100644
--- a/third_party/blink/renderer/core/feature_policy/document_policy_parser.cc
+++ b/third_party/blink/renderer/core/feature_policy/document_policy_parser.cc
@@ -11,6 +11,10 @@
 
 namespace {
 
+constexpr const char* kReportTo = "report-to";
+constexpr const char* kNone = "none";
+constexpr const char* kWildCard = "*";
+
 base::Optional<PolicyValue> ItemToPolicyValue(
     const net::structured_headers::Item& item) {
   switch (item.Type()) {
@@ -34,8 +38,32 @@
   mojom::blink::DocumentPolicyFeature feature;
   PolicyValue policy_value;
   base::Optional<std::string> endpoint_group;
+  // Wildcard feature('*') is used to specify default endpoint for features.
+  bool is_wildcard = false;
 };
 
+base::Optional<ParsedFeature> ParseWildcardFeature(
+    const net::structured_headers::ParameterizedMember& directive) {
+  // Wildcard feature can only have 1 param, which is 'report-to'.
+  if (directive.params.size() != 1)
+    return base::nullopt;
+
+  const auto& param = directive.params.front();
+
+  // Wildcard feature can only have 1 param, which is 'report-to'.
+  if (param.first != kReportTo)
+    return base::nullopt;
+
+  base::Optional<std::string> endpoint_group = ItemToString(param.second);
+
+  if (!endpoint_group)
+    return base::nullopt;
+
+  return base::make_optional<ParsedFeature>(
+      {mojom::blink::DocumentPolicyFeature::kDefault, PolicyValue(),
+       endpoint_group, true});
+}
+
 base::Optional<ParsedFeature> ParseFeature(
     const net::structured_headers::ParameterizedMember& directive,
     const DocumentPolicyNameFeatureMap& name_feature_map,
@@ -59,6 +87,10 @@
     return base::nullopt;
 
   std::string feature_name = feature_token.GetString();
+
+  if (feature_name == kWildCard)
+    return ParseWildcardFeature(directive);
+
   auto feature_iter = name_feature_map.find(feature_name);
 
   // Parse feature_name string to DocumentPolicyFeature.
@@ -98,7 +130,7 @@
     // Document-Policy header that specifies the endpoint group that the policy
     // should send report to. If left unspecified, no report will be send upon
     // policy violation.
-    if (param_name == "report-to") {
+    if (param_name == kReportTo) {
       base::Optional<std::string> endpoint_group = ItemToString(param.second);
       if (!endpoint_group)
         return base::nullopt;
@@ -132,6 +164,35 @@
   return parsed_feature;
 }
 
+// Apply |default_endpoint| to given |parsed_policy|.
+void ApplyDefaultEndpoint(DocumentPolicy::ParsedDocumentPolicy& parsed_policy,
+                          const std::string& default_endpoint) {
+  DocumentPolicy::FeatureEndpointMap& endpoint_map = parsed_policy.endpoint_map;
+
+  if (!default_endpoint.empty()) {
+    // Fill |default_endpoint| to all feature entry whose |endpoint_group|
+    // is missing.
+    for (const auto& feature_and_value : parsed_policy.feature_state) {
+      mojom::blink::DocumentPolicyFeature feature = feature_and_value.first;
+
+      if (endpoint_map.find(feature) == endpoint_map.end())
+        endpoint_map.emplace(feature, default_endpoint);
+    }
+  }
+
+  // Remove |endpoint_group| for feature entry if its |endpoint_group|
+  // is "none".
+  // Note: if |default_endpoint| is "none", all "none" items are filtered out
+  // here. it would be equivalent to doing nothing.
+  for (auto iter = endpoint_map.begin(); iter != endpoint_map.end();) {
+    if (iter->second == kNone) {
+      iter = endpoint_map.erase(iter);
+    } else {
+      ++iter;
+    }
+  }
+}
+
 }  // namespace
 
 // static
@@ -157,6 +218,7 @@
     return base::nullopt;
 
   DocumentPolicy::ParsedDocumentPolicy parse_result;
+  std::string default_endpoint = "";
   for (const net::structured_headers::ParameterizedMember& directive :
        root.value()) {
     base::Optional<ParsedFeature> parsed_feature_option =
@@ -167,6 +229,11 @@
 
     ParsedFeature parsed_feature = *parsed_feature_option;
 
+    if (parsed_feature.is_wildcard) {
+      default_endpoint = *parsed_feature.endpoint_group;
+      continue;
+    }
+
     // If feature is not available, i.e. not enabled, ignore the entry.
     if (available_features.find(parsed_feature.feature) ==
         available_features.end())
@@ -179,6 +246,9 @@
                                         *parsed_feature.endpoint_group);
     }
   }
+
+  ApplyDefaultEndpoint(parse_result, default_endpoint);
+
   return parse_result;
 }
 
diff --git a/third_party/blink/renderer/core/feature_policy/document_policy_parser_test.cc b/third_party/blink/renderer/core/feature_policy/document_policy_parser_test.cc
index d4324757..f13f639 100644
--- a/third_party/blink/renderer/core/feature_policy/document_policy_parser_test.cc
+++ b/third_party/blink/renderer/core/feature_policy/document_policy_parser_test.cc
@@ -63,6 +63,10 @@
     "no-f-bool;report-to=default,f-double;value=2.0;report-to=default",
     "no-f-bool;report-to=default,f-double;report-to=default;value=2.0",
     "no-f-bool;report-to=default,f-double;report-to=endpoint;value=2.0",
+    "no-f-bool,f-double;value=2.0;report-to=endpoint,*;report-to=default",
+    "*;report-to=default",  // An empty policy.
+    "no-f-bool;report-to=none, f-double;value=2.0, *;report-to=default",
+    "no-f-bool;report-to=none, f-double;value=2.0, *;report-to=none",
 };
 
 const char* const kInvalidPolicies[] = {
@@ -116,7 +120,43 @@
         {"no-f-bool;report-to=default,f-double;value=1",
          {{{kBoolFeature, PolicyValue(false)},
            {kDoubleFeature, PolicyValue(1.0)}},
-          {{kBoolFeature, "default"}}}}};
+          {{kBoolFeature, "default"}}}},
+        {"no-f-bool;report-to=none, f-double;value=2.0, *;report-to=default",
+         {/* feature_state */ {{kBoolFeature, PolicyValue(false)},
+                               {kDoubleFeature, PolicyValue(2.0)}},
+          /* endpoint_map */ {{kDoubleFeature, "default"}}}},
+        {"no-f-bool;report-to=not_none, f-double;value=2.0, "
+         "*;report-to=default",
+         {/* feature_state */ {{kBoolFeature, PolicyValue(false)},
+                               {kDoubleFeature, PolicyValue(2.0)}},
+          /* endpoint_map */ {{kBoolFeature, "not_none"},
+                              {kDoubleFeature, "default"}}}},
+        {"no-f-bool;report-to=not_none, f-double;value=2.0, *;report-to=none",
+         {/* feature_state */ {{kBoolFeature, PolicyValue(false)},
+                               {kDoubleFeature, PolicyValue(2.0)}},
+          /* endpoint_map */ {{kBoolFeature, "not_none"}}}},
+        // Default endpoint can be specified anywhere in the header, not
+        // necessary at the end.
+        {"no-f-bool;report-to=not_none, *;report-to=default, "
+         "f-double;value=2.0",
+         {/* feature_state */ {{kBoolFeature, PolicyValue(false)},
+                               {kDoubleFeature, PolicyValue(2.0)}},
+          /* endpoint_map */ {{kBoolFeature, "not_none"},
+                              {kDoubleFeature, "default"}}}},
+        // Default endpoint can be specified multiple times in the header.
+        // According to SH rules, last value wins.
+        {"no-f-bool;report-to=not_none, f-double;value=2.0, "
+         "*;report-to=default, "
+         "*;report-to=none",
+         {/* feature_state */ {{kBoolFeature, PolicyValue(false)},
+                               {kDoubleFeature, PolicyValue(2.0)}},
+          /* endpoint_map */ {{kBoolFeature, "not_none"}}}},
+        // Even if default endpoint is not specified, none still should be
+        // treated as a reserved keyword for endpoint names.
+        {"no-f-bool;report-to=none",
+         {/* feature_state */ {{kBoolFeature, PolicyValue(false)}},
+          /* endpoint_map */ {}}},
+};
 
 const DocumentPolicy::FeatureState kParsedPolicies[] = {
     {},  // An empty policy
diff --git a/third_party/blink/renderer/core/fetch/fetch_manager.cc b/third_party/blink/renderer/core/fetch/fetch_manager.cc
index 5c62a59..d02e450 100644
--- a/third_party/blink/renderer/core/fetch/fetch_manager.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_manager.cc
@@ -12,10 +12,12 @@
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/request_mode.h"
 #include "services/network/public/mojom/fetch_api.mojom-blink.h"
+#include "services/network/public/mojom/trust_tokens.mojom-blink.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_response_init.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
 #include "third_party/blink/renderer/core/dom/abort_signal.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
@@ -25,6 +27,7 @@
 #include "third_party/blink/renderer/core/fetch/form_data_bytes_consumer.h"
 #include "third_party/blink/renderer/core/fetch/place_holder_bytes_consumer.h"
 #include "third_party/blink/renderer/core/fetch/response.h"
+#include "third_party/blink/renderer/core/fetch/trust_token_to_mojom.h"
 #include "third_party/blink/renderer/core/fileapi/blob.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 #include "third_party/blink/renderer/core/frame/frame.h"
@@ -226,7 +229,9 @@
   void PerformNetworkError(const String& message);
   void PerformHTTPFetch(ExceptionState&);
   void PerformDataFetch();
-  void Failed(const String& message);
+  // If |dom_exception| is provided, throws the specified DOMException instead
+  // of the usual "Failed to fetch" TypeError.
+  void Failed(const String& message, DOMException* dom_exception);
   void NotifyFinished();
   ExecutionContext* GetExecutionContext() { return execution_context_; }
 
@@ -530,11 +535,18 @@
 }
 
 void FetchManager::Loader::DidFail(const ResourceError& error) {
-  Failed(String());
+  if (error.TrustTokenOperationError() !=
+      network::mojom::blink::TrustTokenOperationStatus::kOk) {
+    Failed(String(),
+           TrustTokenErrorToDOMException(error.TrustTokenOperationError()));
+    return;
+  }
+
+  Failed(String(), nullptr);
 }
 
 void FetchManager::Loader::DidFailRedirectCheck() {
-  Failed(String());
+  Failed(String(), nullptr);
 }
 
 void FetchManager::Loader::Start(ExceptionState& exception_state) {
@@ -690,7 +702,7 @@
 }
 
 void FetchManager::Loader::PerformNetworkError(const String& message) {
-  Failed(message);
+  Failed(message, nullptr);
 }
 
 void FetchManager::Loader::PerformHTTPFetch(ExceptionState& exception_state) {
@@ -832,7 +844,8 @@
   threadable_loader_->Start(request);
 }
 
-void FetchManager::Loader::Failed(const String& message) {
+void FetchManager::Loader::Failed(const String& message,
+                                  DOMException* dom_exception) {
   if (failed_ || finished_)
     return;
   failed_ = true;
@@ -846,8 +859,12 @@
   if (resolver_) {
     ScriptState* state = resolver_->GetScriptState();
     ScriptState::Scope scope(state);
-    resolver_->Reject(V8ThrowException::CreateTypeError(state->GetIsolate(),
-                                                        "Failed to fetch"));
+    if (dom_exception) {
+      resolver_->Reject(dom_exception);
+    } else {
+      resolver_->Reject(V8ThrowException::CreateTypeError(state->GetIsolate(),
+                                                          "Failed to fetch"));
+    }
   }
   NotifyFinished();
 }
diff --git a/third_party/blink/renderer/core/fetch/trust_token_to_mojom.cc b/third_party/blink/renderer/core/fetch/trust_token_to_mojom.cc
index 1fe53b72..c0064caf 100644
--- a/third_party/blink/renderer/core/fetch/trust_token_to_mojom.cc
+++ b/third_party/blink/renderer/core/fetch/trust_token_to_mojom.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "third_party/blink/renderer/core/fetch/trust_token_to_mojom.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
 
 namespace blink {
 
@@ -87,4 +88,27 @@
   return true;
 }
 
+DOMException* TrustTokenErrorToDOMException(
+    network::mojom::blink::TrustTokenOperationStatus error) {
+  // This should only be called on failure.
+  DCHECK_NE(error, network::mojom::blink::TrustTokenOperationStatus::kOk);
+
+  switch (error) {
+    case network::mojom::blink::TrustTokenOperationStatus::kAlreadyExists:
+      return DOMException::Create(
+          "Redemption operation aborted due to Signed Redemption Record "
+          "cache hit",
+          DOMException::GetErrorName(
+              DOMExceptionCode::kNoModificationAllowedError));
+    case network::mojom::blink::TrustTokenOperationStatus::kFailedPrecondition:
+      return DOMException::Create(
+          "Precondition failed during Trust Tokens operation",
+          DOMException::GetErrorName(DOMExceptionCode::kInvalidStateError));
+    default:
+      return DOMException::Create(
+          "Error executing Trust Tokens operation",
+          DOMException::GetErrorName(DOMExceptionCode::kOperationError));
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/fetch/trust_token_to_mojom.h b/third_party/blink/renderer/core/fetch/trust_token_to_mojom.h
index 680f710..4097c23 100644
--- a/third_party/blink/renderer/core/fetch/trust_token_to_mojom.h
+++ b/third_party/blink/renderer/core/fetch/trust_token_to_mojom.h
@@ -11,6 +11,8 @@
 
 namespace blink {
 
+class DOMException;
+
 // Converts an IDL trustToken object to its Mojo counterpart.
 // The elements of trustToken (and of TrustTokenParams) comprise:
 // - an operation type, always populated
@@ -32,6 +34,13 @@
                               ExceptionState* exception_state,
                               network::mojom::blink::TrustTokenParams* out);
 
+// Converts a Mojo TrustTokenOperationStatus denoting an error into a
+// DOMException suitable for displaying to the API's client.
+//
+// This should only be called on failure; |status| must not equal kOk.
+DOMException* TrustTokenErrorToDOMException(
+    network::mojom::blink::TrustTokenOperationStatus error);
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_FETCH_TRUST_TOKEN_TO_MOJOM_H_
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
index 39c0443..de92635 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -1399,14 +1399,6 @@
   LogToConsole(message);
 }
 
-void ContentSecurityPolicy::ReportMissingReportURI(const String& policy) {
-  LogToConsole("The Content Security Policy '" + policy +
-               "' was delivered in report-only mode, but does not specify a "
-               "'report-uri'; the policy will have no effect. Please either "
-               "add a 'report-uri' directive, or deliver the policy via the "
-               "'Content-Security-Policy' header.");
-}
-
 void ContentSecurityPolicy::LogToConsole(const String& message,
                                          mojom::ConsoleMessageLevel level) {
   LogToConsole(MakeGarbageCollected<ConsoleMessage>(
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.h b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
index deb8f0d..22473bea 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.h
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
@@ -382,7 +382,6 @@
   void ReportInvalidSandboxFlags(const String&);
   void ReportInvalidSourceExpression(const String& directive_name,
                                      const String& source);
-  void ReportMissingReportURI(const String&);
   void ReportUnsupportedDirective(const String&);
   void ReportInvalidInReportOnly(const String&);
   void ReportInvalidDirectiveInMeta(const String& directive_name);
diff --git a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
index f6307f0..2f3920be 100644
--- a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
+++ b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
@@ -171,13 +171,6 @@
     directives->SetEvalDisabledErrorMessage(message);
   }
 
-  if (directives->IsReportOnly() &&
-      source != ContentSecurityPolicySource::kMeta &&
-      directives->ReportEndpoints().IsEmpty()) {
-    policy->ReportMissingReportURI(
-        String(begin, static_cast<wtf_size_t>(end - begin)));
-  }
-
   return directives;
 }
 
diff --git a/third_party/blink/renderer/core/html/resources/android.css b/third_party/blink/renderer/core/html/resources/android.css
index 8212135..b6ee01f 100644
--- a/third_party/blink/renderer/core/html/resources/android.css
+++ b/third_party/blink/renderer/core/html/resources/android.css
@@ -30,6 +30,12 @@
 
 /* These styles override other user-agent styles for Chromium on Android. */
 
+/* This sheet is appended to html.css before parsing which means the selectors
+   below are in the default html namespace:
+
+   @namespace "http://www.w3.org/1999/xhtml"
+*/
+
 input[type="date" i]:disabled,
 input[type="datetime-local" i]:disabled,
 input[type="month" i]:disabled,
diff --git a/third_party/blink/renderer/core/html/resources/controls_refresh.css b/third_party/blink/renderer/core/html/resources/controls_refresh.css
index d3e87b5..276d0fc 100644
--- a/third_party/blink/renderer/core/html/resources/controls_refresh.css
+++ b/third_party/blink/renderer/core/html/resources/controls_refresh.css
@@ -8,6 +8,12 @@
  * using the refreshed controls UI.
  */
 
+/* This sheet is appended to html.css before parsing which means the selectors
+   below are in the default html namespace:
+
+   @namespace "http://www.w3.org/1999/xhtml"
+*/
+
 select,
 select:-internal-list-box,
 input,
diff --git a/third_party/blink/renderer/core/html/resources/forced_colors.css b/third_party/blink/renderer/core/html/resources/forced_colors.css
index c35e7e7..8752b6d 100644
--- a/third_party/blink/renderer/core/html/resources/forced_colors.css
+++ b/third_party/blink/renderer/core/html/resources/forced_colors.css
@@ -8,6 +8,12 @@
  * is enabled.
  */
 
+/* This sheet is appended to html.css before parsing which means the selectors
+   below are in the default html namespace:
+
+   @namespace "http://www.w3.org/1999/xhtml"
+*/
+
 @media forced-colors {
   body {
     background-color: Canvas;
@@ -223,4 +229,4 @@
     background-color: Window !important;
   }
 
-}
\ No newline at end of file
+}
diff --git a/third_party/blink/renderer/core/html/resources/input_multiple_fields.css b/third_party/blink/renderer/core/html/resources/input_multiple_fields.css
index db849b0..d0591f6 100644
--- a/third_party/blink/renderer/core/html/resources/input_multiple_fields.css
+++ b/third_party/blink/renderer/core/html/resources/input_multiple_fields.css
@@ -3,6 +3,12 @@
  * found in the LICENSE file.
  */
 
+/* This sheet is appended to html.css before parsing which means the selectors
+   below are in the default html namespace:
+
+   @namespace "http://www.w3.org/1999/xhtml"
+*/
+
 input[type="date" i],
 input[type="datetime-local" i],
 input[type="month" i],
diff --git a/third_party/blink/renderer/core/html/resources/linux.css b/third_party/blink/renderer/core/html/resources/linux.css
index f45f6c7..847265f 100644
--- a/third_party/blink/renderer/core/html/resources/linux.css
+++ b/third_party/blink/renderer/core/html/resources/linux.css
@@ -30,6 +30,12 @@
 
 /* These styles override other user-agent styles for Chromium on Linux. */
 
+/* This sheet is appended to html.css before parsing which means the selectors
+   below are in the default html namespace:
+
+   @namespace "http://www.w3.org/1999/xhtml"
+*/
+
 select:not(:-internal-list-box) {
     /* Selects with popup menus look like buttons with a drop down triangle on Linux. */
     background-color: ButtonFace;
diff --git a/third_party/blink/renderer/core/html/resources/mac.css b/third_party/blink/renderer/core/html/resources/mac.css
index e575c8e7a..1e1677ba 100644
--- a/third_party/blink/renderer/core/html/resources/mac.css
+++ b/third_party/blink/renderer/core/html/resources/mac.css
@@ -3,6 +3,12 @@
  * found in the LICENSE file.
  */
 
+/* This sheet is appended to html.css before parsing which means the selectors
+   below are in the default html namespace:
+
+   @namespace "http://www.w3.org/1999/xhtml"
+*/
+
 select, input[type="color" i][list] {
     /* TODO(tkent): Use ButtonFace and border same as buttons. */
     background-color: #f8f8f8;
diff --git a/third_party/blink/renderer/core/html/resources/quirks.css b/third_party/blink/renderer/core/html/resources/quirks.css
index e880fe0e..4e9d8a8 100644
--- a/third_party/blink/renderer/core/html/resources/quirks.css
+++ b/third_party/blink/renderer/core/html/resources/quirks.css
@@ -21,6 +21,12 @@
  *
  */
 
+/* This sheet is appended to html.css before parsing which means the selectors
+   below are in the default html namespace:
+
+   @namespace "http://www.w3.org/1999/xhtml"
+*/
+
 /* Give floated images margins of 3px */
 img[align="left" i] {
     margin-right: 3px;
diff --git a/third_party/blink/renderer/core/html/resources/win.css b/third_party/blink/renderer/core/html/resources/win.css
index ce9f3120..c1dfae2 100644
--- a/third_party/blink/renderer/core/html/resources/win.css
+++ b/third_party/blink/renderer/core/html/resources/win.css
@@ -32,6 +32,12 @@
    core/html/resources/tml.css. So far we have used this file exclusively
    for making our form elements match Firefox's. */
 
+/* This sheet is appended to html.css before parsing which means the selectors
+   below are in the default html namespace:
+
+   @namespace "http://www.w3.org/1999/xhtml"
+*/
+
 /*
  * Update padding for all text-like types including unknown types.
  * Non-text types have input[type="foo" i] with padding properties in
diff --git a/third_party/blink/renderer/core/html/resources/win_quirks.css b/third_party/blink/renderer/core/html/resources/win_quirks.css
index 196d0820..09e5fbd 100644
--- a/third_party/blink/renderer/core/html/resources/win_quirks.css
+++ b/third_party/blink/renderer/core/html/resources/win_quirks.css
@@ -32,6 +32,12 @@
    as defined in core/html/resources/quirks.css. So far we have used this
    file exclusively for making our form elements match Firefox's. */
 
+/* This sheet is appended to html.css before parsing which means the selectors
+   below are in the default html namespace:
+
+   @namespace "http://www.w3.org/1999/xhtml"
+*/
+
 textarea {
   /* Matches IE's text offsets in quirksmode (causes text to wrap the same as IE). */
   padding: 2px 0 0 2px;
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 90ffe6c..f9912f0 100644
--- a/third_party/blink/renderer/core/layout/layout_theme_mac.mm
+++ b/third_party/blink/renderer/core/layout/layout_theme_mac.mm
@@ -161,6 +161,7 @@
       return [[NSFileManager defaultManager] displayNameAtPath:file.GetPath()];
     return file.name();
   }
+  bool PopsMenuByArrowKeys() const override;
 
  protected:
   // Controls color values returned from FocusRingColor().
@@ -377,6 +378,10 @@
   return WebTestSupport::IsRunningWebTest();
 }
 
+bool LayoutThemeMacRefresh::PopsMenuByArrowKeys() const {
+  return true;
+}
+
 static FontSelectionValue ToFontWeight(NSInteger app_kit_font_weight) {
   DCHECK_GT(app_kit_font_weight, 0);
   DCHECK_LT(app_kit_font_weight, 15);
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc
index f65bb23..c264b97 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc
@@ -74,6 +74,9 @@
     }
   }
 
+  if (!use_path_fallback_)
+    ClearPath();
+
   fill_bounding_box_ = FloatRect(
       length_context.ResolveLengthPair(svg_style.X(), svg_style.Y(), style),
       bounding_box_size);
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
index 66bff8d5..6ad438e 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
@@ -69,6 +69,19 @@
       TransformHelper::DependsOnReferenceBox(StyleRef());
   LayoutSVGModelObject::StyleDidChange(diff, old_style);
   SVGResources::UpdatePaints(*GetElement(), old_style, StyleRef());
+
+  // Most of the stroke attributes (caps, joins, miters, width, etc.) will cause
+  // a re-layout which will clear the stroke-path cache; however, there are a
+  // couple of additional properties that *won't* cause a layout, but are
+  // significant enough to require invalidating the cache.
+  if (!diff.NeedsFullLayout() && old_style && stroke_path_cache_) {
+    const auto& old_svg_style = old_style->SvgStyle();
+    const auto& svg_style = StyleRef().SvgStyle();
+    if (old_svg_style.StrokeDashOffset() != svg_style.StrokeDashOffset() ||
+        *old_svg_style.StrokeDashArray() != *svg_style.StrokeDashArray()) {
+      stroke_path_cache_.reset();
+    }
+  }
 }
 
 void LayoutSVGShape::WillBeDestroyed() {
@@ -76,10 +89,20 @@
   LayoutSVGModelObject::WillBeDestroyed();
 }
 
+void LayoutSVGShape::ClearPath() {
+  path_.reset();
+  stroke_path_cache_.reset();
+}
+
 void LayoutSVGShape::CreatePath() {
   if (!path_)
     path_ = std::make_unique<Path>();
   *path_ = To<SVGGeometryElement>(GetElement())->AsPath();
+
+  // When the path changes, we need to ensure the stale stroke path cache is
+  // cleared. Because this is done in all callsites, we can just DCHECK that it
+  // has been cleared here.
+  DCHECK(!stroke_path_cache_);
 }
 
 float LayoutSVGShape::DashScaleFactor() const {
@@ -150,24 +173,33 @@
 
 bool LayoutSVGShape::ShapeDependentStrokeContains(
     const HitTestLocation& location) {
-  // In case the subclass didn't create path during UpdateShapeFromElement()
-  // for optimization but still calls this method.
-  if (!HasPath())
-    CreatePath();
+  if (!stroke_path_cache_) {
+    // In case the subclass didn't create path during UpdateShapeFromElement()
+    // for optimization but still calls this method.
+    if (!HasPath())
+      CreatePath();
 
-  StrokeData stroke_data;
-  SVGLayoutSupport::ApplyStrokeStyleToStrokeData(stroke_data, StyleRef(), *this,
-                                                 DashScaleFactor());
+    StrokeData stroke_data;
+    SVGLayoutSupport::ApplyStrokeStyleToStrokeData(stroke_data, StyleRef(),
+                                                   *this, DashScaleFactor());
 
-  if (HasNonScalingStroke()) {
-    // The reason is similar to the above code about HasPath().
-    if (!rare_data_)
-      UpdateNonScalingStrokeData();
-    return NonScalingStrokePath().StrokeContains(
-        NonScalingStrokeTransform().MapPoint(location.TransformedPoint()),
-        stroke_data);
+    if (HasNonScalingStroke()) {
+      // The reason is similar to the above code about HasPath().
+      if (!rare_data_)
+        UpdateNonScalingStrokeData();
+      stroke_path_cache_ = std::make_unique<Path>(
+          NonScalingStrokePath().StrokePath(stroke_data));
+    } else {
+      stroke_path_cache_ =
+          std::make_unique<Path>(path_->StrokePath(stroke_data));
+    }
   }
-  return path_->StrokeContains(location.TransformedPoint(), stroke_data);
+
+  DCHECK(stroke_path_cache_);
+  auto point = location.TransformedPoint();
+  if (HasNonScalingStroke())
+    point = NonScalingStrokeTransform().MapPoint(point);
+  return stroke_path_cache_->Contains(point);
 }
 
 bool LayoutSVGShape::ShapeDependentFillContains(
@@ -217,6 +249,10 @@
   if (EverHadLayout() && SelfNeedsLayout())
     SVGResourcesCache::ClientLayoutChanged(*this);
 
+  // The cached stroke may be affected by the ancestor transform, and so needs
+  // to be cleared regardless of whether the shape or bounds have changed.
+  stroke_path_cache_.reset();
+
   bool update_parent_boundaries = false;
   bool bbox_changed = false;
   // UpdateShapeFromElement() also updates the object & stroke bounds - which
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
index 803a52e..615840901 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
@@ -131,7 +131,7 @@
 
   float VisualRectOutsetForRasterEffects() const override;
 
-  void ClearPath() { path_.reset(); }
+  void ClearPath();
   void CreatePath();
 
   // Update (cached) shape data and the (object) bounding box.
@@ -189,6 +189,7 @@
   // into removing it.
   std::unique_ptr<Path> path_;
   mutable std::unique_ptr<LayoutSVGShapeRareData> rare_data_;
+  std::unique_ptr<Path> stroke_path_cache_;
 
   StrokeGeometryClass geometry_class_;
   bool needs_boundaries_update_ : 1;
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index 009f19f..1e495e2 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -37,7 +37,6 @@
 #include "base/time/default_tick_clock.h"
 #include "services/network/public/cpp/features.h"
 #include "third_party/blink/public/common/features.h"
-#include "third_party/blink/public/common/origin_policy/origin_policy.h"
 #include "third_party/blink/public/mojom/commit_result/commit_result.mojom-blink.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
 #include "third_party/blink/public/platform/web_url_request.h"
diff --git a/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc b/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc
index 2ce3837..58b7110 100644
--- a/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc
+++ b/third_party/blink/renderer/core/loader/mixed_content_checker_test.cc
@@ -7,7 +7,7 @@
 #include <base/macros.h>
 #include <memory>
 #include "base/memory/scoped_refptr.h"
-#include "testing/gmock/include/gmock/gmock-generated-function-mockers.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h"
 #include "third_party/blink/public/platform/web_mixed_content.h"
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index 043e3619..75fc370 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -58,6 +58,10 @@
       LayoutUnit(box_strut.bottom), LayoutUnit(box_strut.left));
 }
 
+inline bool HasSelection(const LayoutObject* layout_object) {
+  return layout_object->GetSelectionState() != SelectionState::kNone;
+}
+
 inline bool IsVisibleToPaint(const NGPhysicalFragment& fragment,
                              const ComputedStyle& style) {
   return !fragment.IsHiddenForPaint() &&
@@ -1364,7 +1368,8 @@
     if (!paint_info.IntersectsCullRect(child->InkOverflow(),
                                        paint_offset + child->Offset()) &&
         // Don't skip empty size text in order to paint selection for <br>.
-        !(child_fragment.IsText() && child_fragment.Size().IsEmpty()))
+        !(child_fragment.IsText() && child_fragment.Size().IsEmpty() &&
+          HasSelection(child_fragment.GetLayoutObject())))
       continue;
 
     if (child_fragment.Type() == NGPhysicalFragment::kFragmentText) {
@@ -1437,7 +1442,7 @@
   if (!paint_info.IntersectsCullRect(
           item.InkOverflow(), paint_offset + item.OffsetInContainerBlock()) &&
       // Don't skip <br>, it doesn't have ink but need to paint selection.
-      !item.IsLineBreak())
+      !(item.IsLineBreak() && HasSelection(item.GetLayoutObject())))
     return;
 
   NGTextFragmentPainter<NGInlineCursor> text_painter(cursor, parent_offset);
diff --git a/third_party/blink/renderer/core/paint/paint_timing.cc b/third_party/blink/renderer/core/paint/paint_timing.cc
index 6e71405..32c14a5 100644
--- a/third_party/blink/renderer/core/paint/paint_timing.cc
+++ b/third_party/blink/renderer/core/paint/paint_timing.cc
@@ -21,6 +21,7 @@
 #include "third_party/blink/renderer/core/timing/dom_window_performance.h"
 #include "third_party/blink/renderer/core/timing/window_performance.h"
 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
+#include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
@@ -245,6 +246,12 @@
   if (interactive_detector) {
     interactive_detector->OnFirstContentfulPaint(first_contentful_paint_swap_);
   }
+  auto* coordinator = GetSupplementable()->GetResourceCoordinator();
+  if (coordinator && GetFrame() && GetFrame()->IsMainFrame()) {
+    PerformanceTiming* timing = performance->timing();
+    base::TimeDelta fcp = stamp - timing->NavigationStartAsMonotonicTime();
+    coordinator->OnFirstContentfulPaint(fcp);
+  }
 }
 
 void PaintTiming::SetFirstImagePaintSwap(base::TimeTicks stamp) {
diff --git a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
index 721fc7b1..eacf2d3 100644
--- a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
+++ b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
@@ -30,6 +30,7 @@
 #include "base/feature_list.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
+#include "services/network/public/mojom/trust_tokens.mojom-shared.h"
 #include "third_party/blink/public/common/blob/blob_utils.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink-forward.h"
@@ -1694,6 +1695,12 @@
     return;
   }
 
+  if (error.TrustTokenOperationError() !=
+      network::mojom::TrustTokenOperationStatus::kOk) {
+    trust_token_operation_error_ =
+        TrustTokenErrorToDOMException(error.TrustTokenOperationError());
+  }
+
   HandleNetworkError();
 }
 
@@ -2082,6 +2089,7 @@
   visitor->Trace(upload_);
   visitor->Trace(blob_loader_);
   visitor->Trace(response_text_);
+  visitor->Trace(trust_token_operation_error_);
   XMLHttpRequestEventTarget::Trace(visitor);
   ThreadableLoaderClient::Trace(visitor);
   DocumentParserClient::Trace(visitor);
diff --git a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.h b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.h
index ce493b4..bd83562 100644
--- a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.h
+++ b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.h
@@ -32,6 +32,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_trust_token.h"
 #include "third_party/blink/renderer/core/dom/document_parser_client.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
 #include "third_party/blink/renderer/core/loader/threadable_loader_client.h"
 #include "third_party/blink/renderer/core/probe/async_task_id.h"
@@ -159,6 +160,9 @@
   String responseType();
   void setResponseType(const String&, ExceptionState&);
   String responseURL();
+  DOMException* trustTokenOperationError() const {
+    return trust_token_operation_error_;
+  }
 
   // For Inspector.
   void SendForInspectorXHRReplay(scoped_refptr<EncodedFormData>,
@@ -303,6 +307,7 @@
   AtomicString method_;
   HTTPHeaderMap request_headers_;
   network::mojom::blink::TrustTokenParamsPtr trust_token_params_;
+  Member<DOMException> trust_token_operation_error_;
   // Not converted to ASCII lowercase. Must be lowered later or compared
   // using case insensitive comparison functions if needed.
   AtomicString mime_type_override_;
diff --git a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.idl b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.idl
index a17a33b..99a761e 100644
--- a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.idl
+++ b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.idl
@@ -78,4 +78,5 @@
     [Custom=Getter, RaisesException=Getter] readonly attribute USVString responseText;
     // TODO(foolip): responseXML should be [Exposed=Window].
     [MeasureAs=XMLHttpRequestResponseXML, RaisesException=Getter] readonly attribute Document? responseXML;
+    [RuntimeEnabled=TrustTokens, SecureContext] readonly attribute DOMException trustTokenOperationError;
 };
diff --git a/third_party/blink/renderer/modules/content_index/content_description.idl b/third_party/blink/renderer/modules/content_index/content_description.idl
index 93b2652..8869c228 100644
--- a/third_party/blink/renderer/modules/content_index/content_description.idl
+++ b/third_party/blink/renderer/modules/content_index/content_description.idl
@@ -18,5 +18,5 @@
     required DOMString description;
     ContentCategory category = "";
     sequence<ContentIconDefinition> icons = [];
-    required USVString launchUrl;
+    required USVString url;
 };
diff --git a/third_party/blink/renderer/modules/content_index/content_description_type_converter.cc b/third_party/blink/renderer/modules/content_index/content_description_type_converter.cc
index cbf40e6a..fbe9ec1 100644
--- a/third_party/blink/renderer/modules/content_index/content_description_type_converter.cc
+++ b/third_party/blink/renderer/modules/content_index/content_description_type_converter.cc
@@ -59,7 +59,7 @@
     result->icons.push_back(blink::mojom::blink::ContentIconDefinition::New(
         icon->src(), icon->sizes(), icon->type()));
   }
-  result->launch_url = description->launchUrl();
+  result->launch_url = description->url();
 
   return result;
 }
@@ -85,7 +85,7 @@
   }
   result->setIcons(blink_icons);
 
-  result->setLaunchUrl(description->launch_url);
+  result->setUrl(description->launch_url);
   return result;
 }
 
diff --git a/third_party/blink/renderer/modules/content_index/content_description_type_converter_test.cc b/third_party/blink/renderer/modules/content_index/content_description_type_converter_test.cc
index 5a3733c..c97cba6b 100644
--- a/third_party/blink/renderer/modules/content_index/content_description_type_converter_test.cc
+++ b/third_party/blink/renderer/modules/content_index/content_description_type_converter_test.cc
@@ -26,7 +26,7 @@
   icon_definition->setSrc(url);
   description->setIcons({icon_definition});
 
-  description->setLaunchUrl(url);
+  description->setUrl(url);
   return description;
 }
 
@@ -40,7 +40,7 @@
   return cd1.id() == cd2.id() && cd1.title() == cd2.title() &&
          cd1.description() == cd2.description() &&
          cd1.category() == cd2.category() && cd1.icons() == cd2.icons() &&
-         cd1.launchUrl() == cd2.launchUrl();
+         cd1.url() == cd2.url();
 }
 
 TEST(ContentDescriptionConversionTest, RoundTrip) {
diff --git a/third_party/blink/renderer/modules/content_index/content_index.cc b/third_party/blink/renderer/modules/content_index/content_index.cc
index 7d77fb4..b4f5016 100644
--- a/third_party/blink/renderer/modules/content_index/content_index.cc
+++ b/third_party/blink/renderer/modules/content_index/content_index.cc
@@ -38,7 +38,7 @@
   if (description.description().IsEmpty())
     return "Description cannot be empty";
 
-  if (description.launchUrl().IsEmpty())
+  if (description.url().IsEmpty())
     return "Invalid launch URL provided";
 
   for (const auto& icon : description.icons()) {
@@ -51,7 +51,7 @@
   }
 
   KURL launch_url =
-      registration->GetExecutionContext()->CompleteURL(description.launchUrl());
+      registration->GetExecutionContext()->CompleteURL(description.url());
   auto* security_origin =
       registration->GetExecutionContext()->GetSecurityOrigin();
   if (!security_origin->CanRequest(launch_url))
diff --git a/third_party/blink/renderer/platform/exported/web_url_error.cc b/third_party/blink/renderer/platform/exported/web_url_error.cc
index c0672826..05f0252a 100644
--- a/third_party/blink/renderer/platform/exported/web_url_error.cc
+++ b/third_party/blink/renderer/platform/exported/web_url_error.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/public/platform/web_url_error.h"
 
 #include "net/base/net_errors.h"
+#include "services/network/public/mojom/trust_tokens.mojom-shared.h"
 
 namespace blink {
 
@@ -50,4 +51,15 @@
       url_(url),
       cors_error_status_(cors_error_status) {}
 
+WebURLError::WebURLError(
+    int reason,
+    network::mojom::TrustTokenOperationStatus trust_token_operation_error,
+    const WebURL& url)
+    : reason_(reason),
+      url_(url),
+      trust_token_operation_error_(trust_token_operation_error) {
+  DCHECK_NE(trust_token_operation_error,
+            network::mojom::TrustTokenOperationStatus::kOk);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc b/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc
index 7595c82..e912dbf 100644
--- a/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc
@@ -18,11 +18,15 @@
 
 BeginFrameProvider::BeginFrameProvider(
     const BeginFrameProviderParams& begin_frame_provider_params,
-    BeginFrameProviderClient* client)
+    BeginFrameProviderClient* client,
+    ContextLifecycleNotifier* context)
     : needs_begin_frame_(false),
       requested_needs_begin_frame_(false),
+      cfs_receiver_(this, context),
+      efs_receiver_(this, context),
       frame_sink_id_(begin_frame_provider_params.frame_sink_id),
       parent_frame_sink_id_(begin_frame_provider_params.parent_frame_sink_id),
+      compositor_frame_sink_(context),
       begin_frame_client_(client) {}
 
 void BeginFrameProvider::ResetCompositorFrameSink() {
@@ -74,9 +78,9 @@
       parent_frame_sink_id_, frame_sink_id_,
       efs_receiver_.BindNewPipeAndPassRemote(task_runner),
       cfs_receiver_.BindNewPipeAndPassRemote(task_runner),
-      compositor_frame_sink_.BindNewPipeAndPassReceiver());
+      compositor_frame_sink_.BindNewPipeAndPassReceiver(task_runner));
 
-  compositor_frame_sink_.set_disconnect_with_reason_handler(base::BindOnce(
+  compositor_frame_sink_.set_disconnect_with_reason_handler(WTF::Bind(
       &BeginFrameProvider::OnMojoConnectionError, WrapWeakPersistent(this)));
 }
 
@@ -121,6 +125,9 @@
 }
 
 void BeginFrameProvider::Trace(Visitor* visitor) {
+  visitor->Trace(cfs_receiver_);
+  visitor->Trace(efs_receiver_);
+  visitor->Trace(compositor_frame_sink_);
   visitor->Trace(begin_frame_client_);
 }
 
diff --git a/third_party/blink/renderer/platform/graphics/begin_frame_provider.h b/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
index 6672388..012d1a8e7 100644
--- a/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
+++ b/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
@@ -13,6 +13,8 @@
 #include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom-blink.h"
 #include "third_party/blink/public/mojom/frame_sinks/embedded_frame_sink.mojom-blink.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 
 namespace blink {
@@ -35,7 +37,8 @@
  public:
   explicit BeginFrameProvider(
       const BeginFrameProviderParams& begin_frame_provider_params,
-      BeginFrameProviderClient*);
+      BeginFrameProviderClient*,
+      ContextLifecycleNotifier*);
 
   void CreateCompositorFrameSinkIfNeeded();
 
@@ -77,12 +80,20 @@
   bool needs_begin_frame_;
   bool requested_needs_begin_frame_;
 
-  mojo::Receiver<viz::mojom::blink::CompositorFrameSinkClient> cfs_receiver_{
-      this};
-  mojo::Receiver<mojom::blink::EmbeddedFrameSinkClient> efs_receiver_{this};
+  HeapMojoReceiver<viz::mojom::blink::CompositorFrameSinkClient,
+                   BeginFrameProvider,
+                   HeapMojoWrapperMode::kWithoutContextObserver>
+      cfs_receiver_;
+
+  HeapMojoReceiver<mojom::blink::EmbeddedFrameSinkClient,
+                   BeginFrameProvider,
+                   HeapMojoWrapperMode::kWithoutContextObserver>
+      efs_receiver_;
   viz::FrameSinkId frame_sink_id_;
   viz::FrameSinkId parent_frame_sink_id_;
-  mojo::Remote<viz::mojom::blink::CompositorFrameSink> compositor_frame_sink_;
+  HeapMojoRemote<viz::mojom::blink::CompositorFrameSink,
+                 HeapMojoWrapperMode::kWithoutContextObserver>
+      compositor_frame_sink_;
   Member<BeginFrameProviderClient> begin_frame_client_;
 };
 
diff --git a/third_party/blink/renderer/platform/graphics/path.h b/third_party/blink/renderer/platform/graphics/path.h
index 79f98c7..f19aba2 100644
--- a/third_party/blink/renderer/platform/graphics/path.h
+++ b/third_party/blink/renderer/platform/graphics/path.h
@@ -82,6 +82,7 @@
   bool Contains(const FloatPoint&) const;
   bool Contains(const FloatPoint&, WindRule) const;
   bool StrokeContains(const FloatPoint&, const StrokeData&) const;
+  SkPath StrokePath(const StrokeData&) const;
 
   FloatRect BoundingRect() const;
   FloatRect StrokeBoundingRect(const StrokeData&) const;
@@ -192,7 +193,6 @@
                   float radius_y,
                   float start_angle,
                   float end_angle);
-  SkPath StrokePath(const StrokeData&) const;
 
   SkPath path_;
 };
diff --git a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc
index 9991d6a..cdc6ad92 100644
--- a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc
+++ b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc
@@ -72,4 +72,9 @@
   had_form_interaction_ = true;
 }
 
+void DocumentResourceCoordinator::OnFirstContentfulPaint(
+    base::TimeDelta time_since_navigation_start) {
+  service_->OnFirstContentfulPaint(time_since_navigation_start);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h
index 73797f7..a3b67ff 100644
--- a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h
+++ b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h
@@ -35,6 +35,7 @@
   void SetIsAdFrame();
   void OnNonPersistentNotificationCreated();
   void SetHadFormInteraction();
+  void OnFirstContentfulPaint(base::TimeDelta time_since_navigation_start);
 
  private:
   explicit DocumentResourceCoordinator(const BrowserInterfaceBrokerProxy&);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_error.cc b/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
index a670684..2ee5788 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
@@ -26,13 +26,16 @@
 
 #include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
 
+#include "base/strings/string_number_conversions.h"
 #include "net/base/net_errors.h"
+#include "services/network/public/mojom/trust_tokens.mojom-blink-forward.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/resource_request_blocked_reason.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/public/platform/web_url_error.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
+#include "third_party/blink/renderer/platform/loader/fetch/trust_token_params_conversion.h"
 
 namespace blink {
 
@@ -101,7 +104,8 @@
       is_access_check_(error.is_web_security_violation()),
       has_copy_in_cache_(error.has_copy_in_cache()),
       cors_error_status_(error.cors_error_status()),
-      blocked_by_response_reason_(error.blocked_by_response_reason()) {
+      blocked_by_response_reason_(error.blocked_by_response_reason()),
+      trust_token_operation_error_(error.trust_token_operation_error()) {
   DCHECK_NE(error_code_, 0);
   InitializeDescription();
 }
@@ -114,6 +118,7 @@
   error_copy.has_copy_in_cache_ = has_copy_in_cache_;
   error_copy.localized_description_ = localized_description_.IsolatedCopy();
   error_copy.is_access_check_ = is_access_check_;
+  error_copy.trust_token_operation_error_ = trust_token_operation_error_;
   return error_copy;
 }
 
@@ -127,6 +132,11 @@
     return WebURLError(*cors_error_status_, has_copy_in_cache, failing_url_);
   }
 
+  if (trust_token_operation_error_ !=
+      network::mojom::blink::TrustTokenOperationStatus::kOk) {
+    return WebURLError(error_code_, trust_token_operation_error_, failing_url_);
+  }
+
   return WebURLError(
       error_code_, extended_error_code_, resolve_error_info_, has_copy_in_cache,
       is_access_check_ ? WebURLError::IsWebSecurityViolation::kTrue
@@ -159,6 +169,9 @@
   if (a.resolve_error_info_ != b.resolve_error_info_)
     return false;
 
+  if (a.trust_token_operation_error_ != b.trust_token_operation_error_)
+    return false;
+
   return true;
 }
 
@@ -299,7 +312,10 @@
             << ", IsAccessCheck = " << error.IsAccessCheck()
             << ", IsTimeout = " << error.IsTimeout()
             << ", HasCopyInCache = " << error.HasCopyInCache()
-            << ", IsCacheMiss = " << error.IsCacheMiss();
+            << ", IsCacheMiss = " << error.IsCacheMiss()
+            << ", TrustTokenOperationError = "
+            << String::FromUTF8(base::NumberToString(
+                   static_cast<int32_t>(error.TrustTokenOperationError())));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_error.h b/third_party/blink/renderer/platform/loader/fetch/resource_error.h
index 7c1e833..71c3e58 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_error.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_error.h
@@ -32,6 +32,7 @@
 #include "net/dns/public/resolve_error_info.h"
 #include "services/network/public/cpp/blocked_by_response_reason.h"
 #include "services/network/public/cpp/cors/cors_error_status.h"
+#include "services/network/public/mojom/trust_tokens.mojom-blink.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -92,6 +93,11 @@
     return cors_error_status_;
   }
 
+  network::mojom::blink::TrustTokenOperationStatus TrustTokenOperationError()
+      const {
+    return trust_token_operation_error_;
+  }
+
   explicit operator WebURLError() const;
 
   static bool Compare(const ResourceError&, const ResourceError&);
@@ -110,6 +116,11 @@
   base::Optional<network::CorsErrorStatus> cors_error_status_;
 
   base::Optional<network::BlockedByResponseReason> blocked_by_response_reason_;
+
+  // Refer to the member comment in WebURLError.
+  network::mojom::blink::TrustTokenOperationStatus
+      trust_token_operation_error_ =
+          network::mojom::blink::TrustTokenOperationStatus::kOk;
 };
 
 inline bool operator==(const ResourceError& a, const ResourceError& b) {
diff --git a/third_party/blink/renderer/platform/mojo/blink_typemaps.gni b/third_party/blink/renderer/platform/mojo/blink_typemaps.gni
index 8af9005..d439274c 100644
--- a/third_party/blink/renderer/platform/mojo/blink_typemaps.gni
+++ b/third_party/blink/renderer/platform/mojo/blink_typemaps.gni
@@ -23,7 +23,4 @@
   "//third_party/blink/public/common/mediastream/media_stream.typemap",
   "//third_party/blink/public/common/screen_orientation/screen_orientation_lock_types.typemap",
   "//third_party/blink/public/mojom/bluetooth/bluetooth.typemap",
-  "//ui/gfx/geometry/mojom/geometry.typemap",
-  "//ui/gfx/mojom/color_space.typemap",
-  "//ui/gfx/mojom/transform.typemap",
 ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index ec60930..ad333f3 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -220,7 +220,6 @@
 crbug.com/974652 [ Debug ] virtual/gpu/fast/canvas/OffscreenCanvas-copyImage.html [ Pass Failure ]
 crbug.com/974652 [ Debug ] fast/canvas/OffscreenCanvas-copyImage.html [ Pass Failure ]
 
-crbug.com/1011060 virtual/gpu/fast/canvas/canvas-getImageData-smooth.html [ Pass Failure ]
 crbug.com/1011060 virtual/gpu/fast/canvas/bug382588.html [ Pass Failure ]
 crbug.com/1011060 virtual/gpu/fast/canvas/canvas-lost-gpu-context.html [ Pass Failure Crash ]
 
@@ -4864,7 +4863,6 @@
 # Canvas tests that are affected by change to Skia GPU rect shadow rendering.
 crbug.com/990918 virtual/gpu/fast/canvas/canvas-shadow-source-in.html [ Pass Failure ]
 crbug.com/990918 virtual/gpu/fast/canvas/canvas-composite-shadow.html [ Pass Failure ]
-crbug.com/990918 virtual/gpu/fast/canvas/canvas-shadow.html [ Pass Failure ]
 
 # Sheriff failures 2017-09-21
 crbug.com/767469 http/tests/navigation/start-load-during-provisional-loader-detach.html [ Pass Failure ]
@@ -4950,9 +4948,6 @@
 # Sheriff failures 2017-11-16
 crbug.com/785980 [ Win ] http/tests/devtools/network/network-xhr-same-url-as-main-resource.js [ Failure Pass ]
 
-# Sheriff failures 2017-11-29
-crbug.com/786641 virtual/gpu/fast/canvas/OffscreenCanvas-2d-imageSmoothing.html [ Pass Failure Timeout ]
-
 # Sheriff failures 2017-12-04
 crbug.com/667560 http/tests/devtools/elements/styles-4/inline-style-sourcemap.js [ Pass Failure ]
 
@@ -5205,7 +5200,6 @@
 # Sheriff 2018-04-11
 crbug.com/831796 fast/events/autoscroll-in-textfield.html [ Failure Pass ]
 crbug.com/831673 http/tests/devtools/reveal-objects.js [ Pass Timeout ]
-crbug.com/831496 virtual/gpu/fast/canvas/fillrect_gradient.html [ Pass Timeout ]
 crbug.com/829952 fast/webgl/texImage-imageBitmap-from-image-resize.html [ Pass Timeout ]
 
 crbug.com/832274 [ Linux ] fast/forms/search/search-appearance-basic.html [ Pass Failure ]
@@ -5495,7 +5489,6 @@
 crbug.com/922951 http/tests/cache/subresource-fragment-identifier.html [ Failure Pass Timeout Crash ]
 crbug.com/922951 http/tests/devtools/tracing/timeline-network-received-data.js [ Failure Pass Timeout Crash ]
 crbug.com/922951 http/tests/history/back-to-post.html [ Failure Pass Timeout Crash ]
-crbug.com/922951 http/tests/security/offscreencanvas-placeholder-read-blocked-no-crossorigin.html [ Failure Pass Timeout Crash ]
 crbug.com/922951 http/tests/security/cookies/basic.html [ Failure Pass Timeout Crash ]
 crbug.com/922951 http/tests/webaudio/autoplay-crossorigin.html [ Failure Pass Timeout Crash ]
 crbug.com/922951 media/controls/overflow-menu-hide-on-click-outside-stoppropagation.html [ Failure Pass Timeout Crash ]
@@ -5504,8 +5497,6 @@
 crbug.com/922951 virtual/audio-service/media/controls/overflow-menu-hide-on-click-outside-stoppropagation.html [ Failure Pass Timeout Crash ]
 crbug.com/922951 virtual/audio-service/media/controls/overflow-menu-hide-on-click-outside.html [ Failure Pass Timeout Crash ]
 crbug.com/922951 virtual/audio-service/media/controls/overflow-menu-toggle-class-for-animation.html [ Failure Pass Timeout Crash ]
-crbug.com/922951 virtual/gpu/fast/canvas/OffscreenCanvas-MessageChannel-transfer.html [ Failure Pass Timeout Crash ]
-crbug.com/922951 virtual/gpu/fast/canvas/color-space/canvas-drawImage-offscreenCanvas.html [ Failure Pass Timeout Crash ]
 crbug.com/922951 virtual/prefer_compositing_to_lcd_text/scrollbars/resize-scales-with-dpi-150.html [ Failure Pass Timeout Crash ]
 crbug.com/922951 virtual/scalefactor150/fast/events/synthetic-events/tap-on-scaled-screen.html [ Failure Pass Timeout Crash ]
 crbug.com/922951 virtual/threaded/http/tests/devtools/tracing/frame-model-instrumentation.js [ Failure Pass Timeout Crash ]
@@ -5793,9 +5784,6 @@
 crbug.com/971319 [ Mac ] media/audio-garbage-collect.html [ Pass Timeout ]
 crbug.com/971319 [ Mac ] virtual/audio-service/media/audio-garbage-collect.html [ Pass Timeout ]
 
-# Sheriff 2019-06-06
-crbug.com/971612 fast/canvas/OffscreenCanvas-MessageChannel-transfer.html [ Pass Failure ]
-
 # Sheriff 2019-06-13
 crbug.com/973692 [ Mac ] external/wpt/css/css-text/parsing/hyphens-computed.html [ Failure ]
 crbug.com/973726 [ Mac ] fast/css/large-list-of-rules-crash.html [ Pass Timeout ]
@@ -6045,8 +6033,6 @@
 crbug.com/1010170 [ Mac ] media/video-played-reset.html [ Failure ]
 
 # Sheriff 2019-10-02
-crbug.com/1010472 [ Linux Debug ] fast/canvas/color-space/canvas-drawImage-offscreenCanvas.html [ Timeout Pass ]
-crbug.com/1010472 [ Mac Debug ] fast/canvas/color-space/canvas-drawImage-offscreenCanvas.html [ Timeout Pass ]
 crbug.com/1010483 [ Win ] fast/parser/residual-style-dom.html [ Crash Pass ]
 crbug.com/1010483 [ Win ] fast/parser/residual-style-hang.html [ Crash Pass ]
 crbug.com/1010483 [ Win ] fast/selectors/specificity-overflow.html [ Crash Pass ]
@@ -6464,9 +6450,6 @@
 
 crbug.com/1049454 external/wpt/service-workers/service-worker/windowclient-navigate.https.html [ Pass Timeout ]
 
-# Sheriff 2020-02-10
-crbug.com/1050306 [ Fuchsia ] virtual/gpu/fast/canvas/canvas-filter-frameless-document.html [ Crash Pass Timeout ]
-
 # Swiftshader issue.
 crbug.com/1048149 external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-innerwidth.html [ Crash Timeout ]
 crbug.com/1048149 external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-screeny.html [ Crash Timeout ]
@@ -6644,8 +6627,6 @@
 crbug.com/1061043 fast/plugins/keypress-event.html [ Pass Failure ]
 crbug.com/1061097 http/tests/security/promise-access-control-allow.htm [ Pass Failure ]
 crbug.com/1061131 [ Mac ] virtual/threaded-prefer-compositing/fast/scrolling/middle-click-autoscroll-latching-clicked-node.html [ Pass Timeout ]
-crbug.com/1061131 [ Win ] fast/canvas/toBlob-in-detached-document.html [ Pass Crash ]
-crbug.com/1061131 [ Mac ] fast/canvas/toBlob-in-detached-document.html [ Pass Crash ]
 crbug.com/1061131 [ Mac ] editing/selection/replaced-boundaries-1.html [ Pass Failure ]
 
 crbug.com/1058888 [ Linux ] animations/animationworklet/peek-updated-composited-property-on-main.html [ Pass Failure ]
@@ -6660,6 +6641,11 @@
 crbug.com/1064127 virtual/threaded/external/wpt/web-animations/timing-model/animations/update-playback-rate-slow.html [ Pass Failure ]
 crbug.com/1064463 external/wpt/web-animations/interfaces/Animation/style-change-events.html [ Pass Failure ]
 
+# These tests will pass once the --enable-features=TrustTokens flag is on by
+# default. A virtual test suite runs the same tests with the flag enabled.
+crbug.com/1061765 http/tests/loading/trust-tokens/* [ Skip ]
+crbug.com/1061765 external/wpt/trust-tokens/end-to-end/* [ Skip ]
+
 # Sheriff 2020-03-26
 crbug.com/1064839 fast/hidpi/image-srcset-svg-canvas-2x.html [ Pass Failure ]
 # Sheriff 2020-03-27
@@ -6673,9 +6659,6 @@
 crbug.com/1066732 fast/events/platform-wheelevent-paging-x-in-scrolling-div.html [ Pass Failure ]
 crbug.com/1066732 fast/events/platform-wheelevent-paging-y-in-scrolling-div.html [ Pass Failure ]
 
-# These tests will pass once the --enable-features=TrustTokens flag is on by default.
-crbug.com/1061765 external/wpt/trust-tokens/end-to-end/* [ Skip ]
-
 # Test flakes
 crbug.com/1066716 http/tests/cache/zero-length-xhr.html [ Pass Timeout ]
 
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 505ab11..ea957f80 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -729,7 +729,7 @@
   },
   {
     "prefix": "trust-tokens",
-    "bases": [ "external/wpt/trust-tokens/end-to-end" ],
+    "bases": [ "external/wpt/trust-tokens/end-to-end", "http/tests/loading/trust-tokens" ],
     "args": [ "--enable-features=TrustTokens" ]
   }
 ]
diff --git a/third_party/blink/web_tests/css3/masking/clip-path-reference-mutated.html b/third_party/blink/web_tests/css3/masking/clip-path-reference-mutated.html
deleted file mode 100644
index fc4e61d..0000000
--- a/third_party/blink/web_tests/css3/masking/clip-path-reference-mutated.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<script src="../../resources/run-after-layout-and-paint.js"></script>
-<style>
-#target {
-  width: 100px;
-  height: 100px;
-  background-color: green;
-  clip-path: url(#clip);
-}
-</style>
-<div id="target"></div>
-<svg height="0" width="0">
-  <defs>
-    <clipPath id="clip" clipPathUnits="objectBoundingBox">
-      <circle cx="0.5" cy="0.5" r="0.25"></circle>
-    </clipPath>
-  </defs>
-</svg>
-<script>
-runAfterLayoutAndPaint(function() {
-  document.querySelector('circle').setAttribute('r', 1);
-}, true);
-</script>
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json
index f2aa665..fc943145 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json
@@ -61823,6 +61823,18 @@
      {}
     ]
    ],
+   "css/css-masking/clip-path/reference-nonexisting-existing-local.html": [
+    [
+     "css/css-masking/clip-path/reference-nonexisting-existing-local.html",
+     [
+      [
+       "/css/css-masking/clip-path/reference/reference-nonexisting-existing-local-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-masking/clip-rule/clip-rule-001.html": [
     [
      "css/css-masking/clip-rule/clip-rule-001.html",
@@ -108677,6 +108689,18 @@
      {}
     ]
    ],
+   "css/filter-effects/clip-under-filter-003.html": [
+    [
+     "css/filter-effects/clip-under-filter-003.html",
+     [
+      [
+       "/css/filter-effects/reference/clip-under-filter-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/filter-effects/css-backdrop-filters-animation-blur.html": [
     [
      "css/filter-effects/css-backdrop-filters-animation-blur.html",
@@ -150878,6 +150902,9 @@
    "css/css-masking/clip-path/reference/reference-local-url-with-base-001-ref.html": [
     []
    ],
+   "css/css-masking/clip-path/reference/reference-nonexisting-existing-local-ref.html": [
+    []
+   ],
    "css/css-masking/clip-path/svg-clipPath.svg": [
     []
    ],
@@ -160814,6 +160841,9 @@
    "css/filter-effects/reference/clip-under-filter-002-ref.html": [
     []
    ],
+   "css/filter-effects/reference/clip-under-filter-003-ref.html": [
+    []
+   ],
    "css/filter-effects/reference/drop-shadow-clipped-001-ref.html": [
     []
    ],
@@ -208721,23 +208751,6 @@
      {}
     ]
    ],
-   "appmanifest/idlharness.window.js": [
-    [
-     "appmanifest/idlharness.window.html",
-     {
-      "script_metadata": [
-       [
-        "script",
-        "/resources/WebIDLParser.js"
-       ],
-       [
-        "script",
-        "/resources/idlharness.js"
-       ]
-      ]
-     }
-    ]
-   ],
    "audio-output/idlharness.https.window.js": [
     [
      "audio-output/idlharness.https.window.html",
@@ -223981,6 +223994,18 @@
      {}
     ]
    ],
+   "css/css-grid/grid-definition/flex-and-minmax-content-resolution-columns-001.html": [
+    [
+     "css/css-grid/grid-definition/flex-and-minmax-content-resolution-columns-001.html",
+     {}
+    ]
+   ],
+   "css/css-grid/grid-definition/flex-and-minmax-content-resolution-rows-001.html": [
+    [
+     "css/css-grid/grid-definition/flex-and-minmax-content-resolution-rows-001.html",
+     {}
+    ]
+   ],
    "css/css-grid/grid-definition/grid-auto-repeat-max-size-001.html": [
     [
      "css/css-grid/grid-definition/grid-auto-repeat-max-size-001.html",
@@ -224311,6 +224336,12 @@
      {}
     ]
    ],
+   "css/css-grid/grid-model/compute-intrinsic-widths-scrollbar-001.html": [
+    [
+     "css/css-grid/grid-model/compute-intrinsic-widths-scrollbar-001.html",
+     {}
+    ]
+   ],
    "css/css-grid/grid-model/grid-box-sizing-001.html": [
     [
      "css/css-grid/grid-model/grid-box-sizing-001.html",
@@ -352759,10 +352790,6 @@
    "0b9c714df2a45545212397d7e391655f3e1091cf",
    "support"
   ],
-  "appmanifest/idlharness.window.js": [
-   "55e8b9871e794c944f329e0e9df6ec140124c660",
-   "testharness"
-  ],
   "audio-output/META.yml": [
    "b6a7d4d06259117af8fb843f6a8d252bac01a8f3",
    "support"
@@ -355944,7 +355971,7 @@
    "testharness"
   ],
   "content-security-policy/inheritance/iframe-all-local-schemes.sub.html": [
-   "cd38c902f05f7871fdec0eafe5481e5eba1928ae",
+   "20a9cbdc9e086163000baafb9c74d4e9d32b071a",
    "testharness"
   ],
   "content-security-policy/inheritance/iframe-srcdoc-inheritance.html": [
@@ -399055,6 +399082,14 @@
    "7fb5d8e117d9f0b7e23bf3921843e8ea29ef4522",
    "reftest"
   ],
+  "css/css-grid/grid-definition/flex-and-minmax-content-resolution-columns-001.html": [
+   "b92eb9f0dddc63ca5d241c35dca2e0c32d406d24",
+   "testharness"
+  ],
+  "css/css-grid/grid-definition/flex-and-minmax-content-resolution-rows-001.html": [
+   "ebaa2c08e4b6fff5042f4c0a4997a28f5cac293a",
+   "testharness"
+  ],
   "css/css-grid/grid-definition/fr-unit-with-percentage.html": [
    "82c97abdd5740d466f049d8b45b67e241f204899",
    "reftest"
@@ -399943,6 +399978,10 @@
    "a5376827eb91a2e4a92fe4738b1a319fcdc38ee8",
    "testharness"
   ],
+  "css/css-grid/grid-model/compute-intrinsic-widths-scrollbar-001.html": [
+   "d61f7ad14e6b911aca586a5a05713c9811db5a0c",
+   "testharness"
+  ],
   "css/css-grid/grid-model/display-grid.html": [
    "7c6b743327ebfa74a841add8c51a5ea7ffb73ec4",
    "reftest"
@@ -404271,6 +404310,10 @@
    "c65761bddfc095e0e85b4feaea4359516a8df5b1",
    "reftest"
   ],
+  "css/css-masking/clip-path/reference-nonexisting-existing-local.html": [
+   "d02e1439e64e79a65c185c703e4813e33225e679",
+   "reftest"
+  ],
   "css/css-masking/clip-path/reference/clip-path-circle-2-ref.html": [
    "7794d32b3f0e2415dbfda8ff12475b0e4f0b4117",
    "support"
@@ -404375,6 +404418,10 @@
    "f718ea6abfbab54333ba674ff0dcd320d8672bcd",
    "support"
   ],
+  "css/css-masking/clip-path/reference/reference-nonexisting-existing-local-ref.html": [
+   "f718ea6abfbab54333ba674ff0dcd320d8672bcd",
+   "support"
+  ],
   "css/css-masking/clip-path/svg-clipPath.svg": [
    "d31a1df42e0ed94c43c2f9d0999d7dbde9e83130",
    "support"
@@ -442835,6 +442882,10 @@
    "8b6a66d45232e9924fe079bfbeff88c1aa0b0f53",
    "reftest"
   ],
+  "css/filter-effects/clip-under-filter-003.html": [
+   "2cfda2a0d3be03edc4f75a7fd1e319e1cc1008b4",
+   "reftest"
+  ],
   "css/filter-effects/crashtests/multiple-references-id-crash-001.html": [
    "9ee04e1015d3c9fc04e8fab240a15d59ae92892d",
    "crashtest"
@@ -443479,6 +443530,10 @@
    "60c2c336346dbd236ba29104fdd7a20fa29e7264",
    "support"
   ],
+  "css/filter-effects/reference/clip-under-filter-003-ref.html": [
+   "e60456b3058be9055adbf45c4feffee4b40e9b56",
+   "support"
+  ],
   "css/filter-effects/reference/drop-shadow-clipped-001-ref.html": [
    "305b1d2233de6845713fd43f2cfc1f72b1afdb60",
    "support"
@@ -486624,7 +486679,7 @@
    "support"
   ],
   "interfaces/appmanifest.idl": [
-   "35c491a5f7bf0e714bec09112755c174d96663d4",
+   "2adc370012422f51514db9a2ee8768f532019736",
    "support"
   ],
   "interfaces/audio-output.idl": [
diff --git a/third_party/blink/web_tests/external/wpt/appmanifest/idlharness.window.js b/third_party/blink/web_tests/external/wpt/appmanifest/idlharness.window.js
deleted file mode 100644
index 55e8b98..0000000
--- a/third_party/blink/web_tests/external/wpt/appmanifest/idlharness.window.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// META: script=/resources/WebIDLParser.js
-// META: script=/resources/idlharness.js
-
-// https://w3c.github.io/manifest/
-
-'use strict';
-
-idl_test(
-  ['appmanifest'],
-  ['html', 'dom'],
-  idl_array => {
-    idl_array.add_objects({
-      Window: ['window'],
-      BeforeInstallPromptEvent: ['new BeforeInstallPromptEvent("type")'],
-    });
-  }
-);
diff --git a/third_party/blink/web_tests/external/wpt/content-index/content-index.https.window.js b/third_party/blink/web_tests/external/wpt/content-index/content-index.https.window.js
index 082ebc3b..5687070 100644
--- a/third_party/blink/web_tests/external/wpt/content-index/content-index.https.window.js
+++ b/third_party/blink/web_tests/external/wpt/content-index/content-index.https.window.js
@@ -22,8 +22,8 @@
   await expectTypeError(index.add(createDescription({iconUrl: '/non-existent-icon.png'})));
   await expectTypeError(index.add(createDescription({iconUrl: '/images/broken.png'})));
 
-  await expectTypeError(index.add(createDescription({launchUrl: 'https://other-domain.com/'})));
-  await expectTypeError(index.add(createDescription({launchUrl: '/different-scope'})));
+  await expectTypeError(index.add(createDescription({url: 'https://other-domain.com/'})));
+  await expectTypeError(index.add(createDescription({url: '/different-scope'})));
 
   await index.add(createDescription({}));
 
diff --git a/third_party/blink/web_tests/external/wpt/content-index/resources.js b/third_party/blink/web_tests/external/wpt/content-index/resources.js
index 1a758ab..51e9800 100644
--- a/third_party/blink/web_tests/external/wpt/content-index/resources.js
+++ b/third_party/blink/web_tests/external/wpt/content-index/resources.js
@@ -14,8 +14,8 @@
 
 function createDescription({id = 'id', title = 'title', description = 'description',
                             category = 'homepage', iconUrl = '/images/green-256x256.png',
-                            launchUrl = scope, includeIcons = true}) {
-  return {id, title, description, category, icons: includeIcons ? [{src: iconUrl}] : [], launchUrl};
+                            url = scope, includeIcons = true}) {
+  return {id, title, description, category, icons: includeIcons ? [{src: iconUrl}] : [], url};
 }
 
 // Creates a Promise test for |func| given the |description|. The |func| will be
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/empty-grid-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/empty-grid-001.html
new file mode 100644
index 0000000..10702c7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/abspos/empty-grid-001.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<title>CSS Grid: empty grid without explicit tracks.</title>
+<link rel="author" title="Sergio Villar" href="mailto:svillar@igalia.com"/>
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#abspos"/>
+<link rel="issue" href="https://crrev.com/562167"/>
+<meta name="assert" content="Test ensures that the grids with no in-flow items are actually empty."/>
+
+<link href="/css/support/grid.css" rel="stylesheet"/>
+<link href="/css/support/width-keyword-classes.css" rel="stylesheet"/>
+<link href="/fonts/ahem.css" rel="stylesheet" type="text/css"/>
+<style>
+.gridWithAbsolutePositionedItem {
+  /* Ensures that the grid container is the containing block of the absolutely positioned grid children. */
+  position: relative;
+}
+
+.grid {
+  grid-auto-columns: 200px;
+  grid-auto-rows: 200px;
+}
+
+.item {
+  position: absolute;
+  font: 10px/1 Ahem;
+}
+
+</style>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<script>
+function addRemoveItem()
+{
+  var gridItem = document.createElement("div");
+  gridItem.style.width = "100px";
+  gridItem.style.height = "100px";
+  gridItem.style.backgroundColor = "red";
+  var gridElement = document.getElementById("dynamicGrid");
+  gridElement.appendChild(gridItem);
+  gridElement.removeChild(gridItem);
+}
+
+setup({ explicit_done: true });
+
+function doTest() {
+  addRemoveItem();
+  checkLayout(".grid");
+}
+</script>
+
+<body onload="document.fonts.ready.then(() => { doTest(); })">
+
+<div class="grid min-content" data-expected-width="0" data-expected-height="0"></div>
+
+<div class="grid min-content gridWithAbsolutePositionedItem" data-expected-width="0" data-expected-height="0">
+  <div class="item" data-expected-width="40" data-expected-height="10">XXXX</div>
+</div>
+
+<div id="dynamicGrid" class="grid min-content" data-expected-width="0" data-expected-height="0"></div>
+
+<div class="grid min-content" style="grid-template-rows: 100px;" data-expected-width="0" data-expected-height="100"></div>
+<div class="grid min-content" style="grid-template-rows: auto;" data-expected-width="0" data-expected-height="0"></div>
+<div class="grid min-content" style="grid-template-rows: 1fr;" data-expected-width="0" data-expected-height="0"></div>
+
+<div class="grid min-content" style="grid-template-columns: 100px;" data-expected-width="100" data-expected-height="0"></div>
+<div class="grid min-content" style="grid-template-columns: auto;" data-expected-width="0" data-expected-height="0"></div>
+<div class="grid min-content" style="grid-template-columns: 1fr;" data-expected-width="0" data-expected-height="0"></div>
+
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/anonymous-grid-items-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/anonymous-grid-items-001.html
new file mode 100644
index 0000000..f5ddd5c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/anonymous-grid-items-001.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<title>CSS Grid: anonynous grid items.</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#grid-items">
+<link rel="match" href="reference/anonymous-grid-items-001-ref.html">
+<meta name="assert" content="This test ensures that anonymous grid items are supported."/>
+<body>
+  <div>The test passes if it has the same output than the reference.</div>
+  <div style="display: grid;">
+    anonymous item
+  </div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-script-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-script-001.html
new file mode 100644
index 0000000..323e9ba3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-script-001.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title>CSS Grid Layout Test: Insert script as grid item</title>
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#grid-item">
+<link rel="stylesheet" href="/css/support/grid.css"/>
+<link rel="match" href="../reference/grid-item-script-001-ref.html">
+<meta name="assert" content="This test ensures that inserting a script element as grid item doesn't crash.">
+<div class="grid">
+<script>
+  var grid = document.getElementsByClassName("grid")[0];
+  grid.offsetTop;
+  grid.innerHTML = "Test passes if it doesn't crash.";
+</script>
+</div>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/column-property-should-not-apply-on-grid-container-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/column-property-should-not-apply-on-grid-container-001.html
new file mode 100644
index 0000000..a795362
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/column-property-should-not-apply-on-grid-container-001.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<title>CSS Grid: column-* properties are ignored.</title>
+<link rel="author" title="Sunil Ratnu" href="mailto:sunil.ratnu@samsung.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#grid-model">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/1364">
+<link rel="match" href="reference/column-property-should-not-apply-on-grid-container-001-ref.html">
+<meta name="assert" content="This test ensures the column-* properties (in the Multicol module) have no effect on a grid container."/>
+<link href="/css/support/grid.css" rel="stylesheet"/>
+<style>
+.grid, .inline-grid
+{
+  width: 20em;
+  column-count: 2;
+  column-gap: 100px;
+  font-kerning: none;
+}
+</style>
+
+<body>
+
+<div class='grid'>
+AAAAAAAAAA BBBBBBBBBB CCCCCCCCCC DDDDDDDDDD
+</div>
+
+<div class='inline-grid'>
+AAAAAAAAAA BBBBBBBBBB CCCCCCCCCC DDDDDDDDDD
+</div>
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/compute-intrinsic-widths-scrollbar-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/compute-intrinsic-widths-scrollbar-001.html
new file mode 100644
index 0000000..d61f7ad1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/compute-intrinsic-widths-scrollbar-001.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>CSS Grid: width of grid container with scrollbar.</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#overflow">
+<meta name="assert" content="This test ensures that a grid container scrollbar is computed properly during intrinsic width calculation."/>
+
+<link href="/css/support/grid.css" rel="stylesheet"/>
+<link href="/css/support/width-keyword-classes.css" rel="stylesheet"/>
+<style>
+  .grid {
+    overflow-y: scroll;
+    grid-template-columns: repeat(4, 50px);
+  }
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<body onload="checkLayout('.grid')">
+  <div class="grid min-content" data-expected-client-width="200">
+    item
+  </div>
+  <div class="grid max-content" data-expected-client-width="200">
+    item
+  </div>
+</body>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/column-property-should-not-apply-on-grid-container-expected.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/reference/column-property-should-not-apply-on-grid-container-001-ref.html
similarity index 71%
rename from third_party/blink/web_tests/fast/css-grid-layout/column-property-should-not-apply-on-grid-container-expected.html
rename to third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/reference/column-property-should-not-apply-on-grid-container-001-ref.html
index c8c771f..154cf02 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/column-property-should-not-apply-on-grid-container-expected.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-model/reference/column-property-should-not-apply-on-grid-container-001-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
-<link href="resources/grid.css" rel="stylesheet">
+<link href="/css/support/grid.css" rel="stylesheet">
 <style>
 .grid, .inline-grid
 {
-    width: 20em;
-    font-kerning: none;
+  width: 20em;
+  font-kerning: none;
 }
 </style>
 
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/auto-margins-ignored-during-track-sizing.html b/third_party/blink/web_tests/external/wpt/css/css-grid/layout-algorithm/auto-margins-ignored-during-track-sizing-001.html
similarity index 64%
rename from third_party/blink/web_tests/fast/css-grid-layout/auto-margins-ignored-during-track-sizing.html
rename to third_party/blink/web_tests/external/wpt/css/css-grid/layout-algorithm/auto-margins-ignored-during-track-sizing-001.html
index 471d476..2a23b1b 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/auto-margins-ignored-during-track-sizing.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/layout-algorithm/auto-margins-ignored-during-track-sizing-001.html
@@ -1,5 +1,10 @@
 <!DOCTYPE html>
-<link rel="match" href="auto-margins-ignored-during-track-sizing-expected.html">
+<title>CSS Grid: grid items using 'auto' margins.</title>
+<link rel="author" title="Javier Fernendez" href="mailto:jfernandez@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-grid/#auto-margins">
+<link rel="help" href="https://drafts.csswg.org/css-grid/#layout-algorithm">
+<link rel="match" href="references/auto-margins-ignored-during-track-sizing-001-ref.html">
+<meta name="assert" content="This test ensures that 'auto' margin is treated as 0px during the tracks sizing algorithm."/>
 <style>
 body { overflow: hidden; }
 .grid {
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/auto-margins-ignored-during-track-sizing-expected.html b/third_party/blink/web_tests/external/wpt/css/css-grid/layout-algorithm/references/auto-margins-ignored-during-track-sizing-001-ref.html
similarity index 100%
rename from third_party/blink/web_tests/fast/css-grid-layout/auto-margins-ignored-during-track-sizing-expected.html
rename to third_party/blink/web_tests/external/wpt/css/css-grid/layout-algorithm/references/auto-margins-ignored-during-track-sizing-001-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/reference/anonymous-grid-items-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/reference/anonymous-grid-items-001-ref.html
new file mode 100644
index 0000000..20302c2f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/reference/anonymous-grid-items-001-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<body>
+  <div>The test passes if it has the same output than the reference.</div>
+  <div>
+    <div>anonymous item</div>
+  </div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/reference/grid-item-script-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/reference/grid-item-script-001-ref.html
new file mode 100644
index 0000000..2574678
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/reference/grid-item-script-001-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<div style="background: grey;">Test passes if it doesn't crash.</div>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference-mutated.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference-mutated.html
new file mode 100644
index 0000000..09642853
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference-mutated.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>CSS Masking: SVG clipPath dynamically updated.</title>
+<link rel="help" href="https://drafts.fxtf.org/css-masking-1/#the-clip-path">
+<link rel="match" href="reference/reference-mutated-ref.html">
+<meta name="assert" content="Test ensures that SVG clipPath updates properly when dynamically changed."/>
+
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+
+<style>
+#target {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+  clip-path: url(#clip);
+}
+</style>
+<div id="target"></div>
+<svg height="0" width="0">
+  <defs>
+    <clipPath id="clip" clipPathUnits="objectBoundingBox">
+      <circle cx="0.5" cy="0.5" r="0.25"></circle>
+    </clipPath>
+  </defs>
+</svg>
+<script>
+waitForAtLeastOneFrame().then(function() {
+  document.querySelector('circle').setAttribute('r', 1);
+  takeScreenshot();
+});
+</script>
diff --git a/third_party/blink/web_tests/css3/masking/clip-path-reference-mutated-expected.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference/reference-mutated-ref.html
similarity index 100%
rename from third_party/blink/web_tests/css3/masking/clip-path-reference-mutated-expected.html
rename to third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference/reference-mutated-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/appmanifest.idl b/third_party/blink/web_tests/external/wpt/interfaces/appmanifest.idl
index 35c491a..2adc370 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/appmanifest.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/appmanifest.idl
@@ -3,26 +3,6 @@
 // (https://github.com/tidoust/reffy-reports)
 // Source: Web App Manifest (https://w3c.github.io/manifest/)
 
-[Exposed=Window]
-interface BeforeInstallPromptEvent : Event {
-  constructor(DOMString type, optional EventInit eventInitDict = {});
-  Promise<PromptResponseObject> prompt();
-};
-
-dictionary PromptResponseObject {
-  AppBannerPromptOutcome userChoice;
-};
-
-enum AppBannerPromptOutcome {
-  "accepted",
-  "dismissed"
-};
-
-partial interface Window {
-  attribute EventHandler onappinstalled;
-  attribute EventHandler onbeforeinstallprompt;
-};
-
 dictionary WebAppManifest {
    TextDirectionType dir = "auto";
    DOMString lang;
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/anonymous-grid-items-expected.html b/third_party/blink/web_tests/fast/css-grid-layout/anonymous-grid-items-expected.html
deleted file mode 100644
index d73553b..0000000
--- a/third_party/blink/web_tests/fast/css-grid-layout/anonymous-grid-items-expected.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-    <div>Checks that anonymous grid items are supported. This should not crash.</div>
-    <div style="display: grid;">
-        <div>anonymous item</div>
-    </div>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/anonymous-grid-items.html b/third_party/blink/web_tests/fast/css-grid-layout/anonymous-grid-items.html
deleted file mode 100644
index 0b5ca902..0000000
--- a/third_party/blink/web_tests/fast/css-grid-layout/anonymous-grid-items.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-    <div>Checks that anonymous grid items are supported. This should not crash.</div>
-    <div style="display: grid;">
-        anonymous item
-    </div>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/column-property-should-not-apply-on-grid-container.html b/third_party/blink/web_tests/fast/css-grid-layout/column-property-should-not-apply-on-grid-container.html
deleted file mode 100644
index 5edad01..0000000
--- a/third_party/blink/web_tests/fast/css-grid-layout/column-property-should-not-apply-on-grid-container.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<html>
-<link href="resources/grid.css" rel="stylesheet">
-<style>
-.grid, .inline-grid
-{
-    width: 20em;
-    -webkit-column-count: 2; /* Chrome, Safari, Opera */
-    -moz-column-count: 2; /* Firefox */
-    column-count: 2;
-
-    -webkit-column-gap: 100px; /* Chrome, Safari, Opera */
-    -moz-column-gap: 100px; /* Firefox */
-    column-gap: 100px;
-}
-</style>
-
-<body>
-
-<div class='grid'>
-AAAAAAAAAA BBBBBBBBBB CCCCCCCCCC DDDDDDDDDD
-</div>
-
-<div class='inline-grid'>
-AAAAAAAAAA BBBBBBBBBB CCCCCCCCCC DDDDDDDDDD
-</div>
-
-</body>
-</html>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/compute-intrinsic-widths-scrollbar-expected.txt b/third_party/blink/web_tests/fast/css-grid-layout/compute-intrinsic-widths-scrollbar-expected.txt
deleted file mode 100644
index 3f5cabd..0000000
--- a/third_party/blink/web_tests/fast/css-grid-layout/compute-intrinsic-widths-scrollbar-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This test checks that grid container scrollbar is computed properly during intrinsic width calculation.
-
-item
-PASS
-item
-PASS
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/compute-intrinsic-widths-scrollbar.html b/third_party/blink/web_tests/fast/css-grid-layout/compute-intrinsic-widths-scrollbar.html
deleted file mode 100644
index 758a962..0000000
--- a/third_party/blink/web_tests/fast/css-grid-layout/compute-intrinsic-widths-scrollbar.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<link href="resources/grid.css" rel="stylesheet">
-<link href="../css-intrinsic-dimensions/resources/width-keyword-classes.css" rel=stylesheet>
-<style>
-    .grid {
-        overflow-y: scroll;
-        grid-template-columns: repeat(4, 50px);
-    }
-</style>
-<script src="../../resources/check-layout.js"></script>
-<p>This test checks that grid container scrollbar is computed properly during intrinsic width calculation.</p>
-<body onload="checkLayout('.grid')">
-    <div class="grid min-content" data-expected-client-width="200">
-        item
-    </div>
-    <div class="grid max-content" data-expected-client-width="200">
-        item
-    </div>
-</body>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/empty-grid-expected.txt b/third_party/blink/web_tests/fast/css-grid-layout/empty-grid-expected.txt
deleted file mode 100644
index 80edb6e..0000000
--- a/third_party/blink/web_tests/fast/css-grid-layout/empty-grid-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-This test checks that grids with no in-flow items are actually empty.
-
-PASS
-XXXX
-PASS
-PASS
-PASS
-PASS
-PASS
-PASS
-PASS
-PASS
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/empty-grid.html b/third_party/blink/web_tests/fast/css-grid-layout/empty-grid.html
deleted file mode 100644
index 29ddf19..0000000
--- a/third_party/blink/web_tests/fast/css-grid-layout/empty-grid.html
+++ /dev/null
@@ -1,61 +0,0 @@
-<!DOCTYPE html>
-<link href="resources/grid.css" rel="stylesheet">
-<link href="../css-intrinsic-dimensions/resources/width-keyword-classes.css" rel="stylesheet">
-<style>
-.gridWithAbsolutePositionedItem {
-    /* Ensures that the grid container is the containing block of the absolutely positioned grid children. */
-    position: relative;
-}
-
-.grid {
-    grid-auto-columns: 200px;
-    grid-auto-rows: 200px;
-}
-
-.item {
-    position: absolute;
-    font: 10px/1 Ahem;
-}
-
-</style>
-
-<script>
-function addRemoveItem()
-{
-    var gridItem = document.createElement("div");
-    gridItem.style.width = "100px";
-    gridItem.style.height = "100px";
-    gridItem.style.backgroundColor = "red";
-    var gridElement = document.getElementById("dynamicGrid");
-    gridElement.appendChild(gridItem);
-    gridElement.removeChild(gridItem);
-}
-
-function doTest() {
-     addRemoveItem();
-     checkLayout(".grid");
-}
-</script>
-<script src="../../resources/check-layout.js"></script>
-
-<body onload="doTest()">
-
-<p>This test checks that grids with no in-flow items are actually empty.</p>
-
-<div class="grid min-content" data-expected-width="0" data-expected-height="0"></div>
-
-<div class="grid min-content gridWithAbsolutePositionedItem" data-expected-width="0" data-expected-height="0">
-    <div class="item" data-expected-width="40" data-expected-height="10">XXXX</div>
-</div>
-
-<div id="dynamicGrid" class="grid min-content" data-expected-width="0" data-expected-height="0"></div>
-
-<div class="grid min-content" style="grid-template-rows: 100px;" data-expected-width="0" data-expected-height="100"></div>
-<div class="grid min-content" style="grid-template-rows: auto;" data-expected-width="0" data-expected-height="0"></div>
-<div class="grid min-content" style="grid-template-rows: 1fr;" data-expected-width="0" data-expected-height="0"></div>
-
-<div class="grid min-content" style="grid-template-columns: 100px;" data-expected-width="100" data-expected-height="0"></div>
-<div class="grid min-content" style="grid-template-columns: auto;" data-expected-width="0" data-expected-height="0"></div>
-<div class="grid min-content" style="grid-template-columns: 1fr;" data-expected-width="0" data-expected-height="0"></div>
-
-</body>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-element-bad-cast-addchild-expected.txt b/third_party/blink/web_tests/fast/css-grid-layout/grid-element-bad-cast-addchild-expected.txt
deleted file mode 100644
index 4e5d528..0000000
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-element-bad-cast-addchild-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This test checks that inserting a non-LayoutBox grid item doesn't make us crash.
-
-This test has PASSED if it didn't crash and you see PASSED below.
-
-PASSED
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-element-bad-cast-addchild.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-element-bad-cast-addchild.html
deleted file mode 100644
index dc002e82..0000000
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-element-bad-cast-addchild.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<link href="resources/grid.css" rel="stylesheet">
-<p>This test checks that inserting a non-LayoutBox grid item doesn't make us crash.</p>
-<p>This test has PASSED if it didn't crash and you see PASSED below.</p>
-<div class="grid">
-<script>
-    if (window.testRunner)
-        testRunner.dumpAsText();
-
-    var grid = document.getElementsByClassName("grid")[0];
-    grid.offsetTop;
-    grid.innerHTML = "PASSED";
-</script>
diff --git a/third_party/blink/web_tests/http/tests/content_index/content-index.html b/third_party/blink/web_tests/http/tests/content_index/content-index.html
index 8fcd42f..c861c02 100644
--- a/third_party/blink/web_tests/http/tests/content_index/content-index.html
+++ b/third_party/blink/web_tests/http/tests/content_index/content-index.html
@@ -35,10 +35,10 @@
       'Icon could not be loaded');
 
   await expectTypeErrorWithMessage(
-      index.add(createDescription({launchUrl: 'https://other-domain.com/'})),
+      index.add(createDescription({url: 'https://other-domain.com/'})),
       `Failed to execute 'add' on 'ContentIndex': Service Worker cannot request provided launch URL`);
   await expectTypeErrorWithMessage(
-      index.add(createDescription({launchUrl: '/different-scope'})),
+      index.add(createDescription({url: '/different-scope'})),
       `Failed to execute 'add' on 'ContentIndex': Launch URL must belong to the Service Worker's scope`);
 
   await index.add(createDescription({}));
diff --git a/third_party/blink/web_tests/http/tests/content_index/resources.js b/third_party/blink/web_tests/http/tests/content_index/resources.js
index 0c08092..0494ec4e 100644
--- a/third_party/blink/web_tests/http/tests/content_index/resources.js
+++ b/third_party/blink/web_tests/http/tests/content_index/resources.js
@@ -21,8 +21,8 @@
 
 function createDescription({id = 'id', title = 'title', description = 'description',
                             category = 'homepage', iconUrl = '/resources/square.png',
-                            launchUrl = scope, includeIcons = true}) {
-  return {id, title, description, category, icons: includeIcons ? [{src: iconUrl}] : [], launchUrl};
+                            url = scope, includeIcons = true}) {
+  return {id, title, description, category, icons: includeIcons ? [{src: iconUrl}] : [], url};
 }
 
 // Creates a Promise test for |func| given the |description|. The |func| will be
diff --git a/third_party/blink/web_tests/http/tests/content_index/resources/sw.js b/third_party/blink/web_tests/http/tests/content_index/resources/sw.js
index 23372d0..a647a2e 100644
--- a/third_party/blink/web_tests/http/tests/content_index/resources/sw.js
+++ b/third_party/blink/web_tests/http/tests/content_index/resources/sw.js
@@ -17,7 +17,7 @@
       icons: [{
         src: '/resources/square.png',
       }],
-      launchUrl: 'resources/',
+      url: 'resources/',
     });
     await postMessageToWindow('Successfully registered');
   } catch (e) {
diff --git a/third_party/blink/web_tests/http/tests/loading/trust-tokens/trust-token-fetch.tentative.https.html b/third_party/blink/web_tests/http/tests/loading/trust-tokens/trust-token-fetch.tentative.https.html
new file mode 100644
index 0000000..aa30715
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/loading/trust-tokens/trust-token-fetch.tentative.https.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Tests the prototype Trust Token API's functionality through its Fetch interface.</title>
+<link rel="help" href="https://github.com/WICG/trust-token-api#trust-token-redemption" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+  'use strict';
+
+  promise_test((t) => promise_rejects_dom(t, 'OperationError',
+    fetch('https://trusttoken.test', {
+      trustToken: {
+        type: 'token-request'
+      }
+    }), 'Trust Token issuance should error.'), 'Trust Token issuance is not implemented');
+
+  promise_test((t) => promise_rejects_dom(t, 'OperationError',
+    fetch('https://trusttoken.test', {
+      trustToken: {
+        type: 'srr-token-redemption'
+      }
+    }), 'Trust Token redemption should error.'), 'Trust Token redemption is not implemented');
+
+  promise_test((t) => promise_rejects_dom(t, 'OperationError',
+    fetch('https://destination.test', {
+      trustToken: {
+        type: 'send-srr',
+        issuer: 'https://issuer.test'
+      }
+    }), 'Trust Token signing should error.'), 'Trust Token signing is not implemented');
+</script>
diff --git a/third_party/blink/web_tests/http/tests/loading/trust-tokens/trust-token-xhr.tentative.https.html b/third_party/blink/web_tests/http/tests/loading/trust-tokens/trust-token-xhr.tentative.https.html
new file mode 100644
index 0000000..90ad1ef
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/loading/trust-tokens/trust-token-xhr.tentative.https.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Tests the prototype Trust Token API's functionality through its XHR interface.</title>
+<link rel="help" href="https://github.com/WICG/trust-token-api#trust-token-redemption" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+  'use strict';
+
+  async_test((t) => {
+    let request = new XMLHttpRequest();
+    request.open('GET', 'https://trusttoken.test');
+    request.setTrustToken({
+      type: 'token-request'
+    });
+    request.onerror = t.step_func_done(() => {
+      assert_equals(request.trustTokenOperationError.name, "OperationError");
+    });
+    request.send();
+  }, 'Trust Token issuance is not implemented');
+
+  async_test((t) => {
+    let request = new XMLHttpRequest();
+    request.open('GET', 'https://trusttoken.test');
+    request.setTrustToken({
+      type: 'srr-token-redemption'
+    });
+    request.onerror = t.step_func_done(() => {
+      assert_equals(request.trustTokenOperationError.name, "OperationError");
+    });
+    request.send();
+  }, 'Trust Token redemption is not implemented');
+
+  async_test((t) => {
+    let request = new XMLHttpRequest();
+    request.open('GET', 'https://destination.test');
+    request.setTrustToken({
+      type: 'send-srr',
+      issuer: 'https://issuer.test'
+    });
+    request.onerror = t.step_func_done(() => {
+      assert_equals(request.trustTokenOperationError.name, "OperationError");
+    });
+    request.send();
+  }, 'Trust Token signing is not implemented');
+</script>
diff --git a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/report-only-report-uri-missing-expected.txt b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/report-only-report-uri-missing-expected.txt
deleted file mode 100644
index 185541ce..0000000
--- a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/report-only-report-uri-missing-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-CONSOLE ERROR: The Content Security Policy 'script-src 'unsafe-inline';' was delivered in report-only mode, but does not specify a 'report-uri'; the policy will have no effect. Please either add a 'report-uri' directive, or deliver the policy via the 'Content-Security-Policy' header.
-This test passes if a console message is present, warning about the missing 'report-uri' directive.
diff --git a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/report-only-report-uri-missing.php b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/report-only-report-uri-missing.php
deleted file mode 100644
index d4b5e21..0000000
--- a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/report-only-report-uri-missing.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-header("Content-Security-Policy-Report-Only: script-src 'unsafe-inline';");
-?>
-<!DOCTYPE html>
-<html>
-<head>
-    <script>
-        if (window.testRunner) {
-          testRunner.dumpAsText();
-          testRunner.dumpPingLoaderCallbacks();
-        }
-        if (window.internals)
-          internals.settings.setExperimentalContentSecurityPolicyFeaturesEnabled(false);
-    </script>
-</head>
-<body>
-    <p>This test passes if a console message is present, warning about the missing 'report-uri' directive.</p>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/sandbox-report-only-expected.txt b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/sandbox-report-only-expected.txt
index 5769220..a6b7503 100644
--- a/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/sandbox-report-only-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/contentSecurityPolicy/sandbox-report-only-expected.txt
@@ -1,5 +1,4 @@
 CONSOLE ERROR: The Content Security Policy directive 'sandbox' is ignored when delivered in a report-only policy.
-CONSOLE ERROR: The Content Security Policy 'sandbox' was delivered in report-only mode, but does not specify a 'report-uri'; the policy will have no effect. Please either add a 'report-uri' directive, or deliver the policy via the 'Content-Security-Policy' header.
 CONSOLE MESSAGE: line 4: Script executed in iframe.
 ALERT: PASS: Iframe was not in a unique origin
 
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/select/menulist-type-ahead-find-original-item-expected.txt b/third_party/blink/web_tests/platform/mac/fast/forms/select/menulist-type-ahead-find-original-item-expected.txt
new file mode 100644
index 0000000..ed5b82f7
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/select/menulist-type-ahead-find-original-item-expected.txt
@@ -0,0 +1,10 @@
+Verify type ahead selection fires onchange event.
+Set focus to select element
+Type down arrow twice and type "a"
+You see "apple" in select element and "PASS" below select element.
+apple
+banana
+cherry
+
+
+FAIL
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/select/optgroup-clicking-expected.txt b/third_party/blink/web_tests/platform/mac/fast/forms/select/optgroup-clicking-expected.txt
new file mode 100644
index 0000000..a5b72aa
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/select/optgroup-clicking-expected.txt
@@ -0,0 +1,42 @@
+Test clicking with optgroup element
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Click enabled option
+PASS $("listbox").selectedIndex is 1
+
+Click on optgroup, should not deselect selectedIndex
+PASS $("listbox").selectedIndex is 1
+
+Click disabled option - doesn't change selectedIndex
+PASS $("listbox").selectedIndex is 1
+
+Menu list with arrow key. The test is expected to fail on OSX because of a key binding difference.
+FAIL $("menulist").selectedIndex should be 8. Was 3.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
+One
+Two
+Three
+Four
+One
+Two
+Three
+Four
+
+
+One
+Two
+Three
+Four
+One
+Two
+Three
+Four
+One
+Two
+Three
+Four
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/select/select-popup-pagekeys-expected.txt b/third_party/blink/web_tests/platform/mac/fast/forms/select/select-popup-pagekeys-expected.txt
new file mode 100644
index 0000000..4a05f8f
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/fast/forms/select/select-popup-pagekeys-expected.txt
@@ -0,0 +1,72 @@
+This test verifies that the Home/End/PageUp/PageDown keys work correctly for pop-up <select> elements that have focus but are not currently popped-up.
+
+Output below is a series of PASS or FAIL lines showing expected and actual selection indexes, followed by a single PASS or FAIL for the status of the entire test.
+
+NOTE: This test will fail on Mac OS, on which these keys are NOT supposed to change the selection of a focused pop-up.
+
+0
+1
+2
+3
+4
+5
+6
+ 
+0
+1
+2
+3
+4
+5
+6
+7
+FAIL: selectedIndex should be 3 (is 0) after a PageDown from index 0
+FAIL: selectedIndex should be 4 (is 1) after a PageDown from index 1
+FAIL: selectedIndex should be 5 (is 2) after a PageDown from index 2
+FAIL: selectedIndex should be 6 (is 3) after a PageDown from index 3
+FAIL: selectedIndex should be 6 (is 4) after a PageDown from index 4
+FAIL: selectedIndex should be 6 (is 5) after a PageDown from index 5
+FAIL: selectedIndex should be 3 (is 6) after a PageUp from index 6
+FAIL: selectedIndex should be 2 (is 5) after a PageUp from index 5
+FAIL: selectedIndex should be 1 (is 4) after a PageUp from index 4
+FAIL: selectedIndex should be 0 (is 3) after a PageUp from index 3
+FAIL: selectedIndex should be 0 (is 2) after a PageUp from index 2
+FAIL: selectedIndex should be 0 (is 1) after a PageUp from index 1
+FAIL: selectedIndex should be 0 (is 6) after a Home from index 6
+FAIL: selectedIndex should be 0 (is 5) after a Home from index 5
+FAIL: selectedIndex should be 0 (is 4) after a Home from index 4
+FAIL: selectedIndex should be 0 (is 3) after a Home from index 3
+FAIL: selectedIndex should be 0 (is 2) after a Home from index 2
+FAIL: selectedIndex should be 0 (is 1) after a Home from index 1
+FAIL: selectedIndex should be 6 (is 5) after a End from index 5
+FAIL: selectedIndex should be 6 (is 4) after a End from index 4
+FAIL: selectedIndex should be 6 (is 3) after a End from index 3
+FAIL: selectedIndex should be 6 (is 2) after a End from index 2
+FAIL: selectedIndex should be 6 (is 1) after a End from index 1
+FAIL: selectedIndex should be 6 (is 0) after a End from index 0
+FAIL: selectedIndex should be 4 (is 1) after a PageDown from index 1
+FAIL: selectedIndex should be 5 (is 2) after a PageDown from index 2
+FAIL: selectedIndex should be 6 (is 4) after a PageDown from index 4
+FAIL: selectedIndex should be 6 (is 5) after a PageDown from index 5
+FAIL: selectedIndex should be 2 (is 6) after a PageUp from index 6
+FAIL: selectedIndex should be 2 (is 5) after a PageUp from index 5
+FAIL: selectedIndex should be 1 (is 4) after a PageUp from index 4
+FAIL: selectedIndex should be 1 (is 2) after a PageUp from index 2
+FAIL: selectedIndex should be 1 (is 7) after a Home from index 7
+FAIL: selectedIndex should be 1 (is 6) after a Home from index 6
+FAIL: selectedIndex should be 1 (is 5) after a Home from index 5
+FAIL: selectedIndex should be 1 (is 4) after a Home from index 4
+FAIL: selectedIndex should be 1 (is 3) after a Home from index 3
+FAIL: selectedIndex should be 1 (is 2) after a Home from index 2
+FAIL: selectedIndex should be 1 (is 0) after a Home from index 0
+FAIL: selectedIndex should be 6 (is 7) after a End from index 7
+FAIL: selectedIndex should be 6 (is 5) after a End from index 5
+FAIL: selectedIndex should be 6 (is 4) after a End from index 4
+FAIL: selectedIndex should be 6 (is 3) after a End from index 3
+FAIL: selectedIndex should be 6 (is 2) after a End from index 2
+FAIL: selectedIndex should be 6 (is 1) after a End from index 1
+FAIL: selectedIndex should be 6 (is 0) after a End from index 0
+
+FAIL: SOME TESTS FAILED (SEE ABOVE)
+
+
diff --git a/third_party/blink/web_tests/virtual/trust-tokens/README.md b/third_party/blink/web_tests/virtual/trust-tokens/README.md
new file mode 100644
index 0000000..34cbc884
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/trust-tokens/README.md
@@ -0,0 +1,5 @@
+The prototype Trust Tokens (https://github.com/wicg/trust-token-api)
+implementation is going behind an embedder-side flag
+(--enable-features=TrustTokens) necessary in addition to the Blink
+RuntimeEnabledFeature. This virtual suite allows running the pertinent tests
+with the flag on. It can be removed once the flag is enabled by default.
diff --git a/third_party/blink/web_tests/virtual/trust-tokens/http/tests/loading/trust-tokens/README.txt b/third_party/blink/web_tests/virtual/trust-tokens/http/tests/loading/trust-tokens/README.txt
new file mode 100644
index 0000000..c981686
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/trust-tokens/http/tests/loading/trust-tokens/README.txt
@@ -0,0 +1,3 @@
+Enable the network service side of the Trust Token API
+(https://github.com/wicg/trust-token-api) with --enable-features=TrustTokens in
+order to test API calls end to end.
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index a387011..86cca4c 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -3884,6 +3884,7 @@
 [Worker]     getter status
 [Worker]     getter statusText
 [Worker]     getter timeout
+[Worker]     getter trustTokenOperationError
 [Worker]     getter upload
 [Worker]     getter withCredentials
 [Worker]     method abort
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index 60a024e0..ba924cf 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -11180,6 +11180,7 @@
     getter status
     getter statusText
     getter timeout
+    getter trustTokenOperationError
     getter upload
     getter withCredentials
     method abort
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
index 99902c4..1d85c1f 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -3697,6 +3697,7 @@
 [Worker]     getter status
 [Worker]     getter statusText
 [Worker]     getter timeout
+[Worker]     getter trustTokenOperationError
 [Worker]     getter upload
 [Worker]     getter withCredentials
 [Worker]     method abort
diff --git a/third_party/custom_tabs_client/BUILD.gn b/third_party/custom_tabs_client/BUILD.gn
deleted file mode 100644
index a9dc309..0000000
--- a/third_party/custom_tabs_client/BUILD.gn
+++ /dev/null
@@ -1,157 +0,0 @@
-# Copyright 2015 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/rules.gni")
-
-android_resources("chrome_tabs_client_example_apk_resources") {
-  sources = [
-    "src/Application/src/main/res/anim/slide_in_left.xml",
-    "src/Application/src/main/res/anim/slide_in_right.xml",
-    "src/Application/src/main/res/anim/slide_out_left.xml",
-    "src/Application/src/main/res/anim/slide_out_right.xml",
-    "src/Application/src/main/res/drawable-hdpi/ic_arrow_back.png",
-    "src/Application/src/main/res/drawable-hdpi/ic_launcher.png",
-    "src/Application/src/main/res/drawable-hdpi/ic_notification_icon.png",
-    "src/Application/src/main/res/drawable-hdpi/ic_play.png",
-    "src/Application/src/main/res/drawable-hdpi/ic_share.png",
-    "src/Application/src/main/res/drawable-hdpi/ic_stop.png",
-    "src/Application/src/main/res/drawable-mdpi/ic_arrow_back.png",
-    "src/Application/src/main/res/drawable-mdpi/ic_launcher.png",
-    "src/Application/src/main/res/drawable-mdpi/ic_notification_icon.png",
-    "src/Application/src/main/res/drawable-mdpi/ic_play.png",
-    "src/Application/src/main/res/drawable-mdpi/ic_share.png",
-    "src/Application/src/main/res/drawable-mdpi/ic_stop.png",
-    "src/Application/src/main/res/drawable-xhdpi/ic_arrow_back.png",
-    "src/Application/src/main/res/drawable-xhdpi/ic_launcher.png",
-    "src/Application/src/main/res/drawable-xhdpi/ic_notification_icon.png",
-    "src/Application/src/main/res/drawable-xhdpi/ic_play.png",
-    "src/Application/src/main/res/drawable-xhdpi/ic_share.png",
-    "src/Application/src/main/res/drawable-xhdpi/ic_stop.png",
-    "src/Application/src/main/res/drawable-xxhdpi/cover.jpg",
-    "src/Application/src/main/res/drawable-xxhdpi/ic_arrow_back.png",
-    "src/Application/src/main/res/drawable-xxhdpi/ic_launcher.png",
-    "src/Application/src/main/res/drawable-xxhdpi/ic_notification_icon.png",
-    "src/Application/src/main/res/drawable-xxhdpi/ic_play.png",
-    "src/Application/src/main/res/drawable-xxhdpi/ic_share.png",
-    "src/Application/src/main/res/drawable-xxhdpi/ic_stop.png",
-    "src/Application/src/main/res/drawable-xxxhdpi/ic_arrow_back.png",
-    "src/Application/src/main/res/drawable-xxxhdpi/ic_launcher.png",
-    "src/Application/src/main/res/drawable-xxxhdpi/ic_share.png",
-    "src/Application/src/main/res/layout/main.xml",
-    "src/Application/src/main/res/layout/remote_view.xml",
-    "src/Application/src/main/res/raw/amazing_grace.mp3",
-    "src/Application/src/main/res/values/strings.xml",
-  ]
-  android_manifest = "src/Application/src/main/AndroidManifest.xml"
-  custom_package = "org.chromium.customtabsclient"
-  deps = [ "//third_party/android_deps:android_support_v7_appcompat_java" ]
-}
-
-android_resources("custom_tabs_support_resources") {
-  sources = [
-    "src/customtabs/res/layout/browser_actions_context_menu_page.xml",
-    "src/customtabs/res/layout/browser_actions_context_menu_row.xml",
-    "src/customtabs/res/values/colors.xml",
-    "src/customtabs/res/values/dimens.xml",
-    "src/customtabs/res/values/strings.xml",
-    "src/customtabs/res/xml/image_share_filepaths.xml",
-  ]
-  android_manifest = "src/customtabs/AndroidManifest.xml"
-  custom_package = "android.support.customtabs"
-}
-
-android_apk("custom_tabs_client_example_apk") {
-  skip_jetify = true
-  sources = [
-    "src/Application/src/main/java/org/chromium/customtabsclient/BottomBarManager.java",
-    "src/Application/src/main/java/org/chromium/customtabsclient/BrowserActionsReceiver.java",
-    "src/Application/src/main/java/org/chromium/customtabsclient/MainActivity.java",
-    "src/Application/src/main/java/org/chromium/customtabsclient/SessionHelper.java",
-  ]
-  android_manifest = "src/Application/src/main/AndroidManifest.xml"
-  min_sdk_version = 16
-  target_sdk_version = 21
-  apk_name = "CustomTabsClientExample"
-  deps = [
-    ":chrome_tabs_client_example_apk_resources",
-    ":custom_tabs_client_shared_java",
-    ":custom_tabs_support_java",
-    "//third_party/android_deps:android_arch_lifecycle_common_java",
-    "//third_party/android_deps:android_support_v7_appcompat_java",
-    "//third_party/android_deps:com_android_support_appcompat_v7_java",
-    "//third_party/android_deps:com_android_support_support_annotations_java",
-  ]
-  chromium_code = false
-}
-
-android_library("custom_tabs_client_shared_java") {
-  skip_jetify = true
-  sources = [
-    "src/shared/src/main/java/org/chromium/customtabsclient/shared/CustomTabsHelper.java",
-    "src/shared/src/main/java/org/chromium/customtabsclient/shared/KeepAliveService.java",
-    "src/shared/src/main/java/org/chromium/customtabsclient/shared/ServiceConnection.java",
-    "src/shared/src/main/java/org/chromium/customtabsclient/shared/ServiceConnectionCallback.java",
-  ]
-
-  deps = [ ":custom_tabs_support_java" ]
-  chromium_code = false
-}
-
-android_library("custom_tabs_support_java") {
-  skip_jetify = true
-  sources = [
-    "src/customtabs/src/android/support/customtabs/CustomTabColorSchemeParams.java",
-    "src/customtabs/src/android/support/customtabs/CustomTabsCallback.java",
-    "src/customtabs/src/android/support/customtabs/CustomTabsClient.java",
-    "src/customtabs/src/android/support/customtabs/CustomTabsIntent.java",
-    "src/customtabs/src/android/support/customtabs/CustomTabsService.java",
-    "src/customtabs/src/android/support/customtabs/CustomTabsServiceConnection.java",
-    "src/customtabs/src/android/support/customtabs/CustomTabsSession.java",
-    "src/customtabs/src/android/support/customtabs/CustomTabsSessionToken.java",
-    "src/customtabs/src/android/support/customtabs/PostMessageBackend.java",
-    "src/customtabs/src/android/support/customtabs/PostMessageService.java",
-    "src/customtabs/src/android/support/customtabs/PostMessageServiceConnection.java",
-    "src/customtabs/src/android/support/customtabs/TrustedWebUtils.java",
-    "src/customtabs/src/android/support/customtabs/browseractions/BrowserActionItem.java",
-    "src/customtabs/src/android/support/customtabs/browseractions/BrowserActionsFallbackMenuAdapter.java",
-    "src/customtabs/src/android/support/customtabs/browseractions/BrowserActionsFallbackMenuDialog.java",
-    "src/customtabs/src/android/support/customtabs/browseractions/BrowserActionsFallbackMenuUi.java",
-    "src/customtabs/src/android/support/customtabs/browseractions/BrowserActionsFallbackMenuView.java",
-    "src/customtabs/src/android/support/customtabs/browseractions/BrowserActionsIntent.java",
-    "src/customtabs/src/android/support/customtabs/browseractions/BrowserServiceFileProvider.java",
-    "src/customtabs/src/android/support/customtabs/browseractions/BrowserServiceImageReadTask.java",
-    "src/customtabs/src/android/support/customtabs/trusted/TrustedWebActivityBuilder.java",
-    "src/customtabs/src/android/support/customtabs/trusted/TrustedWebActivityService.java",
-    "src/customtabs/src/android/support/customtabs/trusted/TrustedWebActivityServiceConnectionManager.java",
-    "src/customtabs/src/android/support/customtabs/trusted/TrustedWebActivityServiceWrapper.java",
-  ]
-  deps = [
-    ":custom_tabs_support_resources",
-
-    # TODO (bjoyce): Restore to android_support_v7_appcompat_java once source
-    # files are manually written to androidx crbug.com/1047843.
-    # "//third_party/android_deps:android_support_v7_appcompat_java",
-    # Remove _temp target once upstream is compatible.
-    "//third_party/android_deps:com_android_support_appcompat_v7_java_temp",
-    "//third_party/android_deps:com_android_support_collections_java_orig",
-    "//third_party/android_deps:com_android_support_interpolator_java",
-    "//third_party/android_deps:com_android_support_support_annotations_java",
-    "//third_party/android_deps:com_android_support_support_compat_java",
-  ]
-  srcjar_deps = [ ":chrome_custom_tabs_service_aidl" ]
-  android_manifest_for_lint = "src/customtabs/AndroidManifest.xml"
-  chromium_code = false
-}
-
-android_aidl("chrome_custom_tabs_service_aidl") {
-  interface_file = "common.aidl"
-
-  java_in_dir = "src/customtabs/src/android/support/customtabs"
-  sources = [
-    "$java_in_dir/ICustomTabsCallback.aidl",
-    "$java_in_dir/ICustomTabsService.aidl",
-    "$java_in_dir/IPostMessageService.aidl",
-    "$java_in_dir/trusted/ITrustedWebActivityService.aidl",
-  ]
-}
diff --git a/third_party/custom_tabs_client/LICENSE b/third_party/custom_tabs_client/LICENSE
deleted file mode 100644
index 67db858..0000000
--- a/third_party/custom_tabs_client/LICENSE
+++ /dev/null
@@ -1,175 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
diff --git a/third_party/custom_tabs_client/OWNERS b/third_party/custom_tabs_client/OWNERS
deleted file mode 100644
index e341d82..0000000
--- a/third_party/custom_tabs_client/OWNERS
+++ /dev/null
@@ -1,7 +0,0 @@
-lizeb@chromium.org
-peconn@chromium.org
-yusufo@chromium.org
-
-per-file *.aidl=set noparent
-per-file *.aidl=file://ipc/SECURITY_OWNERS
-# COMPONENT: UI>Browser>Mobile>CustomTabs
diff --git a/third_party/custom_tabs_client/README.chromium b/third_party/custom_tabs_client/README.chromium
deleted file mode 100644
index 0bf829b..0000000
--- a/third_party/custom_tabs_client/README.chromium
+++ /dev/null
@@ -1,26 +0,0 @@
-Name: Chrome Custom Tabs - Example and Usage
-Short Name: Chrome Custom Tabs Client
-URL: https://chromium.googlesource.com/external/github.com/GoogleChrome/custom-tabs-client
-Version: unknown
-License: Apache 2.0
-Security Critical: yes
-License Android Compatible: yes
-
-Description:
-This presents an example application using Chrome Custom Tabs, and a possible
-usage of both the intent and the background service APIs. It covers UI
-customization, callback setup, pre-warming and pre-fetching, and lifecycle
-management. Also inside demos there is another application that launches
-custom tabs in different modes.
-
-The example applicaton also presents how to use Browser Actions, including
-creating request intent and adding custom items.
-
-The actual code that Chromium builds from is in
-//third_party/android_sdk/androidx_browser, this subdirectory is kept around
-for the example app (the custom_tabs_client_example_apk target).
-
-TODO(peconn): Get rid of src/customtabs and depend instead on
-androidx_browser.
-
-Local Modifications: None
diff --git a/third_party/custom_tabs_client/common.aidl b/third_party/custom_tabs_client/common.aidl
deleted file mode 100644
index 5566e8c..0000000
--- a/third_party/custom_tabs_client/common.aidl
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright 2015 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.
-
-interface android.support.customtabs.ICustomTabsService;
-interface android.support.customtabs.ICustomTabsCallback;
-interface android.support.customtabs.IPostMessageService;
diff --git a/third_party/googletest/BUILD.gn b/third_party/googletest/BUILD.gn
index a906f07..52c2858 100644
--- a/third_party/googletest/BUILD.gn
+++ b/third_party/googletest/BUILD.gn
@@ -171,8 +171,6 @@
     "src/googlemock/include/gmock/gmock-cardinalities.h",
     "src/googlemock/include/gmock/gmock-function-mocker.h",
     "src/googlemock/include/gmock/gmock-generated-actions.h",
-    "src/googlemock/include/gmock/gmock-generated-function-mockers.h",
-    "src/googlemock/include/gmock/gmock-generated-matchers.h",
     "src/googlemock/include/gmock/gmock-matchers.h",
     "src/googlemock/include/gmock/gmock-more-actions.h",
     "src/googlemock/include/gmock/gmock-more-matchers.h",
diff --git a/third_party/sqlite/PRESUBMIT.py b/third_party/sqlite/PRESUBMIT.py
index 7be2bbc..950e536e 100644
--- a/third_party/sqlite/PRESUBMIT.py
+++ b/third_party/sqlite/PRESUBMIT.py
@@ -8,11 +8,17 @@
 
 
 def CheckChangeOnUpload(input_api, output_api):
-  results = []
+    results = []
+    this_dir = input_api.PresubmitLocalPath()
 
-  results += input_api.RunTests(
-      input_api.canned_checks.GetUnitTests(input_api, output_api, [
-          'scripts/extract_sqlite_api_unittest.py'
-      ], env=None, run_on_python2=False, run_on_python3=True))
+    results += input_api.RunTests(
+        input_api.canned_checks.GetUnitTestsInDirectory(
+            input_api,
+            output_api,
+            input_api.os_path.join(this_dir, 'scripts'),
+            whitelist=['.*unittest.py$'],
+            env=None,
+            run_on_python2=False,
+            run_on_python3=True))
 
-  return results
+    return results
diff --git a/third_party/sqlite/scripts/.style.yapf b/third_party/sqlite/scripts/.style.yapf
new file mode 100644
index 0000000..1d02278
--- /dev/null
+++ b/third_party/sqlite/scripts/.style.yapf
@@ -0,0 +1,3 @@
+[style]
+based_on_style = pep8
+
diff --git a/third_party/sqlite/scripts/.yapfignore b/third_party/sqlite/scripts/.yapfignore
new file mode 100644
index 0000000..a278a739
--- /dev/null
+++ b/third_party/sqlite/scripts/.yapfignore
@@ -0,0 +1,3 @@
+# TODO(cmumford): Format older files in a future CL.
+extract_sqlite_api.py
+extract_sqlite_api_unittest.py
diff --git a/third_party/sqlite/scripts/sqlite_cherry_picker.py b/third_party/sqlite/scripts/sqlite_cherry_picker.py
index eaef97c..c4d5de8 100755
--- a/third_party/sqlite/scripts/sqlite_cherry_picker.py
+++ b/third_party/sqlite/scripts/sqlite_cherry_picker.py
@@ -12,325 +12,361 @@
 
 
 class UnstagedFiles(Exception):
-  pass
+    pass
 
 
 class UnknownHash(Exception):
-  pass
+    pass
+
+
+class IncorrectType(Exception):
+    pass
 
 
 class bcolors:
-  HEADER = '\033[95m'
-  OKBLUE = '\033[94m'
-  OKGREEN = '\033[92m'
-  WARNING = '\033[93m'
-  FAIL = '\033[91m'
-  ENDC = '\033[0m'
+    HEADER = '\033[95m'
+    OKBLUE = '\033[94m'
+    OKGREEN = '\033[92m'
+    WARNING = '\033[93m'
+    FAIL = '\033[91m'
+    ENDC = '\033[0m'
 
 
 def _print_command(cmd):
-  """Print the command to be executed to the console.
+    """Print the command to be executed to the console.
 
-  Use a different color so that it can be easily seen amongst the output
-  commands.
-  """
-  if (isinstance(cmd, list)):
-    cmd = ' '.join(cmd)
-  print('{}{}{}'.format(bcolors.OKBLUE, cmd, bcolors.ENDC))
+    Use a different color so that it can be easily seen amongst the output
+    commands.
+    """
+    if (isinstance(cmd, list)):
+        cmd = ' '.join(cmd)
+    print('{}{}{}'.format(bcolors.OKBLUE, cmd, bcolors.ENDC))
 
 
 class ManifestEntry(object):
-  """Represents a single entry in a SQLite manifest."""
+    """Represents a single entry in a SQLite manifest."""
 
-  valid_types = ('C', 'D', 'F', 'P', 'R', 'T', 'U', 'Z')
+    def __init__(self, entry_type, items):
+        if not len(entry_type) == 1:
+            raise IncorrectType(entry_type)
+        self.entry_type = entry_type
+        self.items = items
 
-  def __init__(self, entry_type, items):
-    assert entry_type in ManifestEntry.valid_types
-    self.entry_type = entry_type
-    self.items = items
+    def get_hash_type(self):
+        """Return the type of hash used for this entry."""
+        last_item = self.items[-1]
+        if not all(c in string.hexdigits for c in last_item):
+            print(
+                '"{}" doesn\'t appear to be a hash.'.format(last_item),
+                file=sys.stderr)
+            raise UnknownHash()
+        elif len(last_item) == 40:
+            return 'sha1'
+        elif len(last_item) == 64:
+            return 'sha3'
+        else:
+            raise UnknownHash('Incorrect length {} for {}'.format(
+                len(last_item), last_item))
 
-  def get_hash_type(self):
-    """Return the type of hash used for this entry."""
-    last_item = self.items[-1]
-    if not all(c in string.hexdigits for c in last_item):
-      print(
-          '"{}" doesn\'t appear to be a hash.'.format(last_item),
-          file=sys.stderr)
-      raise UnknownHash()
-    elif len(last_item) == 40:
-      return 'sha1'
-    elif len(last_item) == 64:
-      return 'sha3'
-    else:
-      print(
-          'Incorrect length {} for {}'.format(len(last_item), last_item),
-          file=sys.stderr)
-      raise UnknownHash()
+    @staticmethod
+    def calc_hash(data, method):
+        """Return the string sha1 or sha3 hash digest for the given data."""
+        if method == 'sha3':
+            h = hashlib.sha3_256()
+        elif method == 'sha1':
+            h = hashlib.sha1()
+        else:
+            assert False
+        h.update(data)
+        return h.hexdigest()
 
-  @staticmethod
-  def calc_hash(fname, method):
-    """Return the string sha3 hash digest for the given file."""
-    with open(fname, 'rb') as input_file:
-      if method == 'sha3':
-        h = hashlib.sha3_256()
-      elif method == 'sha1':
-        h = hashlib.sha1()
-      else:
-        assert False
-      h.update(input_file.read())
-      return h.hexdigest()
+    @staticmethod
+    def calc_file_hash(fname, method):
+        """Return the string sha1 or sha3 hash digest for the given file."""
+        with open(fname, 'rb') as input_file:
+            return ManifestEntry.calc_hash(input_file.read(), method)
 
-  def update_file_hash(self):
-    """Calculates a new file hash for this entry."""
-    self.items[1] = ManifestEntry.calc_hash(self.items[0], self.get_hash_type())
+    def update_file_hash(self):
+        """Calculates a new file hash for this entry."""
+        self.items[1] = ManifestEntry.calc_file_hash(self.items[0],
+                                                     self.get_hash_type())
 
-  def __str__(self):
-    return '{} {}'.format(self.entry_type, ' '.join(self.items))
+    def __str__(self):
+        return '{} {}'.format(self.entry_type, ' '.join(self.items))
 
 
 class Manifest(object):
-  """A deserialized SQLite manifest."""
+    """A deserialized SQLite manifest."""
 
-  def __init__(self):
-    self.entries = []
+    def __init__(self):
+        self.entries = []
 
-  def find_file_entry(self, fname):
-    """Given a file path return the entry. Returns None if none found."""
-    for entry in self.entries:
-      if entry.entry_type == 'F' and entry.items[0] == fname:
-        return entry
-    return None
+    def find_file_entry(self, fname):
+        """Given a file path return the entry. Returns None if none found."""
+        for entry in self.entries:
+            if entry.entry_type == 'F' and entry.items[0] == fname:
+                return entry
+        return None
 
 
 class ManifestSerializer(object):
-  """De/serialize SQLite manifests."""
+    """De/serialize SQLite manifests."""
 
-  @staticmethod
-  def read(fname):
-    """Deserialze a manifest file and return a Manifest object."""
-    _manifest = Manifest()
-    with open(fname) as input_file:
-      for line in input_file.readlines():
-        items = line.split()
-        if not items:
-          continue
-        _manifest.entries.append(ManifestEntry(items[0], items[1:]))
-    return _manifest
+    @staticmethod
+    def read_stream(input_stream):
+        """Deserialize a manifest from an input stream and return a Manifest
+        object."""
+        _manifest = Manifest()
+        for line in input_stream.readlines():
+            items = line.split()
+            if not items:
+                continue
+            _manifest.entries.append(ManifestEntry(items[0], items[1:]))
+        return _manifest
 
-  @staticmethod
-  def write(fname, manifest):
-    """Serialize the given manifest to the specified file."""
-    with open(fname, 'w') as output_file:
-      for entry in manifest.entries:
-        print(str(entry), file=output_file)
+    @staticmethod
+    def read_file(fname):
+        """Deserialize a manifest file and return a Manifest object."""
+        with open(fname) as input_stream:
+            return ManifestSerializer.read_stream(input_stream)
+
+    @staticmethod
+    def write_stream(manifest, output_stream):
+        """Serialize the given manifest to the given stream."""
+        for entry in manifest.entries:
+            print(str(entry), file=output_stream)
+
+    @staticmethod
+    def write_file(manifest, fname):
+        """Serialize the given manifest to the specified file."""
+        with open(fname, 'w') as output_stream:
+            ManifestSerializer.write_stream(manifest, output_stream)
 
 
 class Git(object):
+    @staticmethod
+    def _get_status():
+        changes = []
+        for line in subprocess.check_output(['git', 'status',
+                                             '--porcelain']).splitlines():
+            changes.append(line.decode('utf-8'))
+        return changes
 
-  @staticmethod
-  def _get_status():
-    changes = []
-    for line in subprocess.check_output(['git', 'status',
-                                         '--porcelain']).splitlines():
-      changes.append(line.decode('utf-8'))
-    return changes
+    @staticmethod
+    def get_staged_changes():
+        changes = []
+        for line in Git._get_status():
+            entry = line[0:2]
+            if entry == 'M ':
+                changes.append(line.split()[1])
+        return changes
 
-  @staticmethod
-  def get_staged_changes():
-    changes = []
-    for line in Git._get_status():
-      entry = line[0:2]
-      if entry == 'M ':
-        changes.append(line.split()[1])
-    return changes
+    @staticmethod
+    def get_unstaged_changes():
+        changes = []
+        for line in Git._get_status():
+            entry = line[0:2]
+            if entry == ' M':
+                changes.append(line.split()[1])
+        return changes
 
-  @staticmethod
-  def get_unstaged_changes():
-    changes = []
-    for line in Git._get_status():
-      entry = line[0:2]
-      if entry == ' M':
-        changes.append(line.split()[1])
-    return changes
-
-  @staticmethod
-  def get_unmerged_changes():
-    changes = []
-    for line in Git._get_status():
-      entry = line[0:2]
-      if entry == 'UU':
-        changes.append(line.split()[1])
-    return changes
+    @staticmethod
+    def get_unmerged_changes():
+        changes = []
+        for line in Git._get_status():
+            entry = line[0:2]
+            if entry == 'UU':
+                changes.append(line.split()[1])
+        return changes
 
 
 class CherryPicker(object):
-  """Class to cherry pick commits in a SQLite Git repository."""
+    """Class to cherry pick commits in a SQLite Git repository."""
 
-  def __init__(self):
-    self._print_cmds = True
-    self._update_amangamation = True
+    # The binary file extenions for files committed to the SQLite repository.
+    # This is used as a simple way of detecting files that cannot (simply) be
+    # resolved in a merge conflict. This script will automatically ignore
+    # all conflicted files with any of these extensions. If, in the future, new
+    # binary types are added then a conflict will arise during cherry-pick and
+    # the user will need to resolve it.
+    binary_extensions = (
+        '.data',
+        '.db',
+        '.ico',
+        '.jpg',
+        '.png',
+    )
 
-  def _take_head_version(self, file_path):
-    subprocess.call(
-        'git show HEAD:{} > {}'.format(file_path, file_path), shell=True)
-    subprocess.call('git add {}'.format(file_path), shell=True)
+    def __init__(self):
+        self._print_cmds = True
+        self._update_amangamation = True
 
-  @staticmethod
-  def _is_binary_file(file_path):
-    _, file_extension = os.path.splitext(file_path)
-    return file_extension == '.db'
+    def _take_head_version(self, file_path):
+        subprocess.call(
+            'git show HEAD:{} > {}'.format(file_path, file_path), shell=True)
+        subprocess.call('git add {}'.format(file_path), shell=True)
 
-  @staticmethod
-  def _append_cherry_pick_comments(comments):
-    # TODO(cmumford): Figure out how to append comments on cherry picks
-    pass
+    @staticmethod
+    def _is_binary_file(file_path):
+        _, file_extension = os.path.splitext(file_path)
+        return file_extension in CherryPicker.binary_extensions
 
-  def _cherry_pick_git_commit(self, commit_id):
-    """Cherry-pick a given Git commit into the current branch."""
-    cmd = ['git', 'cherry-pick', '-x', commit_id]
-    if self._print_cmds:
-      _print_command(' '.join(cmd))
-    returncode = subprocess.call(cmd)
-    # The manifest and manifest.uuid contain Fossil hashes. Restore to
-    # HEAD version and update only when all conflicts have been resolved.
-    comments = None
-    self._take_head_version('manifest')
-    self._take_head_version('manifest.uuid')
-    for unmerged_file in Git.get_unmerged_changes():
-      if CherryPicker._is_binary_file(unmerged_file):
-        print('{} is a binary file, keeping branch version.'.format(
-            unmerged_file))
-        self._take_head_version(unmerged_file)
-        if not comments:
-          comments = ['Cherry-pick notes', '==============================']
-        comments.append(
-            '{} is binary file (with conflict). Keeping branch version'.format(
-                unmerged_file))
-    if comments:
-      CherryPicker._append_cherry_pick_comments(comments)
-    self.continue_cherry_pick()
+    @staticmethod
+    def _append_cherry_pick_comments(comments):
+        # TODO(cmumford): Figure out how to append comments on cherry picks
+        pass
 
-  @staticmethod
-  def _is_git_commit_id(commit_id):
-    return len(commit_id) == 40
+    def _cherry_pick_git_commit(self, commit_id):
+        """Cherry-pick a given Git commit into the current branch."""
+        cmd = ['git', 'cherry-pick', '-x', commit_id]
+        if self._print_cmds:
+            _print_command(' '.join(cmd))
+        returncode = subprocess.call(cmd)
+        # The manifest and manifest.uuid contain Fossil hashes. Restore to
+        # HEAD version and update only when all conflicts have been resolved.
+        comments = None
+        self._take_head_version('manifest')
+        self._take_head_version('manifest.uuid')
+        for unmerged_file in Git.get_unmerged_changes():
+            if CherryPicker._is_binary_file(unmerged_file):
+                print('{} is a binary file, keeping branch version.'.format(
+                    unmerged_file))
+                self._take_head_version(unmerged_file)
+                if not comments:
+                    comments = [
+                        'Cherry-pick notes', '=============================='
+                    ]
+                comments.append(
+                    '{} is binary file (with conflict). Keeping branch version'
+                    .format(unmerged_file))
+        if comments:
+            CherryPicker._append_cherry_pick_comments(comments)
+        self.continue_cherry_pick()
 
-  def _find_git_commit_id(self, fossil_commit_id):
-    cmd = [
-        'git', '--no-pager', 'log', '--color=never', '--all',
-        '--pretty=format:%H', '--grep={}'.format(fossil_commit_id),
-        'origin/master'
-    ]
-    if self._print_cmds:
-      _print_command(' '.join(cmd))
-    for line in subprocess.check_output(cmd).splitlines():
-      return line.decode('utf-8')
-    # Not found.
-    assert False
+    @staticmethod
+    def _is_git_commit_id(commit_id):
+        return len(commit_id) == 40
 
-  def cherry_pick(self, commit_id):
-    """Cherry-pick a given commit into the current branch.
+    def _find_git_commit_id(self, fossil_commit_id):
+        cmd = [
+            'git', '--no-pager', 'log', '--color=never', '--all',
+            '--pretty=format:%H', '--grep={}'.format(fossil_commit_id),
+            'origin/master'
+        ]
+        if self._print_cmds:
+            _print_command(' '.join(cmd))
+        for line in subprocess.check_output(cmd).splitlines():
+            return line.decode('utf-8')
+        # Not found.
+        assert False
+
+    def cherry_pick(self, commit_id):
+        """Cherry-pick a given commit into the current branch.
 
         Can cherry-pick a given Git or a Fossil commit.
-    """
-    if not CherryPicker._is_git_commit_id(commit_id):
-      commit_id = self._find_git_commit_id(commit_id)
-    self._cherry_pick_git_commit(commit_id)
+        """
+        if not CherryPicker._is_git_commit_id(commit_id):
+            commit_id = self._find_git_commit_id(commit_id)
+        self._cherry_pick_git_commit(commit_id)
 
-  def _generate_amalgamation(self):
-    for config_name in ['chromium', 'dev']:
-      generate_amalgamation.make_aggregate(config_name)
-      generate_amalgamation.extract_sqlite_api(config_name)
+    def _generate_amalgamation(self):
+        for config_name in ['chromium', 'dev']:
+            generate_amalgamation.make_aggregate(config_name)
+            generate_amalgamation.extract_sqlite_api(config_name)
 
-  def _add_amalgamation(self):
-    os.chdir(generate_amalgamation._SQLITE_SRC_DIR)
-    for config_name in ['chromium', 'dev']:
-      cmd = [
-          'git', 'add',
-          generate_amalgamation.get_amalgamation_dir(config_name)
-      ]
-      if self._print_cmds:
-        _print_command(' '.join(cmd))
-      subprocess.check_call(cmd)
+    def _add_amalgamation(self):
+        os.chdir(generate_amalgamation._SQLITE_SRC_DIR)
+        for config_name in ['chromium', 'dev']:
+            cmd = [
+                'git', 'add',
+                generate_amalgamation.get_amalgamation_dir(config_name)
+            ]
+            if self._print_cmds:
+                _print_command(' '.join(cmd))
+            subprocess.check_call(cmd)
 
-  def _update_manifests(self):
-    """Update the SQLite's Fossil manifest files.
+    def _update_manifests(self):
+        """Update the SQLite's Fossil manifest files.
 
-    This isn't strictly necessary as the manifest isn't used during
-    any build, and manifest.uuid is the Fossil commit ID (which
-    has no meaning in a Git repo). However, keeping these updated
-    helps make it more obvious that a commit originated in
-    Git and not Fossil.
-    """
-    manifest = ManifestSerializer.read('manifest')
-    files_not_in_manifest = ('manifest', 'manifest.uuid')
-    for fname in Git.get_staged_changes():
-      if fname in files_not_in_manifest:
-        continue
-      entry = manifest.find_file_entry(fname)
-      if not entry:
-        print(
-            'Cannot find manifest entry for "{}"'.format(fname),
-            file=sys.stderr)
-        sys.exit(1)
-      manifest.find_file_entry(fname).update_file_hash()
-    ManifestSerializer.write('manifest', manifest)
-    cmd = ['git', 'add', 'manifest']
-    if self._print_cmds:
-      _print_command(' '.join(cmd))
-    subprocess.check_call(cmd)
-    # manifest.uuid contains the hash from the Fossil repository which
-    # doesn't make sense in a Git branch. Just write all zeros.
-    with open('manifest.uuid', 'w') as output_file:
-      print('0' * 64, file=output_file)
-    cmd = ['git', 'add', 'manifest.uuid']
-    if self._print_cmds:
-      _print_command(' '.join(cmd))
-    subprocess.check_call(cmd)
+        This isn't strictly necessary as the manifest isn't used during
+        any build, and manifest.uuid is the Fossil commit ID (which
+        has no meaning in a Git repo). However, keeping these updated
+        helps make it more obvious that a commit originated in
+        Git and not Fossil.
+        """
+        manifest = ManifestSerializer.read_file('manifest')
+        files_not_in_manifest = ('manifest', 'manifest.uuid')
+        for fname in Git.get_staged_changes():
+            if fname in files_not_in_manifest:
+                continue
+            entry = manifest.find_file_entry(fname)
+            if not entry:
+                print(
+                    'Cannot find manifest entry for "{}"'.format(fname),
+                    file=sys.stderr)
+                sys.exit(1)
+            manifest.find_file_entry(fname).update_file_hash()
+        ManifestSerializer.write_file(manifest, 'manifest')
+        cmd = ['git', 'add', 'manifest']
+        if self._print_cmds:
+            _print_command(' '.join(cmd))
+        subprocess.check_call(cmd)
+        # manifest.uuid contains the hash from the Fossil repository which
+        # doesn't make sense in a Git branch. Just write all zeros.
+        with open('manifest.uuid', 'w') as output_file:
+            print('0' * 64, file=output_file)
+        cmd = ['git', 'add', 'manifest.uuid']
+        if self._print_cmds:
+            _print_command(' '.join(cmd))
+        subprocess.check_call(cmd)
 
-  def continue_cherry_pick(self):
-    if Git.get_unstaged_changes() or Git.get_unmerged_changes():
-      raise UnstagedFiles()
-    self._update_manifests()
-    if self._update_amangamation:
-      self._generate_amalgamation()
-      self._add_amalgamation()
-    cmd = ['git', 'cherry-pick', '--continue']
-    if self._print_cmds:
-      _print_command(' '.join(cmd))
-    subprocess.check_call(cmd)
+    def continue_cherry_pick(self):
+        if Git.get_unstaged_changes() or Git.get_unmerged_changes():
+            raise UnstagedFiles()
+        self._update_manifests()
+        if self._update_amangamation:
+            self._generate_amalgamation()
+            self._add_amalgamation()
+        cmd = ['git', 'cherry-pick', '--continue']
+        if self._print_cmds:
+            _print_command(' '.join(cmd))
+        subprocess.check_call(cmd)
 
 
 if __name__ == '__main__':
-  desc = 'A script for cherry-picking commits from the SQLite repo.'
-  parser = argparse.ArgumentParser(description=desc)
-  parser.add_argument(
-      'commit', nargs='*', help='The commit ids to cherry pick (in order)')
-  parser.add_argument(
-      '--continue',
-      dest='cont',
-      action='store_true',
-      help='Continue the cherry-pick once conflicts have been resolved')
-  namespace = parser.parse_args()
-  cherry_picker = CherryPicker()
-  if namespace.cont:
-    try:
-      cherry_picker.continue_cherry_pick()
-      sys.exit(0)
-    except UnstagedFiles:
-      print('There are still unstaged files to resolve before continuing.')
-      sys.exit(1)
-  num_picked = 0
-  for commit_id in namespace.commit:
-    try:
-      cherry_picker.cherry_pick(commit_id)
-      num_picked += 1
-    except UnstagedFiles:
-      print('\nThis cherry-pick contains conflicts. Please resolve them ')
-      print('(e.g git mergetool) and rerun this script '
-            '`sqlite_cherry_picker.py --continue`')
-      print('or `git cherry-pick --abort`.')
-      if commit_id != namespace.commit[-1]:
-        msg = ('NOTE: You have only successfully cherry-picked {} out of {} '
-               'commits.')
-        print(msg.format(num_picked, len(namespace.commit)))
-      sys.exit(1)
+    desc = 'A script for cherry-picking commits from the SQLite repo.'
+    parser = argparse.ArgumentParser(description=desc)
+    parser.add_argument(
+        'commit', nargs='*', help='The commit ids to cherry pick (in order)')
+    parser.add_argument(
+        '--continue',
+        dest='cont',
+        action='store_true',
+        help='Continue the cherry-pick once conflicts have been resolved')
+    namespace = parser.parse_args()
+    cherry_picker = CherryPicker()
+    if namespace.cont:
+        try:
+            cherry_picker.continue_cherry_pick()
+            sys.exit(0)
+        except UnstagedFiles:
+            print(
+                'There are still unstaged files to resolve before continuing.')
+            sys.exit(1)
+    num_picked = 0
+    for commit_id in namespace.commit:
+        try:
+            cherry_picker.cherry_pick(commit_id)
+            num_picked += 1
+        except UnstagedFiles:
+            print(
+                '\nThis cherry-pick contains conflicts. Please resolve them ')
+            print('(e.g git mergetool) and rerun this script '
+                  '`sqlite_cherry_picker.py --continue`')
+            print('or `git cherry-pick --abort`.')
+            if commit_id != namespace.commit[-1]:
+                msg = (
+                    'NOTE: You have only successfully cherry-picked {} out of '
+                    '{} commits.')
+                print(msg.format(num_picked, len(namespace.commit)))
+            sys.exit(1)
diff --git a/third_party/sqlite/scripts/sqlite_cherry_picker_unittest.py b/third_party/sqlite/scripts/sqlite_cherry_picker_unittest.py
new file mode 100755
index 0000000..587c7cfa
--- /dev/null
+++ b/third_party/sqlite/scripts/sqlite_cherry_picker_unittest.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python3
+
+# 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.
+"""Tests for sqlite_cherry_picker.py.
+
+These tests should be getting picked up by the PRESUBMIT.py in the parent
+directory.
+"""
+
+from pathlib import Path
+import io
+import os
+import shutil
+import tempfile
+import unittest
+import sqlite_cherry_picker
+
+# pylint: disable=W0212,C0103,C0115,C0116
+
+
+class CherryPickerUnittest(unittest.TestCase):
+    def setUp(self):
+        self.test_root = tempfile.mkdtemp()
+
+    def tearDown(self):
+        if self.test_root:
+            shutil.rmtree(self.test_root)
+
+    def testManifestEntryConstructor(self):
+        with self.assertRaises(sqlite_cherry_picker.IncorrectType):
+            entry = sqlite_cherry_picker.ManifestEntry('DD', [
+                'vsixtest/vsixtest.tcl',
+                '6a9a6ab600c25a91a7acc6293828957a386a8a93'
+            ])
+            del entry  # unused because exception will be raised.
+
+    def testManifestEntryHashType(self):
+        entry = sqlite_cherry_picker.ManifestEntry('F', [
+            'vsixtest/vsixtest.tcl', '6a9a6ab600c25a91a7acc6293828957a386a8a93'
+        ])
+        self.assertEqual(entry.get_hash_type(), 'sha1')
+
+        entry = sqlite_cherry_picker.ManifestEntry('F', [
+            'tool/warnings-clang.sh',
+            'bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7'
+        ])
+        self.assertEqual(entry.get_hash_type(), 'sha3')
+
+        # test a bad hash which is too short and cannot be identified as either
+        # a sha1 or sha3 hash.
+        with self.assertRaises(sqlite_cherry_picker.UnknownHash):
+            entry = sqlite_cherry_picker.ManifestEntry(
+                'F', ['file/path.sh', '12345678'])
+            entry.get_hash_type()
+
+    def testManifestEntryHashCalc(self):
+        data = 'abcdefghijklmnopqrstuvwxyDEFGHIJKLMUVWXYZ0123456789'.encode(
+            'utf-8')
+        self.assertEqual(
+            sqlite_cherry_picker.ManifestEntry.calc_hash(data, 'sha1'),
+            'e117bfe4bcb1429cf8a0f72f8f4ea322a9a500eb')
+        self.assertEqual(
+            sqlite_cherry_picker.ManifestEntry.calc_hash(data, 'sha3'),
+            '2cb59ee01402c45e7c56008b7ca33d006dbd980a5e222fac3a584f5639a450d7')
+
+    def testManifestFindEntry(self):
+        manifest = sqlite_cherry_picker.Manifest()
+        self.assertIsNone(manifest.find_file_entry('nonexistent'))
+        manifest.entries = [
+            sqlite_cherry_picker.ManifestEntry('F', [
+                'tool/warnings-clang.sh',
+                'bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7'
+            ]),
+            sqlite_cherry_picker.ManifestEntry('T',
+                                               ['+bgcolor', '*', '#d0c0ff'])
+        ]
+
+        entry = manifest.find_file_entry('tool/warnings-clang.sh')
+        self.assertIsNotNone(entry)
+        self.assertEqual(entry.items[0], 'tool/warnings-clang.sh')
+
+        # Should only find files.
+        self.assertIsNone(manifest.find_file_entry('+bgcolor'))
+
+    def testManifestDeserialize(self):
+        manfest_path = os.path.join(
+            os.path.dirname(os.path.realpath(__file__)), 'test_data',
+            'test_manifest')
+        manifest_data = Path(manfest_path).read_text()
+        input_stream = io.StringIO(manifest_data)
+        manifest = sqlite_cherry_picker.ManifestSerializer.read_stream(
+            input_stream)
+        self.assertEqual(len(manifest.entries), 9)
+
+        output_stream = io.StringIO()
+        sqlite_cherry_picker.ManifestSerializer.write_stream(
+            manifest, output_stream)
+        self.assertEqual(output_stream.getvalue(), manifest_data)
+
+    def testGitHash(self):
+        valid_git_commit_id = '61c3ca1b1c77bbcaa35f9326decf3658bdb5626a'
+        self.assertTrue(
+            sqlite_cherry_picker.CherryPicker._is_git_commit_id(
+                valid_git_commit_id))
+
+        invalid_git_commit_id = 'f3658bdb5626a'
+        self.assertFalse(
+            sqlite_cherry_picker.CherryPicker._is_git_commit_id(
+                invalid_git_commit_id))
+
+    def testIsBinaryFile(self):
+        self.assertTrue(
+            sqlite_cherry_picker.CherryPicker._is_binary_file(
+                'path/test.data'))
+        self.assertTrue(
+            sqlite_cherry_picker.CherryPicker._is_binary_file('path/test.db'))
+        self.assertTrue(
+            sqlite_cherry_picker.CherryPicker._is_binary_file('path/test.ico'))
+        self.assertTrue(
+            sqlite_cherry_picker.CherryPicker._is_binary_file('path/test.jpg'))
+        self.assertTrue(
+            sqlite_cherry_picker.CherryPicker._is_binary_file('path/test.png'))
+
+        self.assertFalse(
+            sqlite_cherry_picker.CherryPicker._is_binary_file('path/test.c'))
+        self.assertFalse(
+            sqlite_cherry_picker.CherryPicker._is_binary_file('path/test.h'))
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/third_party/sqlite/scripts/test_data/test_manifest b/third_party/sqlite/scripts/test_data/test_manifest
new file mode 100644
index 0000000..109045e1
--- /dev/null
+++ b/third_party/sqlite/scripts/test_data/test_manifest
@@ -0,0 +1,9 @@
+C Version\s3.31.1
+D 2020-01-27T19:55:54.490
+F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
+R bf075f6bcc1758c5c1ecd13052997456
+T +bgcolor * #d0c0ff
+T +sym-release *
+T +sym-version-3.31.1 *
+U drh
+Z 7c50801eed3eaef969e028ef5a0a641a
diff --git a/tools/android/avd/OWNERS b/tools/android/avd/OWNERS
new file mode 100644
index 0000000..3e81536
--- /dev/null
+++ b/tools/android/avd/OWNERS
@@ -0,0 +1 @@
+file://build/android/pylib/local/emulator/OWNERS
diff --git a/tools/android/avd/avd.py b/tools/android/avd/avd.py
index 357561f..1098400 100755
--- a/tools/android/avd/avd.py
+++ b/tools/android/avd/avd.py
@@ -99,6 +99,12 @@
       action='store_true',
       default=False,
       help='Enable graphical window display on the emulator.')
+  start_parser.add_argument(
+      '--debug-tags',
+      help='Comma-separated list of debug tags. This can be used to enable or '
+      'disable debug messages from specific parts of the emulator, e.g. '
+      'init, snapshot. See "emulator -help-debug-tags" '
+      'for a full list of tags.')
   add_common_arguments(start_parser)
 
   def start_cmd(args):
@@ -106,7 +112,8 @@
     inst.Start(
         read_only=args.read_only,
         snapshot_save=not args.read_only,
-        window=args.emulator_window)
+        window=args.emulator_window,
+        debug_tags=args.debug_tags)
     print('%s started (pid: %d)' % (str(inst), inst._emulator_proc.pid))
     return 0
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 9fe479a7..5b570dae 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -37550,6 +37550,7 @@
   <int value="-2134244069" label="HttpFormWarning:enabled"/>
   <int value="-2133892372" label="ResamplingInputEvents:disabled"/>
   <int value="-2133277113" label="CCTModuleCustomHeader:disabled"/>
+  <int value="-2133276662" label="EduCoexistenceConsentLog:disabled"/>
   <int value="-2132591642" label="enable-input-view"/>
   <int value="-2132161378" label="SendTabToSelfHistory:disabled"/>
   <int value="-2131746498"
@@ -38885,6 +38886,7 @@
   <int value="-649956990" label="enable-harfbuzz-rendertext"/>
   <int value="-648925189" label="ExploreSites:enabled"/>
   <int value="-645455405" label="MacViewsNativeDialogs:enabled"/>
+  <int value="-643217597" label="EduCoexistenceConsentLog:enabled"/>
   <int value="-641820371" label="EnableCustomMacPaperSizes:enabled"/>
   <int value="-641719457" label="disable-compositor-touch-hit-testing"/>
   <int value="-640191786" label="DesktopPWAsWithoutExtensions:enabled"/>
diff --git a/ui/accessibility/ax_tree_serializer.h b/ui/accessibility/ax_tree_serializer.h
index 18fe3aa..b9e6fc36 100644
--- a/ui/accessibility/ax_tree_serializer.h
+++ b/ui/accessibility/ax_tree_serializer.h
@@ -180,6 +180,8 @@
   // like when Reset() is called.
   void InternalReset();
 
+  ClientTreeNode* GetClientTreeNodeParent(ClientTreeNode* obj);
+
   // The tree source.
   AXTreeSource<AXSourceNode, AXNodeData, AXTreeData>* tree_;
 
@@ -269,7 +271,7 @@
   std::vector<ClientTreeNode*> client_ancestors;
   while (client_node) {
     client_ancestors.push_back(client_node);
-    client_node = client_node->parent;
+    client_node = GetClientTreeNodeParent(client_node);
   }
 
   // Start at the root. Keep going until the source ancestor chain and
@@ -304,9 +306,12 @@
   // that we're inside of an invalid subtree that all needs to be
   // re-serialized, so the LCA should be higher.
   ClientTreeNode* client_node = ClientTreeNodeById(tree_->GetId(node));
-  while (
-      tree_->IsValid(node) &&
-      (!client_node || (client_node->parent && client_node->parent->invalid))) {
+  while (tree_->IsValid(node)) {
+    if (client_node) {
+      ClientTreeNode* parent = GetClientTreeNodeParent(client_node);
+      if (!parent || !parent->invalid)
+        break;
+    }
     node = tree_->GetParent(node);
     if (tree_->IsValid(node))
       client_node = ClientTreeNodeById(tree_->GetId(node));
@@ -326,12 +331,13 @@
     int child_id = tree_->GetId(child);
     ClientTreeNode* client_child = ClientTreeNodeById(child_id);
     if (client_child) {
-      if (!client_child->parent) {
+      ClientTreeNode* parent = client_child->parent;
+      if (!parent) {
         // If the client child has no parent, it must have been the
         // previous root node, so there is no LCA and we can exit early.
         *out_lca = tree_->GetNull();
         return true;
-      } else if (client_child->parent->id != id) {
+      } else if (parent->id != id) {
         // If the client child's parent is not this node, update the LCA
         // and return true (reparenting was found).
         *out_lca = LeastCommonAncestor(*out_lca, client_child);
@@ -367,6 +373,19 @@
 }
 
 template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
+ClientTreeNode*
+AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::GetClientTreeNodeParent(
+    ClientTreeNode* obj) {
+  ClientTreeNode* parent = obj->parent;
+#if DCHECK_IS_ON()
+  if (!parent)
+    return nullptr;
+  DCHECK(ClientTreeNodeById(parent->id)) << "Parent not in id map.";
+#endif  // DCHECK_IS_ON()
+  return parent;
+}
+
+template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
 bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::SerializeChanges(
     AXSourceNode node,
     AXTreeUpdateBase<AXNodeData, AXTreeData>* out_update) {
@@ -549,7 +568,7 @@
     // above. If this happens, reset and return an error.
 
     ClientTreeNode* client_child = ClientTreeNodeById(new_child_id);
-    if (client_child && client_child->parent != client_node) {
+    if (client_child && GetClientTreeNodeParent(client_child) != client_node) {
       DVLOG(1) << "Illegal reparenting detected";
 #if defined(ADDRESS_SANITIZER)
       // Wrapping this in ADDRESS_SANITIZER will cause it to run on
diff --git a/ui/base/cocoa/command_dispatcher.h b/ui/base/cocoa/command_dispatcher.h
index 0fca888..91f7d54 100644
--- a/ui/base/cocoa/command_dispatcher.h
+++ b/ui/base/cocoa/command_dispatcher.h
@@ -58,6 +58,9 @@
 - (void)dispatchUsingKeyModifiers:(id)sender
                        forHandler:(id<UserInterfaceItemCommandHandler>)handler;
 
+// TODO(bokan): Temporary to help debug https://crbug.com/1039833.
+- (BOOL)isRedispatchingKeyEvent;
+
 @end
 
 // If the NSWindow's firstResponder implements CommandDispatcherTarget, then
diff --git a/ui/base/cocoa/command_dispatcher.mm b/ui/base/cocoa/command_dispatcher.mm
index 506ab361..50a0232 100644
--- a/ui/base/cocoa/command_dispatcher.mm
+++ b/ui/base/cocoa/command_dispatcher.mm
@@ -250,6 +250,10 @@
     [[self bubbleParent] commandDispatchUsingKeyModifiers:sender];
 }
 
+- (BOOL)isRedispatchingKeyEvent {
+  return _isRedispatchingKeyEvent;
+}
+
 - (NSWindow<CommandDispatchingWindow>*)bubbleParent {
   NSWindow* parent = [_owner parentWindow];
   if (parent && [parent hasKeyAppearance] &&
diff --git a/ui/display/mojom/BUILD.gn b/ui/display/mojom/BUILD.gn
index a759490..41443e6 100644
--- a/ui/display/mojom/BUILD.gn
+++ b/ui/display/mojom/BUILD.gn
@@ -21,4 +21,55 @@
     "//ui/gfx/geometry/mojom",
     "//ui/gfx/mojom",
   ]
+
+  shared_cpp_typemaps = [
+    {
+      types = [
+        {
+          mojom = "display.mojom.Rotation"
+          cpp = "::display::Display::Rotation"
+        },
+      ]
+      traits_headers = [ "display_mojom_traits.h" ]
+      traits_public_deps = [ ":shared_mojom_traits" ]
+    },
+  ]
+
+  cpp_typemaps = [
+    {
+      types = [
+        {
+          mojom = "display.mojom.Display"
+          cpp = "::display::Display"
+        },
+        {
+          mojom = "display.mojom.TouchSupport"
+          cpp = "::display::Display::TouchSupport"
+        },
+        {
+          mojom = "display.mojom.AccelerometerSupport"
+          cpp = "::display::Display::AccelerometerSupport"
+        },
+      ]
+      traits_headers = [ "display_mojom_traits.h" ]
+      traits_public_deps = [ ":shared_mojom_traits" ]
+    },
+  ]
+  cpp_typemaps += shared_cpp_typemaps
+  blink_cpp_typemaps = shared_cpp_typemaps
+}
+
+component("shared_mojom_traits") {
+  output_name = "display_shared_mojom_traits"
+  defines = [ "IS_DISPLAY_SHARED_MOJOM_TRAITS_IMPL" ]
+  sources = [
+    "display_mojom_traits.cc",
+    "display_mojom_traits.h",
+  ]
+  public_deps = [
+    ":mojom_shared",
+    "//base",
+    "//ui/display",
+    "//ui/gfx/mojom",
+  ]
 }
diff --git a/ui/display/mojom/display.typemap b/ui/display/mojom/display.typemap
deleted file mode 100644
index a9f2662..0000000
--- a/ui/display/mojom/display.typemap
+++ /dev/null
@@ -1,24 +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.
-
-mojom = "//ui/display/mojom/display.mojom"
-public_headers = [ "//ui/display/display.h" ]
-traits_headers = [ "//ui/display/mojom/display_mojom_traits.h" ]
-sources = [
-  "//ui/display/mojom/display_mojom_traits.cc",
-]
-public_deps = [
-  "//ui/display",
-]
-deps = [
-  "//ui/gfx/geometry",
-  "//ui/gfx/geometry/mojom:mojom_traits",
-]
-
-type_mappings = [
-  "display.mojom.Display=::display::Display",
-  "display.mojom.Rotation=::display::Display::Rotation",
-  "display.mojom.TouchSupport=::display::Display::TouchSupport",
-  "display.mojom.AccelerometerSupport=::display::Display::AccelerometerSupport",
-]
diff --git a/ui/display/mojom/display_mojom_traits.h b/ui/display/mojom/display_mojom_traits.h
index 303908e..fbd0f30 100644
--- a/ui/display/mojom/display_mojom_traits.h
+++ b/ui/display/mojom/display_mojom_traits.h
@@ -5,23 +5,25 @@
 #ifndef UI_DISPLAY_MOJOM_DISPLAY_MOJOM_TRAITS_H_
 #define UI_DISPLAY_MOJOM_DISPLAY_MOJOM_TRAITS_H_
 
+#include "base/component_export.h"
 #include "ui/display/display.h"
-#include "ui/display/mojom/display.mojom.h"
+#include "ui/display/mojom/display.mojom-shared.h"
 #include "ui/gfx/geometry/mojom/geometry_mojom_traits.h"
 #include "ui/gfx/mojom/display_color_spaces_mojom_traits.h"
 
 namespace mojo {
 
 template <>
-struct EnumTraits<display::mojom::Rotation, display::Display::Rotation> {
+struct COMPONENT_EXPORT(DISPLAY_SHARED_MOJOM_TRAITS)
+    EnumTraits<display::mojom::Rotation, display::Display::Rotation> {
   static display::mojom::Rotation ToMojom(display::Display::Rotation type);
   static bool FromMojom(display::mojom::Rotation type,
                         display::Display::Rotation* output);
 };
 
 template <>
-struct EnumTraits<display::mojom::TouchSupport,
-                  display::Display::TouchSupport> {
+struct COMPONENT_EXPORT(DISPLAY_SHARED_MOJOM_TRAITS)
+    EnumTraits<display::mojom::TouchSupport, display::Display::TouchSupport> {
   static display::mojom::TouchSupport ToMojom(
       display::Display::TouchSupport type);
   static bool FromMojom(display::mojom::TouchSupport type,
@@ -29,8 +31,9 @@
 };
 
 template <>
-struct EnumTraits<display::mojom::AccelerometerSupport,
-                  display::Display::AccelerometerSupport> {
+struct COMPONENT_EXPORT(DISPLAY_SHARED_MOJOM_TRAITS)
+    EnumTraits<display::mojom::AccelerometerSupport,
+               display::Display::AccelerometerSupport> {
   static display::mojom::AccelerometerSupport ToMojom(
       display::Display::AccelerometerSupport type);
   static bool FromMojom(display::mojom::AccelerometerSupport type,
@@ -38,7 +41,8 @@
 };
 
 template <>
-struct StructTraits<display::mojom::DisplayDataView, display::Display> {
+struct COMPONENT_EXPORT(DISPLAY_SHARED_MOJOM_TRAITS)
+    StructTraits<display::mojom::DisplayDataView, display::Display> {
   static int64_t id(const display::Display& display) { return display.id(); }
 
   static const gfx::Rect& bounds(const display::Display& display) {
diff --git a/ui/display/mojom/display_mojom_traits_unittest.cc b/ui/display/mojom/display_mojom_traits_unittest.cc
index 5b2f092..dd4e5f96 100644
--- a/ui/display/mojom/display_mojom_traits_unittest.cc
+++ b/ui/display/mojom/display_mojom_traits_unittest.cc
@@ -12,6 +12,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/display/display.h"
 #include "ui/display/display_layout.h"
+#include "ui/display/mojom/display.mojom.h"
 #include "ui/display/mojom/display_layout_mojom_traits.h"
 #include "ui/display/mojom/display_mode_mojom_traits.h"
 #include "ui/display/mojom/display_mojom_traits.h"
diff --git a/ui/display/mojom/display_rotation_for_blink.typemap b/ui/display/mojom/display_rotation_for_blink.typemap
deleted file mode 100644
index b370d03..0000000
--- a/ui/display/mojom/display_rotation_for_blink.typemap
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright 2018 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//ui/display/mojom/display.mojom"
-public_headers = [ "//ui/display/display.h" ]
-traits_headers = [ "//ui/display/mojom/display_mojom_traits.h" ]
-public_deps = [
-  "//ui/display",
-  "//ui/display/mojom:mojom",
-]
-type_mappings = [ "display.mojom.Rotation=::display::Display::Rotation" ]
diff --git a/ui/display/mojom/typemaps.gni b/ui/display/mojom/typemaps.gni
index 1cbc47b1..25abdcd 100644
--- a/ui/display/mojom/typemaps.gni
+++ b/ui/display/mojom/typemaps.gni
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 
 typemaps = [
-  "//ui/display/mojom/display.typemap",
   "//ui/display/mojom/display_constants.typemap",
   "//ui/display/mojom/display_layout.typemap",
   "//ui/display/mojom/display_mode.typemap",
diff --git a/ui/events/gestures/blink/web_gesture_curve_impl.cc b/ui/events/gestures/blink/web_gesture_curve_impl.cc
index a02f80b..fd3f9615 100644
--- a/ui/events/gestures/blink/web_gesture_curve_impl.cc
+++ b/ui/events/gestures/blink/web_gesture_curve_impl.cc
@@ -33,7 +33,8 @@
     const gfx::Vector2dF& initial_velocity,
     bool use_mobile_fling_curve,
     const gfx::PointF& position_in_screen,
-    const gfx::Size& viewport_size) {
+    const float boost_multiplier,
+    const gfx::Size& bounding_size) {
   if (device_source == blink::WebGestureDevice::kSyntheticAutoscroll) {
     return std::make_unique<FixedVelocityCurve>(initial_velocity,
                                                 base::TimeTicks());
@@ -62,7 +63,8 @@
         display::win::ScreenWin::GetPixelsPerInch(position_in_screen);
 #endif  // define(OS_WIN)
     return std::make_unique<PhysicsBasedFlingCurve>(
-        initial_velocity, base::TimeTicks(), pixels_per_inch, viewport_size);
+        initial_velocity, base::TimeTicks(), pixels_per_inch, boost_multiplier,
+        bounding_size);
   }
 
   return std::make_unique<FlingCurve>(initial_velocity, base::TimeTicks());
@@ -79,11 +81,12 @@
     bool on_main_thread,
     bool use_mobile_fling_curve,
     const gfx::PointF& position_in_screen,
+    const float boost_multiplier,
     const gfx::Size& viewport_size) {
   return std::unique_ptr<WebGestureCurve>(new WebGestureCurveImpl(
       CreateDefaultPlatformCurve(device_source, initial_velocity,
                                  use_mobile_fling_curve, position_in_screen,
-                                 viewport_size),
+                                 boost_multiplier, viewport_size),
       initial_offset, on_main_thread ? ThreadType::MAIN : ThreadType::IMPL));
 }
 
diff --git a/ui/events/gestures/blink/web_gesture_curve_impl.h b/ui/events/gestures/blink/web_gesture_curve_impl.h
index 5d97c047..a5bfc61d 100644
--- a/ui/events/gestures/blink/web_gesture_curve_impl.h
+++ b/ui/events/gestures/blink/web_gesture_curve_impl.h
@@ -24,12 +24,19 @@
  public:
   static std::unique_ptr<blink::WebGestureCurve> CreateFromDefaultPlatformCurve(
       blink::WebGestureDevice device_source,
+      // Initial velocity has boost_multiplier from fling booster already
+      // applied
       const gfx::Vector2dF& initial_velocity,
       const gfx::Vector2dF& initial_offset,
       bool on_main_thread,
       bool use_mobile_fling_curve,
       const gfx::PointF& position_in_screen,
-      const gfx::Size& viewport_szie);
+      // Multiplier for fling distance based on fling boosting. Used in physics
+      // based fling curve
+      const float boost_multiplier,
+      // Maximum fling distance subject to boost_multiplier and default
+      // bounds multiplier. Used in physics based fling curve
+      const gfx::Size& bounding_size);
   static std::unique_ptr<blink::WebGestureCurve> CreateFromUICurveForTesting(
       std::unique_ptr<GestureCurve> curve,
       const gfx::Vector2dF& initial_offset);
diff --git a/ui/events/gestures/physics_based_fling_curve.cc b/ui/events/gestures/physics_based_fling_curve.cc
index a46f783..c5414cd5 100644
--- a/ui/events/gestures/physics_based_fling_curve.cc
+++ b/ui/events/gestures/physics_based_fling_curve.cc
@@ -54,7 +54,7 @@
 // generate fling animation curve.
 gfx::Vector2dF CalculateEndPoint(const gfx::Vector2dF& pixels_per_inch,
                                  const gfx::Vector2dF& velocity_pixels_per_ms,
-                                 const gfx::Size& viewport) {
+                                 const gfx::Size& bounding_size) {
   // deceleration is in pixels/ ms^2.
   gfx::Vector2dF deceleration = GetDecelerationInPixelsPerMs2(pixels_per_inch);
 
@@ -66,18 +66,14 @@
       GetOffset(velocity_pixels_per_ms.x(), deceleration.x(), duration.x()),
       GetOffset(velocity_pixels_per_ms.y(), deceleration.y(), duration.y()));
 
-  // Upper bound for the scroll distance for a fling
-  gfx::Vector2dF max_end_point =
-      gfx::Vector2dF(3 * viewport.width(), 3 * viewport.height());
-
-  if (std::abs(offset_in_screen_coord_space.x()) > max_end_point.x()) {
+  if (std::abs(offset_in_screen_coord_space.x()) > bounding_size.width()) {
     float sign = offset_in_screen_coord_space.x() > 0 ? 1 : -1;
-    offset_in_screen_coord_space.set_x(max_end_point.x() * sign);
+    offset_in_screen_coord_space.set_x(bounding_size.width() * sign);
   }
 
-  if (std::abs(offset_in_screen_coord_space.y()) > max_end_point.y()) {
+  if (std::abs(offset_in_screen_coord_space.y()) > bounding_size.height()) {
     float sign = offset_in_screen_coord_space.y() > 0 ? 1 : -1;
-    offset_in_screen_coord_space.set_y(max_end_point.y() * sign);
+    offset_in_screen_coord_space.set_y(bounding_size.height() * sign);
   }
 
   return offset_in_screen_coord_space;
@@ -91,13 +87,16 @@
     const gfx::Vector2dF& velocity,
     base::TimeTicks start_timestamp,
     const gfx::Vector2dF& pixels_per_inch,
-    const gfx::Size& viewport)
+    const float boost_multiplier,
+    const gfx::Size& bounding_size)
     : start_timestamp_(start_timestamp),
       p1_(gfx::PointF(kDefaultP1X, kDefaultP1Y)),
       p2_(gfx::PointF(kDefaultP2X, kDefaultP2Y)),
-      distance_(CalculateEndPoint(pixels_per_inch,
-                                  gfx::ScaleVector2d(velocity, 1 / 1000.0f),
-                                  viewport)),
+      distance_(CalculateEndPoint(
+          pixels_per_inch,
+          gfx::ScaleVector2d(velocity, 1 / 1000.0f),
+          ScaleToFlooredSize(bounding_size,
+                             boost_multiplier * kDefaultBoundsMultiplier))),
       curve_duration_(CalculateDurationAndConfigureControlPoints(velocity)),
       bezier_(p1_.x(), p1_.y(), p2_.x(), p2_.y()),
       previous_time_delta_(base::TimeDelta()) {
diff --git a/ui/events/gestures/physics_based_fling_curve.h b/ui/events/gestures/physics_based_fling_curve.h
index 38af2bf..4d4bfc7 100644
--- a/ui/events/gestures/physics_based_fling_curve.h
+++ b/ui/events/gestures/physics_based_fling_curve.h
@@ -21,10 +21,15 @@
 // suitable for touch screen-based flings.
 class EVENTS_BASE_EXPORT PhysicsBasedFlingCurve : public GestureCurve {
  public:
-  PhysicsBasedFlingCurve(const gfx::Vector2dF& velocity,
-                         base::TimeTicks start_timestamp,
-                         const gfx::Vector2dF& pixels_per_inch,
-                         const gfx::Size& viewport);
+  PhysicsBasedFlingCurve(
+      const gfx::Vector2dF& velocity,
+      base::TimeTicks start_timestamp,
+      const gfx::Vector2dF& pixels_per_inch,
+      // Multiplier for fling distance based on fling boosting
+      const float boost_multiplier,
+      // Maximum fling distance subject to boost_multiplier and default
+      // bounds multiplier
+      const gfx::Size& bounding_size);
   ~PhysicsBasedFlingCurve() override;
 
   // GestureCurve implementation.
@@ -35,6 +40,9 @@
   float curve_duration() const { return curve_duration_; }
   const gfx::PointF& p1_for_testing() const { return p1_; }
   const gfx::PointF& p2_for_testing() const { return p2_; }
+  static int default_bounds_multiplier_for_testing() {
+    return kDefaultBoundsMultiplier;
+  }
 
  private:
   // Time when fling curve is generated.
@@ -50,6 +58,12 @@
   // crrev.com/c/1865928 is merged.
   // crbug.com/1028501
   const float curve_duration_;
+
+  // Default value used to scale the viewport when it is passed in as a
+  // parameter in the generation of a physics based fling curve. This value
+  // increases the upper bound of the scroll distance for a fling.
+  constexpr static int kDefaultBoundsMultiplier = 3;
+
   const gfx::CubicBezier bezier_;
   base::TimeDelta previous_time_delta_;
   gfx::Vector2dF cumulative_scroll_;
diff --git a/ui/events/gestures/physics_based_fling_curve_unittest.cc b/ui/events/gestures/physics_based_fling_curve_unittest.cc
index f954d6d0..010da57 100644
--- a/ui/events/gestures/physics_based_fling_curve_unittest.cc
+++ b/ui/events/gestures/physics_based_fling_curve_unittest.cc
@@ -9,6 +9,7 @@
 namespace ui {
 
 const float kDefaultPixelsPerInch = 96.f;
+const float kBoostMultiplierUnboosted = 1.f;
 
 TEST(PhysicsBasedFlingCurveTest, BasicFlingTestVelocityY) {
   const gfx::Vector2dF fling_velocity(0, 5000);
@@ -17,7 +18,8 @@
                                        kDefaultPixelsPerInch);
   const gfx::Size viewport(1920, 1080);
 
-  PhysicsBasedFlingCurve curve(fling_velocity, now, pixels_per_inch, viewport);
+  PhysicsBasedFlingCurve curve(fling_velocity, now, pixels_per_inch,
+                               kBoostMultiplierUnboosted, viewport);
 
   gfx::Vector2dF offset;
   gfx::Vector2dF velocity;
@@ -66,7 +68,8 @@
                                        kDefaultPixelsPerInch);
   const gfx::Size viewport(1920, 1080);
 
-  PhysicsBasedFlingCurve curve(fling_velocity, now, pixels_per_inch, viewport);
+  PhysicsBasedFlingCurve curve(fling_velocity, now, pixels_per_inch,
+                               kBoostMultiplierUnboosted, viewport);
 
   gfx::Vector2dF offset;
   gfx::Vector2dF velocity;
@@ -114,7 +117,8 @@
                                        kDefaultPixelsPerInch);
   const gfx::Size viewport(1920, 1080);
 
-  PhysicsBasedFlingCurve curve(fling_velocity, now, pixels_per_inch, viewport);
+  PhysicsBasedFlingCurve curve(fling_velocity, now, pixels_per_inch,
+                               kBoostMultiplierUnboosted, viewport);
 
   gfx::Vector2dF offset;
   gfx::Vector2dF velocity;
@@ -162,7 +166,8 @@
                                        kDefaultPixelsPerInch);
   const gfx::Size viewport(1920, 1080);
 
-  PhysicsBasedFlingCurve curve(velocity, now, pixels_per_inch, viewport);
+  PhysicsBasedFlingCurve curve(velocity, now, pixels_per_inch,
+                               kBoostMultiplierUnboosted, viewport);
 
   EXPECT_EQ(0.20f, curve.p1_for_testing().x());
   EXPECT_NEAR(curve.p1_for_testing().y(), 0.43f, 0.01f);
@@ -177,7 +182,8 @@
                                        kDefaultPixelsPerInch);
   const gfx::Size viewport(1920, 1080);
 
-  PhysicsBasedFlingCurve curve(velocity, now, pixels_per_inch, viewport);
+  PhysicsBasedFlingCurve curve(velocity, now, pixels_per_inch,
+                               kBoostMultiplierUnboosted, viewport);
 
   EXPECT_NEAR(curve.p1_for_testing().x(), 0.19f, 0.01f);
   EXPECT_EQ(curve.p1_for_testing().y(), 1.0f);
diff --git a/ui/gfx/geometry/mojom/BUILD.gn b/ui/gfx/geometry/mojom/BUILD.gn
index 4731f08..5bb3781 100644
--- a/ui/gfx/geometry/mojom/BUILD.gn
+++ b/ui/gfx/geometry/mojom/BUILD.gn
@@ -11,6 +11,72 @@
   sources = [ "geometry.mojom" ]
 
   check_includes_blink = false
+
+  shared_cpp_typemap = {
+    types = [
+      {
+        mojom = "gfx.mojom.Point"
+        cpp = "::gfx::Point"
+      },
+      {
+        mojom = "gfx.mojom.PointF"
+        cpp = "::gfx::PointF"
+      },
+      {
+        mojom = "gfx.mojom.Point3F"
+        cpp = "::gfx::Point3F"
+      },
+      {
+        mojom = "gfx.mojom.Size"
+        cpp = "::gfx::Size"
+      },
+      {
+        mojom = "gfx.mojom.SizeF"
+        cpp = "::gfx::SizeF"
+      },
+      {
+        mojom = "gfx.mojom.Rect"
+        cpp = "::gfx::Rect"
+      },
+      {
+        mojom = "gfx.mojom.RectF"
+        cpp = "::gfx::RectF"
+      },
+      {
+        mojom = "gfx.mojom.Insets"
+        cpp = "::gfx::Insets"
+      },
+      {
+        mojom = "gfx.mojom.InsetsF"
+        cpp = "::gfx::InsetsF"
+      },
+      {
+        mojom = "gfx.mojom.Quaternion"
+        cpp = "::gfx::Quaternion"
+      },
+      {
+        mojom = "gfx.mojom.Vector2d"
+        cpp = "::gfx::Vector2d"
+      },
+      {
+        mojom = "gfx.mojom.Vector2dF"
+        cpp = "::gfx::Vector2dF"
+      },
+      {
+        mojom = "gfx.mojom.Vector3dF"
+        cpp = "::gfx::Vector3dF"
+      },
+      {
+        mojom = "gfx.mojom.ScrollOffset"
+        cpp = "::gfx::ScrollOffset"
+      },
+    ]
+
+    traits_headers = [ "geometry_mojom_traits.h" ]
+    traits_public_deps = [ ":mojom_traits" ]
+  }
+  cpp_typemaps = [ shared_cpp_typemap ]
+  blink_cpp_typemaps = [ shared_cpp_typemap ]
 }
 
 mojom("test_interfaces") {
@@ -37,7 +103,7 @@
 source_set("mojom_traits") {
   sources = [ "geometry_mojom_traits.h" ]
   public_deps = [
-    ":mojom_shared_cpp_sources",
+    ":mojom_shared",
     "//ui/gfx/geometry",
   ]
 }
diff --git a/ui/gfx/geometry/mojom/geometry.typemap b/ui/gfx/geometry/mojom/geometry.typemap
deleted file mode 100644
index 7897c92..0000000
--- a/ui/gfx/geometry/mojom/geometry.typemap
+++ /dev/null
@@ -1,40 +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.
-
-mojom = "//ui/gfx/geometry/mojom/geometry.mojom"
-public_headers = [
-  "//ui/gfx/geometry/point.h",
-  "//ui/gfx/geometry/point_f.h",
-  "//ui/gfx/geometry/point3_f.h",
-  "//ui/gfx/geometry/size.h",
-  "//ui/gfx/geometry/rect.h",
-  "//ui/gfx/geometry/rect_f.h",
-  "//ui/gfx/geometry/safe_integer_conversions.h",
-  "//ui/gfx/geometry/scroll_offset.h",
-  "//ui/gfx/geometry/insets.h",
-  "//ui/gfx/geometry/quaternion.h",
-  "//ui/gfx/geometry/vector2d.h",
-  "//ui/gfx/geometry/vector2d_f.h",
-  "//ui/gfx/geometry/vector3d_f.h",
-]
-traits_headers = [ "//ui/gfx/geometry/mojom/geometry_mojom_traits.h" ]
-public_deps = [
-  "//ui/gfx/geometry/mojom:mojom_traits",
-]
-type_mappings = [
-  "gfx.mojom.Point=::gfx::Point",
-  "gfx.mojom.PointF=::gfx::PointF",
-  "gfx.mojom.Point3F=::gfx::Point3F",
-  "gfx.mojom.Size=::gfx::Size",
-  "gfx.mojom.SizeF=::gfx::SizeF",
-  "gfx.mojom.Rect=::gfx::Rect",
-  "gfx.mojom.RectF=::gfx::RectF",
-  "gfx.mojom.Insets=::gfx::Insets",
-  "gfx.mojom.InsetsF=::gfx::InsetsF",
-  "gfx.mojom.Quaternion=::gfx::Quaternion",
-  "gfx.mojom.Vector2d=::gfx::Vector2d",
-  "gfx.mojom.Vector2dF=::gfx::Vector2dF",
-  "gfx.mojom.Vector3dF=::gfx::Vector3dF",
-  "gfx.mojom.ScrollOffset=::gfx::ScrollOffset",
-]
diff --git a/ui/gfx/mojom/BUILD.gn b/ui/gfx/mojom/BUILD.gn
index f6fffd3..cd30b12 100644
--- a/ui/gfx/mojom/BUILD.gn
+++ b/ui/gfx/mojom/BUILD.gn
@@ -29,43 +29,76 @@
     "//ui/gfx/geometry/mojom",
   ]
 
-  buffer_types_shared_cpp_typemap = {
-    types = [
-      {
-        mojom = "gfx.mojom.BufferFormat"
-        cpp = "::gfx::BufferFormat"
-      },
-      {
-        mojom = "gfx.mojom.BufferUsage"
-        cpp = "::gfx::BufferUsage"
-      },
-      {
-        mojom = "gfx.mojom.BufferUsageAndFormat"
-        cpp = "::gfx::BufferUsageAndFormat"
-      },
-      {
-        mojom = "gfx.mojom.GpuMemoryBufferHandle"
-        cpp = "::gfx::GpuMemoryBufferHandle"
-        move_only = true
-        nullable_is_same_type = true
-      },
-      {
-        mojom = "gfx.mojom.GpuMemoryBufferId"
-        cpp = "::gfx::GpuMemoryBufferId"
-        copyable_pass_by_value = true
-      },
-      {
-        mojom = "gfx.mojom.GpuMemoryBufferType"
-        cpp = "::gfx::GpuMemoryBufferType"
-      },
-    ]
+  shared_cpp_typemaps = [
+    {
+      types = [
+        {
+          mojom = "gfx.mojom.BufferFormat"
+          cpp = "::gfx::BufferFormat"
+        },
+        {
+          mojom = "gfx.mojom.BufferUsage"
+          cpp = "::gfx::BufferUsage"
+        },
+        {
+          mojom = "gfx.mojom.BufferUsageAndFormat"
+          cpp = "::gfx::BufferUsageAndFormat"
+        },
+        {
+          mojom = "gfx.mojom.GpuMemoryBufferHandle"
+          cpp = "::gfx::GpuMemoryBufferHandle"
+          move_only = true
+          nullable_is_same_type = true
+        },
+        {
+          mojom = "gfx.mojom.GpuMemoryBufferId"
+          cpp = "::gfx::GpuMemoryBufferId"
+          copyable_pass_by_value = true
+        },
+        {
+          mojom = "gfx.mojom.GpuMemoryBufferType"
+          cpp = "::gfx::GpuMemoryBufferType"
+        },
+      ]
 
-    traits_headers = [ "buffer_types_mojom_traits.h" ]
-    traits_public_deps = [ ":shared_mojom_traits" ]
-  }
+      traits_headers = [ "buffer_types_mojom_traits.h" ]
+      traits_public_deps = [ ":shared_mojom_traits" ]
+    },
+    {
+      types = [
+        {
+          mojom = "gfx.mojom.ColorSpace"
+          cpp = "::gfx::ColorSpace"
+        },
+      ]
+      traits_headers = [ "color_space_mojom_traits.h" ]
+      traits_public_deps = [ ":color_space_mojom_support" ]
+    },
+    {
+      types = [
+        {
+          mojom = "gfx.mojom.GpuFenceHandle"
+          cpp = "::gfx::GpuFenceHandle"
+        },
+      ]
+      traits_headers = [ "gpu_fence_handle_mojom_traits.h" ]
+      traits_public_deps = [ ":shared_mojom_traits" ]
+    },
+    {
+      types = [
+        {
+          mojom = "gfx.mojom.Transform"
+          cpp = "::gfx::Transform"
+        },
+      ]
+      traits_headers = [ "transform_mojom_traits.h" ]
+      traits_public_deps = [ "//ui/gfx" ]
+    },
+  ]
 
-  cpp_typemaps = [ buffer_types_shared_cpp_typemap ]
-  blink_cpp_typemaps = [ buffer_types_shared_cpp_typemap ]
+  cpp_typemaps = []
+  cpp_typemaps = shared_cpp_typemaps
+  blink_cpp_typemaps = shared_cpp_typemaps
 }
 
 mojom("native_handle_types") {
@@ -136,6 +169,8 @@
   sources = [
     "buffer_types_mojom_traits.cc",
     "buffer_types_mojom_traits.h",
+    "gpu_fence_handle_mojom_traits.cc",
+    "gpu_fence_handle_mojom_traits.h",
   ]
   public_deps = [
     ":mojom_shared",
diff --git a/ui/gfx/mojom/color_space.typemap b/ui/gfx/mojom/color_space.typemap
deleted file mode 100644
index 79ec50a..0000000
--- a/ui/gfx/mojom/color_space.typemap
+++ /dev/null
@@ -1,9 +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.
-
-mojom = "//ui/gfx/mojom/color_space.mojom"
-public_headers = [ "//ui/gfx/color_space.h" ]
-traits_headers = [ "//ui/gfx/mojom/color_space_mojom_traits.h" ]
-public_deps = [ "//ui/gfx/mojom:color_space_mojom_support" ]
-type_mappings = [ "gfx.mojom.ColorSpace=::gfx::ColorSpace" ]
diff --git a/ui/gfx/mojom/gpu_fence_handle.typemap b/ui/gfx/mojom/gpu_fence_handle.typemap
deleted file mode 100644
index ef97ab51..0000000
--- a/ui/gfx/mojom/gpu_fence_handle.typemap
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//ui/gfx/mojom/gpu_fence_handle.mojom"
-public_headers = [ "//ui/gfx/gpu_fence_handle.h" ]
-traits_headers = [ "//ui/gfx/mojom/gpu_fence_handle_mojom_traits.h" ]
-sources = [
-  "//ui/gfx/mojom/gpu_fence_handle_mojom_traits.cc",
-]
-deps = [
-  "//ui/gfx",
-]
-type_mappings = [ "gfx.mojom.GpuFenceHandle=::gfx::GpuFenceHandle" ]
diff --git a/ui/gfx/mojom/gpu_fence_handle_for_blink.typemap b/ui/gfx/mojom/gpu_fence_handle_for_blink.typemap
deleted file mode 100644
index c6540e8..0000000
--- a/ui/gfx/mojom/gpu_fence_handle_for_blink.typemap
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//ui/gfx/mojom/gpu_fence_handle.mojom"
-public_headers = [ "//ui/gfx/gpu_fence_handle.h" ]
-traits_headers = [ "//ui/gfx/mojom/gpu_fence_handle_mojom_traits.h" ]
-public_deps = [
-  "//mojo/public/cpp/bindings",
-  "//ui/gfx/mojom",
-]
-type_mappings = [ "gfx.mojom.GpuFenceHandle=::gfx::GpuFenceHandle" ]
diff --git a/ui/gfx/mojom/gpu_fence_handle_mojom_traits.h b/ui/gfx/mojom/gpu_fence_handle_mojom_traits.h
index 74ef6032..f688b2cb 100644
--- a/ui/gfx/mojom/gpu_fence_handle_mojom_traits.h
+++ b/ui/gfx/mojom/gpu_fence_handle_mojom_traits.h
@@ -5,13 +5,15 @@
 #ifndef UI_GFX_MOJOM_GPU_FENCE_HANDLE_MOJOM_TRAITS_H_
 #define UI_GFX_MOJOM_GPU_FENCE_HANDLE_MOJOM_TRAITS_H_
 
+#include "base/component_export.h"
 #include "ui/gfx/gpu_fence_handle.h"
-#include "ui/gfx/mojom/gpu_fence_handle.mojom.h"
+#include "ui/gfx/mojom/gpu_fence_handle.mojom-shared.h"
 
 namespace mojo {
 
 template <>
-struct EnumTraits<gfx::mojom::GpuFenceHandleType, gfx::GpuFenceHandleType> {
+struct COMPONENT_EXPORT(GFX_SHARED_MOJOM_TRAITS)
+    EnumTraits<gfx::mojom::GpuFenceHandleType, gfx::GpuFenceHandleType> {
   static gfx::mojom::GpuFenceHandleType ToMojom(gfx::GpuFenceHandleType type) {
     switch (type) {
       case gfx::GpuFenceHandleType::kEmpty:
@@ -38,7 +40,8 @@
 };
 
 template <>
-struct StructTraits<gfx::mojom::GpuFenceHandleDataView, gfx::GpuFenceHandle> {
+struct COMPONENT_EXPORT(GFX_SHARED_MOJOM_TRAITS)
+    StructTraits<gfx::mojom::GpuFenceHandleDataView, gfx::GpuFenceHandle> {
   static gfx::GpuFenceHandleType type(const gfx::GpuFenceHandle& handle) {
     return handle.type;
   }
diff --git a/ui/gfx/mojom/transform.typemap b/ui/gfx/mojom/transform.typemap
deleted file mode 100644
index ff2bf8a..0000000
--- a/ui/gfx/mojom/transform.typemap
+++ /dev/null
@@ -1,8 +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.
-
-mojom = "//ui/gfx/mojom/transform.mojom"
-public_headers = [ "//ui/gfx/transform.h" ]
-traits_headers = [ "//ui/gfx/mojom/transform_mojom_traits.h" ]
-type_mappings = [ "gfx.mojom.Transform=::gfx::Transform" ]
diff --git a/ui/gfx/typemaps.gni b/ui/gfx/typemaps.gni
index 4646e0cb..7b7f550 100644
--- a/ui/gfx/typemaps.gni
+++ b/ui/gfx/typemaps.gni
@@ -3,20 +3,16 @@
 # found in the LICENSE file.
 
 typemaps = [
-  "//ui/gfx/geometry/mojom/geometry.typemap",
   "//ui/gfx/image/mojom/image.typemap",
   "//ui/gfx/mojom/accelerated_widget.typemap",
   "//ui/gfx/mojom/ca_layer_params.typemap",
-  "//ui/gfx/mojom/color_space.typemap",
   "//ui/gfx/mojom/display_color_spaces.typemap",
   "//ui/gfx/mojom/font_render_params.typemap",
-  "//ui/gfx/mojom/gpu_fence_handle.typemap",
   "//ui/gfx/mojom/overlay_transform.typemap",
   "//ui/gfx/mojom/presentation_feedback.typemap",
   "//ui/gfx/mojom/rrect_f.typemap",
   "//ui/gfx/mojom/selection_bound.typemap",
   "//ui/gfx/mojom/swap_result.typemap",
   "//ui/gfx/mojom/swap_timings.typemap",
-  "//ui/gfx/mojom/transform.typemap",
   "//ui/gfx/range/mojom/range.typemap",
 ]
diff --git a/ui/views/controls/tree/tree_view.cc b/ui/views/controls/tree/tree_view.cc
index 01da559..a04aa78e 100644
--- a/ui/views/controls/tree/tree_view.cc
+++ b/ui/views/controls/tree/tree_view.cc
@@ -895,7 +895,7 @@
 
   } else {
     // !IsRoot(node)) && node->parent() != nullptr.
-    if (node->parent()->is_expanded()) {
+    if (IsExpanded(node->parent()->model_node())) {
       int depth = 0;
       row = GetRowForInternalNode(node, &depth);
       if (depth >= 0) {
diff --git a/ui/views/widget/widget_interactive_uitest.cc b/ui/views/widget/widget_interactive_uitest.cc
index b1369d7..8e8efbc3 100644
--- a/ui/views/widget/widget_interactive_uitest.cc
+++ b/ui/views/widget/widget_interactive_uitest.cc
@@ -307,10 +307,10 @@
   // Create widget 1 and expect the active window to be its window.
   View* focusable_view1 = new View;
   focusable_view1->SetFocusBehavior(View::FocusBehavior::ALWAYS);
-  Widget* widget1 = CreateTopLevelNativeWidget();
+  WidgetAutoclosePtr widget1(CreateTopLevelNativeWidget());
   widget1->GetContentsView()->AddChildView(focusable_view1);
   widget1->Show();
-  aura::Window* root_window1 = GetRootWindow(widget1);
+  aura::Window* root_window1 = GetRootWindow(widget1.get());
   focusable_view1->RequestFocus();
 
   EXPECT_TRUE(root_window1 != nullptr);
@@ -321,12 +321,12 @@
 
   // Create widget 2 and expect the active window to be its window.
   View* focusable_view2 = new View;
-  Widget* widget2 = CreateTopLevelNativeWidget();
+  WidgetAutoclosePtr widget2(CreateTopLevelNativeWidget());
   widget1->GetContentsView()->AddChildView(focusable_view2);
   widget2->Show();
-  aura::Window* root_window2 = GetRootWindow(widget2);
+  aura::Window* root_window2 = GetRootWindow(widget2.get());
   focusable_view2->RequestFocus();
-  ActivatePlatformWindow(widget2);
+  ActivatePlatformWindow(widget2.get());
 
   wm::ActivationClient* activation_client2 =
       wm::GetActivationClient(root_window2);
@@ -338,18 +338,15 @@
   // Now set focus back to widget 1 and expect the active window to be its
   // window.
   focusable_view1->RequestFocus();
-  ActivatePlatformWindow(widget1);
+  ActivatePlatformWindow(widget1.get());
   EXPECT_EQ(activation_client2->GetActiveWindow(),
             reinterpret_cast<aura::Window*>(NULL));
   EXPECT_EQ(activation_client1->GetActiveWindow(), widget1->GetNativeView());
-
-  widget2->CloseNow();
-  widget1->CloseNow();
 }
 
 // Verifies bubbles result in a focus lost when shown.
 TEST_F(DesktopWidgetTestInteractive, FocusChangesOnBubble) {
-  Widget* widget = CreateTopLevelNativeWidget();
+  WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
   View* focusable_view =
       widget->GetContentsView()->AddChildView(std::make_unique<View>());
   focusable_view->SetFocusBehavior(View::FocusBehavior::ALWAYS);
@@ -376,8 +373,6 @@
 
   // Closing the bubble should result in focus going back to the contents view.
   EXPECT_TRUE(focusable_view->HasFocus());
-
-  widget->CloseNow();
 }
 
 class TouchEventHandler : public ui::EventHandler {
@@ -433,210 +428,23 @@
 
   View* focusable_view = new View;
   focusable_view->SetFocusBehavior(View::FocusBehavior::ALWAYS);
-  Widget* widget = CreateTopLevelNativeWidget();
+  WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
   widget->GetContentsView()->AddChildView(focusable_view);
   widget->Show();
 
   {
-    TouchEventHandler touch_event_handler(widget);
+    TouchEventHandler touch_event_handler(widget.get());
     ASSERT_TRUE(ui_controls::SendTouchEvents(ui_controls::PRESS, 1, 100, 100));
     touch_event_handler.WaitForEvents();
   }
-
-  widget->CloseNow();
 }
 
 #endif  // defined(OS_WIN)
 
-TEST_F(WidgetTestInteractive, CaptureAutoReset) {
-  Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
-  View* container = new View;
-  toplevel->SetContentsView(container);
-
-  EXPECT_FALSE(toplevel->HasCapture());
-  toplevel->SetCapture(nullptr);
-  EXPECT_TRUE(toplevel->HasCapture());
-
-  // By default, mouse release removes capture.
-  gfx::Point click_location(45, 15);
-  ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location,
-                         ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
-                         ui::EF_LEFT_MOUSE_BUTTON);
-  toplevel->OnMouseEvent(&release);
-  EXPECT_FALSE(toplevel->HasCapture());
-
-  // Now a mouse release shouldn't remove capture.
-  toplevel->set_auto_release_capture(false);
-  toplevel->SetCapture(nullptr);
-  EXPECT_TRUE(toplevel->HasCapture());
-  toplevel->OnMouseEvent(&release);
-  EXPECT_TRUE(toplevel->HasCapture());
-  toplevel->ReleaseCapture();
-  EXPECT_FALSE(toplevel->HasCapture());
-
-  toplevel->Close();
-  RunPendingMessages();
-}
-
-TEST_F(WidgetTestInteractive, ResetCaptureOnGestureEnd) {
-  Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
-  View* container = new View;
-  toplevel->SetContentsView(container);
-
-  View* gesture = new GestureCaptureView;
-  gesture->SetBounds(0, 0, 30, 30);
-  container->AddChildView(gesture);
-
-  MouseView* mouse = new MouseView;
-  mouse->SetBounds(30, 0, 30, 30);
-  container->AddChildView(mouse);
-
-  toplevel->SetSize(gfx::Size(100, 100));
-  toplevel->Show();
-
-  // Start a gesture on |gesture|.
-  ui::GestureEvent tap_down(15, 15, 0, base::TimeTicks(),
-                            ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
-  ui::GestureEvent end(15, 15, 0, base::TimeTicks(),
-                       ui::GestureEventDetails(ui::ET_GESTURE_END));
-  toplevel->OnGestureEvent(&tap_down);
-
-  // Now try to click on |mouse|. Since |gesture| will have capture, |mouse|
-  // will not receive the event.
-  gfx::Point click_location(45, 15);
-
-  ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
-                       ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
-                       ui::EF_LEFT_MOUSE_BUTTON);
-  ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location,
-                         ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
-                         ui::EF_LEFT_MOUSE_BUTTON);
-
-  EXPECT_TRUE(toplevel->HasCapture());
-
-  toplevel->OnMouseEvent(&press);
-  toplevel->OnMouseEvent(&release);
-  EXPECT_EQ(0, mouse->pressed());
-
-  EXPECT_FALSE(toplevel->HasCapture());
-
-  // The end of the gesture should release the capture, and pressing on |mouse|
-  // should now reach |mouse|.
-  toplevel->OnGestureEvent(&end);
-  toplevel->OnMouseEvent(&press);
-  toplevel->OnMouseEvent(&release);
-  EXPECT_EQ(1, mouse->pressed());
-
-  toplevel->Close();
-  RunPendingMessages();
-}
-
-// Checks that if a mouse-press triggers a capture on a different widget (which
-// consumes the mouse-release event), then the target of the press does not have
-// capture.
-TEST_F(WidgetTestInteractive, DisableCaptureWidgetFromMousePress) {
-  // The test creates two widgets: |first| and |second|.
-  // The View in |first| makes |second| visible, sets capture on it, and starts
-  // a nested loop (like a menu does). The View in |second| terminates the
-  // nested loop and closes the widget.
-  // The test sends a mouse-press event to |first|, and posts a task to send a
-  // release event to |second|, to make sure that the release event is
-  // dispatched after the nested loop starts.
-
-  Widget* first = CreateTopLevelFramelessPlatformWidget();
-  Widget* second = CreateTopLevelFramelessPlatformWidget();
-
-  NestedLoopCaptureView* container = new NestedLoopCaptureView(second);
-  first->SetContentsView(container);
-
-  second->SetContentsView(new ExitLoopOnRelease(container->GetQuitClosure()));
-
-  first->SetSize(gfx::Size(100, 100));
-  first->Show();
-
-  gfx::Point location(20, 20);
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          &Widget::OnMouseEvent, base::Unretained(second),
-          base::Owned(new ui::MouseEvent(
-              ui::ET_MOUSE_RELEASED, location, location, ui::EventTimeForNow(),
-              ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON))));
-  ui::MouseEvent press(ui::ET_MOUSE_PRESSED, location, location,
-                       ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
-                       ui::EF_LEFT_MOUSE_BUTTON);
-  first->OnMouseEvent(&press);
-  EXPECT_FALSE(first->HasCapture());
-  first->Close();
-  RunPendingMessages();
-}
-
-// Tests some grab/ungrab events.
-// TODO(estade): can this be enabled now that this is an interactive ui test?
-TEST_F(WidgetTestInteractive, DISABLED_GrabUngrab) {
-  Widget* toplevel = CreateTopLevelPlatformWidget();
-  Widget* child1 = CreateChildNativeWidgetWithParent(toplevel);
-  Widget* child2 = CreateChildNativeWidgetWithParent(toplevel);
-
-  toplevel->SetBounds(gfx::Rect(0, 0, 500, 500));
-
-  child1->SetBounds(gfx::Rect(10, 10, 300, 300));
-  View* view = new MouseView();
-  view->SetBounds(0, 0, 300, 300);
-  child1->GetRootView()->AddChildView(view);
-
-  child2->SetBounds(gfx::Rect(200, 10, 200, 200));
-  view = new MouseView();
-  view->SetBounds(0, 0, 200, 200);
-  child2->GetRootView()->AddChildView(view);
-
-  toplevel->Show();
-  RunPendingMessages();
-
-  // Click on child1
-  gfx::Point p1(45, 45);
-  ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1, ui::EventTimeForNow(),
-                         ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
-  toplevel->OnMouseEvent(&pressed);
-
-  EXPECT_TRUE(toplevel->HasCapture());
-  EXPECT_TRUE(child1->HasCapture());
-  EXPECT_FALSE(child2->HasCapture());
-
-  ui::MouseEvent released(ui::ET_MOUSE_RELEASED, p1, p1, ui::EventTimeForNow(),
-                          ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
-  toplevel->OnMouseEvent(&released);
-
-  EXPECT_FALSE(toplevel->HasCapture());
-  EXPECT_FALSE(child1->HasCapture());
-  EXPECT_FALSE(child2->HasCapture());
-
-  RunPendingMessages();
-
-  // Click on child2
-  gfx::Point p2(315, 45);
-  ui::MouseEvent pressed2(ui::ET_MOUSE_PRESSED, p2, p2, ui::EventTimeForNow(),
-                          ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
-  toplevel->OnMouseEvent(&pressed2);
-  EXPECT_TRUE(pressed2.handled());
-  EXPECT_TRUE(toplevel->HasCapture());
-  EXPECT_TRUE(child2->HasCapture());
-  EXPECT_FALSE(child1->HasCapture());
-
-  ui::MouseEvent released2(ui::ET_MOUSE_RELEASED, p2, p2, ui::EventTimeForNow(),
-                           ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
-  toplevel->OnMouseEvent(&released2);
-  EXPECT_FALSE(toplevel->HasCapture());
-  EXPECT_FALSE(child1->HasCapture());
-  EXPECT_FALSE(child2->HasCapture());
-
-  toplevel->CloseNow();
-}
-
 // Tests mouse move outside of the window into the "resize controller" and back
 // will still generate an OnMouseEntered and OnMouseExited event..
 TEST_F(WidgetTestInteractive, CheckResizeControllerEvents) {
-  Widget* toplevel = CreateTopLevelFramelessPlatformWidget();
+  WidgetAutoclosePtr toplevel(CreateTopLevelFramelessPlatformWidget());
 
   toplevel->SetBounds(gfx::Rect(0, 0, 100, 100));
 
@@ -678,20 +486,16 @@
   toplevel->OnMouseEvent(&moved_over);
   EXPECT_EQ(1, view->EnteredCalls());
   EXPECT_EQ(0, view->ExitedCalls());
-
-  RunPendingMessages();
-
-  toplevel->CloseNow();
 }
 
 // Test view focus restoration when a widget is deactivated and re-activated.
 TEST_F(WidgetTestInteractive, ViewFocusOnWidgetActivationChanges) {
-  Widget* widget1 = CreateTopLevelPlatformWidget();
+  WidgetAutoclosePtr widget1(CreateTopLevelPlatformWidget());
   View* view1 = new View;
   view1->SetFocusBehavior(View::FocusBehavior::ALWAYS);
   widget1->GetContentsView()->AddChildView(view1);
 
-  Widget* widget2 = CreateTopLevelPlatformWidget();
+  WidgetAutoclosePtr widget2(CreateTopLevelPlatformWidget());
   View* view2a = new View;
   View* view2b = new View;
   view2a->SetFocusBehavior(View::FocusBehavior::ALWAYS);
@@ -699,12 +503,12 @@
   widget2->GetContentsView()->AddChildView(view2a);
   widget2->GetContentsView()->AddChildView(view2b);
 
-  ShowSync(widget1);
+  ShowSync(widget1.get());
   EXPECT_TRUE(widget1->IsActive());
   view1->RequestFocus();
   EXPECT_EQ(view1, widget1->GetFocusManager()->GetFocusedView());
 
-  ShowSync(widget2);
+  ShowSync(widget2.get());
   EXPECT_TRUE(widget2->IsActive());
   EXPECT_FALSE(widget1->IsActive());
   EXPECT_EQ(nullptr, widget1->GetFocusManager()->GetFocusedView());
@@ -713,20 +517,17 @@
   view2b->RequestFocus();
   EXPECT_EQ(view2b, widget2->GetFocusManager()->GetFocusedView());
 
-  ActivateSync(widget1);
+  ActivateSync(widget1.get());
   EXPECT_TRUE(widget1->IsActive());
   EXPECT_EQ(view1, widget1->GetFocusManager()->GetFocusedView());
   EXPECT_FALSE(widget2->IsActive());
   EXPECT_EQ(nullptr, widget2->GetFocusManager()->GetFocusedView());
 
-  ActivateSync(widget2);
+  ActivateSync(widget2.get());
   EXPECT_TRUE(widget2->IsActive());
   EXPECT_EQ(view2b, widget2->GetFocusManager()->GetFocusedView());
   EXPECT_FALSE(widget1->IsActive());
   EXPECT_EQ(nullptr, widget1->GetFocusManager()->GetFocusedView());
-
-  widget1->CloseNow();
-  widget2->CloseNow();
 }
 
 // Test z-order of child widgets relative to their parent.
@@ -801,7 +602,7 @@
 
 // Test view focus retention when a widget's HWND is disabled and re-enabled.
 TEST_F(WidgetTestInteractive, ViewFocusOnHWNDEnabledChanges) {
-  Widget* widget = CreateTopLevelFramelessPlatformWidget();
+  WidgetAutoclosePtr widget(CreateTopLevelFramelessPlatformWidget());
   widget->SetContentsView(new View);
   for (size_t i = 0; i < 2; ++i) {
     auto child = std::make_unique<View>();
@@ -811,7 +612,7 @@
 
   widget->Show();
   widget->GetNativeWindow()->GetHost()->Show();
-  const HWND hwnd = HWNDForWidget(widget);
+  const HWND hwnd = HWNDForWidget(widget.get());
   EXPECT_TRUE(::IsWindow(hwnd));
   EXPECT_TRUE(::IsWindowEnabled(hwnd));
   EXPECT_EQ(hwnd, ::GetActiveWindow());
@@ -836,8 +637,6 @@
     EXPECT_TRUE(widget->IsActive());
     EXPECT_EQ(view, widget->GetFocusManager()->GetFocusedView());
   }
-
-  widget->CloseNow();
 }
 
 // This class subclasses the Widget class to listen for activation change
@@ -1089,61 +888,6 @@
 }
 #endif
 
-// Disabled on Mac. Desktop Mac doesn't have system modal windows since Carbon
-// was deprecated. It does have application modal windows, but only Ash requests
-// those.
-#if defined(OS_MACOSX)
-#define MAYBE_SystemModalWindowReleasesCapture \
-  DISABLED_SystemModalWindowReleasesCapture
-#elif defined(OS_CHROMEOS)
-// Investigate enabling for Chrome OS. It probably requires help from the window
-// service.
-#define MAYBE_SystemModalWindowReleasesCapture \
-  DISABLED_SystemModalWindowReleasesCapture
-#else
-#define MAYBE_SystemModalWindowReleasesCapture SystemModalWindowReleasesCapture
-#endif
-
-// Test that when opening a system-modal window, capture is released.
-TEST_F(DesktopWidgetTestInteractive, MAYBE_SystemModalWindowReleasesCapture) {
-  TestWidgetFocusChangeListener focus_listener;
-  WidgetFocusManager::GetInstance()->AddFocusChangeListener(&focus_listener);
-
-  // Create a top level widget.
-  Widget top_level_widget;
-  Widget::InitParams init_params =
-      CreateParams(Widget::InitParams::TYPE_WINDOW);
-  init_params.show_state = ui::SHOW_STATE_NORMAL;
-  gfx::Rect initial_bounds(0, 0, 500, 500);
-  init_params.bounds = initial_bounds;
-  init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  top_level_widget.Init(std::move(init_params));
-  ShowSync(&top_level_widget);
-
-  ASSERT_FALSE(focus_listener.focus_changes().empty());
-  EXPECT_EQ(top_level_widget.GetNativeView(),
-            focus_listener.focus_changes().back());
-
-  EXPECT_FALSE(top_level_widget.HasCapture());
-  top_level_widget.SetCapture(nullptr);
-  EXPECT_TRUE(top_level_widget.HasCapture());
-
-  // Create a modal dialog.
-  ModalDialogDelegate* dialog_delegate =
-      new ModalDialogDelegate(ui::MODAL_TYPE_SYSTEM);
-
-  Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
-      dialog_delegate, nullptr, top_level_widget.GetNativeView());
-  modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
-  ShowSync(modal_dialog_widget);
-
-  EXPECT_FALSE(top_level_widget.HasCapture());
-
-  modal_dialog_widget->CloseNow();
-  top_level_widget.CloseNow();
-  WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(&focus_listener);
-}
-
 TEST_F(DesktopWidgetTestInteractive, CanActivateFlagIsHonored) {
   Widget widget;
   Widget::InitParams init_params =
@@ -1171,7 +915,7 @@
 // Test that touch selection quick menu is not activated when opened.
 TEST_F(DesktopWidgetTestInteractive,
        MAYBE_TouchSelectionQuickMenuIsNotActivated) {
-  Widget* widget = CreateTopLevelNativeWidget();
+  WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
   widget->SetBounds(gfx::Rect(0, 0, 200, 200));
 
   Textfield* textfield = new Textfield;
@@ -1186,7 +930,7 @@
 
   RunPendingMessages();
 
-  ui::test::EventGenerator generator(GetRootWindow(widget));
+  ui::test::EventGenerator generator(GetRootWindow(widget.get()));
   generator.GestureTapAt(textfield->GetBoundsInScreen().origin() +
                          gfx::Vector2d(10, 10));
   static_cast<TouchSelectionControllerImpl*>(
@@ -1196,7 +940,6 @@
   EXPECT_TRUE(textfield->HasFocus());
   EXPECT_TRUE(widget->IsActive());
   EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
-  widget->CloseNow();
 }
 #endif  // defined(USE_AURA)
 
@@ -1255,90 +998,76 @@
 }  // namespace test
 
 TEST_F(WidgetTestInteractive, ShowCreatesActiveWindow) {
-  Widget* widget = CreateTopLevelPlatformWidget();
+  WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
 
-  ShowSync(widget);
-  EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
-
-  widget->CloseNow();
+  ShowSync(widget.get());
+  EXPECT_EQ(GetWidgetShowState(widget.get()), ui::SHOW_STATE_NORMAL);
 }
 
 TEST_F(WidgetTestInteractive, ShowInactive) {
   WidgetTest::WaitForSystemAppActivation();
-  Widget* widget = CreateTopLevelPlatformWidget();
+  WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
 
-  ShowInactiveSync(widget);
-  EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_INACTIVE);
-
-  widget->CloseNow();
+  ShowInactiveSync(widget.get());
+  EXPECT_EQ(GetWidgetShowState(widget.get()), ui::SHOW_STATE_INACTIVE);
 }
 
 TEST_F(WidgetTestInteractive, InactiveBeforeShow) {
-  Widget* widget = CreateTopLevelPlatformWidget();
+  WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
 
   EXPECT_FALSE(widget->IsActive());
   EXPECT_FALSE(widget->IsVisible());
 
-  ShowSync(widget);
+  ShowSync(widget.get());
 
   EXPECT_TRUE(widget->IsActive());
   EXPECT_TRUE(widget->IsVisible());
-
-  widget->CloseNow();
 }
 
 TEST_F(WidgetTestInteractive, ShowInactiveAfterShow) {
   // Create 2 widgets to ensure window layering does not change.
-  Widget* widget = CreateTopLevelPlatformWidget();
-  Widget* widget2 = CreateTopLevelPlatformWidget();
+  WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
+  WidgetAutoclosePtr widget2(CreateTopLevelPlatformWidget());
 
-  ShowSync(widget2);
+  ShowSync(widget2.get());
   EXPECT_FALSE(widget->IsActive());
   EXPECT_TRUE(widget2->IsVisible());
   EXPECT_TRUE(widget2->IsActive());
 
-  ShowSync(widget);
+  ShowSync(widget.get());
   EXPECT_TRUE(widget->IsActive());
   EXPECT_FALSE(widget2->IsActive());
 
-  ShowInactiveSync(widget);
+  ShowInactiveSync(widget.get());
   EXPECT_TRUE(widget->IsActive());
   EXPECT_FALSE(widget2->IsActive());
-  EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
-
-  widget2->CloseNow();
-  widget->CloseNow();
+  EXPECT_EQ(GetWidgetShowState(widget.get()), ui::SHOW_STATE_NORMAL);
 }
 
 TEST_F(WidgetTestInteractive, ShowAfterShowInactive) {
-  Widget* widget = CreateTopLevelPlatformWidget();
+  WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
   widget->SetBounds(gfx::Rect(100, 100, 100, 100));
 
-  ShowInactiveSync(widget);
-  ShowSync(widget);
-  EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
-
-  widget->CloseNow();
+  ShowInactiveSync(widget.get());
+  ShowSync(widget.get());
+  EXPECT_EQ(GetWidgetShowState(widget.get()), ui::SHOW_STATE_NORMAL);
 }
 
 #if BUILDFLAG(ENABLE_DESKTOP_AURA) || defined(OS_MACOSX)
 TEST_F(WidgetTestInteractive, InactiveWidgetDoesNotGrabActivation) {
-  Widget* widget = CreateTopLevelPlatformWidget();
-  ShowSync(widget);
-  EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
+  WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
+  ShowSync(widget.get());
+  EXPECT_EQ(GetWidgetShowState(widget.get()), ui::SHOW_STATE_NORMAL);
 
-  Widget widget2;
+  WidgetAutoclosePtr widget2(new Widget());
   Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  widget2.Init(std::move(params));
-  widget2.Show();
+  widget2->Init(std::move(params));
+  widget2->Show();
   RunPendingMessagesForActiveStatusChange();
 
-  EXPECT_EQ(GetWidgetShowState(&widget2), ui::SHOW_STATE_INACTIVE);
-  EXPECT_EQ(GetWidgetShowState(widget), ui::SHOW_STATE_NORMAL);
-
-  widget->CloseNow();
-  widget2.CloseNow();
+  EXPECT_EQ(GetWidgetShowState(widget2.get()), ui::SHOW_STATE_INACTIVE);
+  EXPECT_EQ(GetWidgetShowState(widget.get()), ui::SHOW_STATE_NORMAL);
 }
 #endif  // BUILDFLAG(ENABLE_DESKTOP_AURA) || defined(OS_MACOSX)
 
@@ -1354,37 +1083,33 @@
 
 // Test that window state is not changed after getting out of full screen.
 TEST_F(WidgetTestInteractive, MAYBE_ExitFullscreenRestoreState) {
-  Widget* toplevel = CreateTopLevelPlatformWidget();
+  WidgetAutoclosePtr toplevel(CreateTopLevelPlatformWidget());
 
   toplevel->Show();
   RunPendingMessages();
 
   // This should be a normal state window.
-  EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
+  EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel.get()));
 
   toplevel->SetFullscreen(true);
-  EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
+  EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel.get()));
   toplevel->SetFullscreen(false);
-  EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
+  EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel.get()));
 
   // And it should still be in normal state after getting out of full screen.
-  EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel));
+  EXPECT_EQ(ui::SHOW_STATE_NORMAL, GetWidgetShowState(toplevel.get()));
 
   // Now, make it maximized.
   toplevel->Maximize();
-  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
+  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel.get()));
 
   toplevel->SetFullscreen(true);
-  EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
+  EXPECT_EQ(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel.get()));
   toplevel->SetFullscreen(false);
-  EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel));
+  EXPECT_NE(ui::SHOW_STATE_FULLSCREEN, GetWidgetShowState(toplevel.get()));
 
   // And it stays maximized after getting out of full screen.
-  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel));
-
-  // Clean up.
-  toplevel->Close();
-  RunPendingMessages();
+  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED, GetWidgetShowState(toplevel.get()));
 }
 
 // Testing initial focus is assigned properly for normal top-level widgets,
@@ -1414,23 +1139,21 @@
 }
 
 TEST_F(DesktopWidgetTestInteractive, RestoreAfterMinimize) {
-  Widget* widget = CreateTopLevelNativeWidget();
-  ShowSync(widget);
+  WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
+  ShowSync(widget.get());
   ASSERT_FALSE(widget->IsMinimized());
 
   PropertyWaiter minimize_waiter(
-      base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget)),
+      base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget.get())),
       true);
   widget->Minimize();
   EXPECT_TRUE(minimize_waiter.Wait());
 
   PropertyWaiter restore_waiter(
-      base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget)),
+      base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget.get())),
       false);
   widget->Restore();
   EXPECT_TRUE(restore_waiter.Wait());
-
-  widget->CloseNow();
 }
 
 #if defined(OS_WIN)
@@ -1439,14 +1162,14 @@
 // Tests that root window visibility toggles correctly when the desktop widget
 // is minimized and maximized on Windows, and the Widget remains visible.
 TEST_F(DesktopWidgetTestInteractive, RestoreAndMinimizeVisibility) {
-  Widget* widget = CreateTopLevelNativeWidget();
-  aura::Window* root_window = GetRootWindow(widget);
-  ShowSync(widget);
+  WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
+  aura::Window* root_window = GetRootWindow(widget.get());
+  ShowSync(widget.get());
   ASSERT_FALSE(widget->IsMinimized());
   EXPECT_TRUE(root_window->IsVisible());
 
   PropertyWaiter minimize_widget_waiter(
-      base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget)),
+      base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget.get())),
       true);
   widget->Minimize();
   EXPECT_TRUE(minimize_widget_waiter.Wait());
@@ -1454,22 +1177,21 @@
   EXPECT_FALSE(root_window->IsVisible());
 
   PropertyWaiter restore_widget_waiter(
-      base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget)),
+      base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget.get())),
       false);
   widget->Restore();
   EXPECT_TRUE(restore_widget_waiter.Wait());
   EXPECT_TRUE(widget->IsVisible());
   EXPECT_TRUE(root_window->IsVisible());
-  widget->CloseNow();
 }
 
 // Test that focus is restored to the widget after a minimized window
 // is activated.
 TEST_F(DesktopWidgetTestInteractive, MinimizeAndActivateFocus) {
-  Widget* widget = CreateTopLevelNativeWidget();
-  aura::Window* root_window = GetRootWindow(widget);
+  WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
+  aura::Window* root_window = GetRootWindow(widget.get());
   auto* widget_window = widget->GetNativeWindow();
-  ShowSync(widget);
+  ShowSync(widget.get());
   ASSERT_FALSE(widget->IsMinimized());
   EXPECT_TRUE(root_window->IsVisible());
   widget_window->Focus();
@@ -1479,7 +1201,7 @@
   EXPECT_TRUE(widget->GetContentsView()->HasFocus());
 
   PropertyWaiter minimize_widget_waiter(
-      base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget)),
+      base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget.get())),
       true);
   widget->Minimize();
   EXPECT_TRUE(minimize_widget_waiter.Wait());
@@ -1487,7 +1209,7 @@
   EXPECT_FALSE(root_window->IsVisible());
 
   PropertyWaiter restore_widget_waiter(
-      base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget)),
+      base::BindRepeating(&Widget::IsMinimized, base::Unretained(widget.get())),
       false);
   widget->Activate();
   EXPECT_TRUE(widget->GetContentsView()->HasFocus());
@@ -1495,7 +1217,6 @@
   EXPECT_TRUE(widget->IsVisible());
   EXPECT_TRUE(root_window->IsVisible());
   EXPECT_TRUE(widget_window->CanFocus());
-  widget->CloseNow();
 }
 
 #endif  // defined(OS_WIN)
@@ -1504,8 +1225,8 @@
 // Tests that minimizing a widget causes the gesture_handler
 // to be cleared when the widget is minimized.
 TEST_F(DesktopWidgetTestInteractive, EventHandlersClearedOnWidgetMinimize) {
-  Widget* widget = CreateTopLevelNativeWidget();
-  ShowSync(widget);
+  WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
+  ShowSync(widget.get());
   ASSERT_FALSE(widget->IsMinimized());
   View mouse_handler_view;
   internal::RootView* root_view =
@@ -1517,8 +1238,6 @@
 
   widget->Minimize();
   EXPECT_FALSE(GetGestureHandler(root_view));
-
-  widget->CloseNow();
 }
 #endif
 
@@ -1529,16 +1248,16 @@
 TEST_F(DesktopWidgetTestInteractive,
        DesktopNativeWidgetWithModalTransientChild) {
   // Create a desktop native Widget for Widget::Deactivate().
-  Widget* deactivate_widget = CreateTopLevelNativeWidget();
-  ShowSync(deactivate_widget);
+  WidgetAutoclosePtr deactivate_widget(CreateTopLevelNativeWidget());
+  ShowSync(deactivate_widget.get());
 
   // Create a top level desktop native widget.
-  Widget* top_level = CreateTopLevelNativeWidget();
+  WidgetAutoclosePtr top_level(CreateTopLevelNativeWidget());
 
   Textfield* textfield = new Textfield;
   textfield->SetBounds(0, 0, 200, 20);
   top_level->GetRootView()->AddChildView(textfield);
-  ShowSync(top_level);
+  ShowSync(top_level.get());
   textfield->RequestFocus();
   EXPECT_TRUE(textfield->HasFocus());
 
@@ -1559,18 +1278,15 @@
   EXPECT_TRUE(dialog_textfield->HasFocus());
   EXPECT_FALSE(textfield->HasFocus());
 
-  DeactivateSync(top_level);
+  DeactivateSync(top_level.get());
   EXPECT_FALSE(dialog_textfield->HasFocus());
   EXPECT_FALSE(textfield->HasFocus());
 
   // After deactivation and activation of top level widget, only modal dialog
   // should restore focused view.
-  ActivateSync(top_level);
+  ActivateSync(top_level.get());
   EXPECT_TRUE(dialog_textfield->HasFocus());
   EXPECT_FALSE(textfield->HasFocus());
-
-  top_level->CloseNow();
-  deactivate_widget->CloseNow();
 }
 #endif  // defined(OS_LINUX) && BUILDFLAG(ENABLE_DESKTOP_AURA)
 
@@ -1762,6 +1478,236 @@
   EXPECT_TRUE(mouse_view2->pressed());
 }
 
+TEST_F(WidgetCaptureTest, CaptureAutoReset) {
+  WidgetAutoclosePtr toplevel(CreateTopLevelFramelessPlatformWidget());
+  View* container = new View;
+  toplevel->SetContentsView(container);
+
+  EXPECT_FALSE(toplevel->HasCapture());
+  toplevel->SetCapture(nullptr);
+  EXPECT_TRUE(toplevel->HasCapture());
+
+  // By default, mouse release removes capture.
+  gfx::Point click_location(45, 15);
+  ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location,
+                         ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+                         ui::EF_LEFT_MOUSE_BUTTON);
+  toplevel->OnMouseEvent(&release);
+  EXPECT_FALSE(toplevel->HasCapture());
+
+  // Now a mouse release shouldn't remove capture.
+  toplevel->set_auto_release_capture(false);
+  toplevel->SetCapture(nullptr);
+  EXPECT_TRUE(toplevel->HasCapture());
+  toplevel->OnMouseEvent(&release);
+  EXPECT_TRUE(toplevel->HasCapture());
+  toplevel->ReleaseCapture();
+  EXPECT_FALSE(toplevel->HasCapture());
+}
+
+TEST_F(WidgetCaptureTest, ResetCaptureOnGestureEnd) {
+  WidgetAutoclosePtr toplevel(CreateTopLevelFramelessPlatformWidget());
+  View* container = new View;
+  toplevel->SetContentsView(container);
+
+  View* gesture = new GestureCaptureView;
+  gesture->SetBounds(0, 0, 30, 30);
+  container->AddChildView(gesture);
+
+  MouseView* mouse = new MouseView;
+  mouse->SetBounds(30, 0, 30, 30);
+  container->AddChildView(mouse);
+
+  toplevel->SetSize(gfx::Size(100, 100));
+  toplevel->Show();
+
+  // Start a gesture on |gesture|.
+  ui::GestureEvent tap_down(15, 15, 0, base::TimeTicks(),
+                            ui::GestureEventDetails(ui::ET_GESTURE_TAP_DOWN));
+  ui::GestureEvent end(15, 15, 0, base::TimeTicks(),
+                       ui::GestureEventDetails(ui::ET_GESTURE_END));
+  toplevel->OnGestureEvent(&tap_down);
+
+  // Now try to click on |mouse|. Since |gesture| will have capture, |mouse|
+  // will not receive the event.
+  gfx::Point click_location(45, 15);
+
+  ui::MouseEvent press(ui::ET_MOUSE_PRESSED, click_location, click_location,
+                       ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+                       ui::EF_LEFT_MOUSE_BUTTON);
+  ui::MouseEvent release(ui::ET_MOUSE_RELEASED, click_location, click_location,
+                         ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+                         ui::EF_LEFT_MOUSE_BUTTON);
+
+  EXPECT_TRUE(toplevel->HasCapture());
+
+  toplevel->OnMouseEvent(&press);
+  toplevel->OnMouseEvent(&release);
+  EXPECT_EQ(0, mouse->pressed());
+
+  EXPECT_FALSE(toplevel->HasCapture());
+
+  // The end of the gesture should release the capture, and pressing on |mouse|
+  // should now reach |mouse|.
+  toplevel->OnGestureEvent(&end);
+  toplevel->OnMouseEvent(&press);
+  toplevel->OnMouseEvent(&release);
+  EXPECT_EQ(1, mouse->pressed());
+}
+
+// Checks that if a mouse-press triggers a capture on a different widget (which
+// consumes the mouse-release event), then the target of the press does not have
+// capture.
+TEST_F(WidgetCaptureTest, DisableCaptureWidgetFromMousePress) {
+  // The test creates two widgets: |first| and |second|.
+  // The View in |first| makes |second| visible, sets capture on it, and starts
+  // a nested loop (like a menu does). The View in |second| terminates the
+  // nested loop and closes the widget.
+  // The test sends a mouse-press event to |first|, and posts a task to send a
+  // release event to |second|, to make sure that the release event is
+  // dispatched after the nested loop starts.
+
+  WidgetAutoclosePtr first(CreateTopLevelFramelessPlatformWidget());
+  Widget* second = CreateTopLevelFramelessPlatformWidget();
+
+  NestedLoopCaptureView* container = new NestedLoopCaptureView(second);
+  first->SetContentsView(container);
+
+  second->SetContentsView(new ExitLoopOnRelease(container->GetQuitClosure()));
+
+  first->SetSize(gfx::Size(100, 100));
+  first->Show();
+
+  gfx::Point location(20, 20);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          &Widget::OnMouseEvent, base::Unretained(second),
+          base::Owned(new ui::MouseEvent(
+              ui::ET_MOUSE_RELEASED, location, location, ui::EventTimeForNow(),
+              ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON))));
+  ui::MouseEvent press(ui::ET_MOUSE_PRESSED, location, location,
+                       ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+                       ui::EF_LEFT_MOUSE_BUTTON);
+  first->OnMouseEvent(&press);
+  EXPECT_FALSE(first->HasCapture());
+}
+
+// Tests some grab/ungrab events.
+// TODO(estade): can this be enabled now that this is an interactive ui test?
+TEST_F(WidgetCaptureTest, DISABLED_GrabUngrab) {
+  WidgetAutoclosePtr toplevel(CreateTopLevelPlatformWidget());
+  Widget* child1 = CreateChildNativeWidgetWithParent(toplevel.get());
+  Widget* child2 = CreateChildNativeWidgetWithParent(toplevel.get());
+
+  toplevel->SetBounds(gfx::Rect(0, 0, 500, 500));
+
+  child1->SetBounds(gfx::Rect(10, 10, 300, 300));
+  View* view = new MouseView();
+  view->SetBounds(0, 0, 300, 300);
+  child1->GetRootView()->AddChildView(view);
+
+  child2->SetBounds(gfx::Rect(200, 10, 200, 200));
+  view = new MouseView();
+  view->SetBounds(0, 0, 200, 200);
+  child2->GetRootView()->AddChildView(view);
+
+  toplevel->Show();
+  RunPendingMessages();
+
+  // Click on child1
+  gfx::Point p1(45, 45);
+  ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1, ui::EventTimeForNow(),
+                         ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+  toplevel->OnMouseEvent(&pressed);
+
+  EXPECT_TRUE(toplevel->HasCapture());
+  EXPECT_TRUE(child1->HasCapture());
+  EXPECT_FALSE(child2->HasCapture());
+
+  ui::MouseEvent released(ui::ET_MOUSE_RELEASED, p1, p1, ui::EventTimeForNow(),
+                          ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+  toplevel->OnMouseEvent(&released);
+
+  EXPECT_FALSE(toplevel->HasCapture());
+  EXPECT_FALSE(child1->HasCapture());
+  EXPECT_FALSE(child2->HasCapture());
+
+  RunPendingMessages();
+
+  // Click on child2
+  gfx::Point p2(315, 45);
+  ui::MouseEvent pressed2(ui::ET_MOUSE_PRESSED, p2, p2, ui::EventTimeForNow(),
+                          ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+  toplevel->OnMouseEvent(&pressed2);
+  EXPECT_TRUE(pressed2.handled());
+  EXPECT_TRUE(toplevel->HasCapture());
+  EXPECT_TRUE(child2->HasCapture());
+  EXPECT_FALSE(child1->HasCapture());
+
+  ui::MouseEvent released2(ui::ET_MOUSE_RELEASED, p2, p2, ui::EventTimeForNow(),
+                           ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
+  toplevel->OnMouseEvent(&released2);
+  EXPECT_FALSE(toplevel->HasCapture());
+  EXPECT_FALSE(child1->HasCapture());
+  EXPECT_FALSE(child2->HasCapture());
+}
+
+// Disabled on Mac. Desktop Mac doesn't have system modal windows since Carbon
+// was deprecated. It does have application modal windows, but only Ash requests
+// those.
+#if defined(OS_MACOSX)
+#define MAYBE_SystemModalWindowReleasesCapture \
+  DISABLED_SystemModalWindowReleasesCapture
+#elif defined(OS_CHROMEOS)
+// Investigate enabling for Chrome OS. It probably requires help from the window
+// service.
+#define MAYBE_SystemModalWindowReleasesCapture \
+  DISABLED_SystemModalWindowReleasesCapture
+#else
+#define MAYBE_SystemModalWindowReleasesCapture SystemModalWindowReleasesCapture
+#endif
+
+// Test that when opening a system-modal window, capture is released.
+TEST_F(WidgetCaptureTest, MAYBE_SystemModalWindowReleasesCapture) {
+  TestWidgetFocusChangeListener focus_listener;
+  WidgetFocusManager::GetInstance()->AddFocusChangeListener(&focus_listener);
+
+  // Create a top level widget.
+  Widget top_level_widget;
+  Widget::InitParams init_params =
+      CreateParams(Widget::InitParams::TYPE_WINDOW);
+  init_params.show_state = ui::SHOW_STATE_NORMAL;
+  gfx::Rect initial_bounds(0, 0, 500, 500);
+  init_params.bounds = initial_bounds;
+  init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  top_level_widget.Init(std::move(init_params));
+  ShowSync(&top_level_widget);
+
+  ASSERT_FALSE(focus_listener.focus_changes().empty());
+  EXPECT_EQ(top_level_widget.GetNativeView(),
+            focus_listener.focus_changes().back());
+
+  EXPECT_FALSE(top_level_widget.HasCapture());
+  top_level_widget.SetCapture(nullptr);
+  EXPECT_TRUE(top_level_widget.HasCapture());
+
+  // Create a modal dialog.
+  ModalDialogDelegate* dialog_delegate =
+      new ModalDialogDelegate(ui::MODAL_TYPE_SYSTEM);
+
+  Widget* modal_dialog_widget = views::DialogDelegate::CreateDialogWidget(
+      dialog_delegate, nullptr, top_level_widget.GetNativeView());
+  modal_dialog_widget->SetBounds(gfx::Rect(100, 100, 200, 200));
+  ShowSync(modal_dialog_widget);
+
+  EXPECT_FALSE(top_level_widget.HasCapture());
+
+  modal_dialog_widget->CloseNow();
+  top_level_widget.CloseNow();
+  WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(&focus_listener);
+}
+
 // Regression test for http://crbug.com/382421 (Linux-Aura issue).
 // TODO(pkotwicz): Make test pass on CrOS and Windows.
 // TODO(tapted): Investigate for toolkit-views on Mac http;//crbug.com/441064.
@@ -1971,33 +1917,32 @@
 #endif
 // Test input method focus changes affected by top window activaction.
 TEST_F(WidgetInputMethodInteractiveTest, MAYBE_Activation) {
-  Widget* widget = CreateTopLevelNativeWidget();
+  WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
   Textfield* textfield = new Textfield;
   widget->GetRootView()->AddChildView(textfield);
   textfield->RequestFocus();
 
-  ShowSync(widget);
+  ShowSync(widget.get());
 
   EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT,
             widget->GetInputMethod()->GetTextInputType());
 
-  DeactivateSync(widget);
+  DeactivateSync(widget.get());
 
   EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE,
             widget->GetInputMethod()->GetTextInputType());
-  widget->CloseNow();
 }
 
 // Test input method focus changes affected by focus changes within 1 window.
 TEST_F(WidgetInputMethodInteractiveTest, OneWindow) {
-  Widget* widget = CreateTopLevelNativeWidget();
+  WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
   Textfield* textfield1 = new Textfield;
   Textfield* textfield2 = new Textfield;
   textfield2->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
   widget->GetRootView()->AddChildView(textfield1);
   widget->GetRootView()->AddChildView(textfield2);
 
-  ShowSync(widget);
+  ShowSync(widget.get());
 
   textfield1->RequestFocus();
   EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT,
@@ -2011,31 +1956,30 @@
 // DNWA (which just activates the last active window) and involves the
 // AuraTestHelper which sets the input method as DummyInputMethod.
 #if BUILDFLAG(ENABLE_DESKTOP_AURA) || defined(OS_MACOSX)
-  DeactivateSync(widget);
+  DeactivateSync(widget.get());
   EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE,
             widget->GetInputMethod()->GetTextInputType());
 
-  ActivateSync(widget);
+  ActivateSync(widget.get());
   EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD,
             widget->GetInputMethod()->GetTextInputType());
 
-  DeactivateSync(widget);
+  DeactivateSync(widget.get());
   textfield1->RequestFocus();
-  ActivateSync(widget);
+  ActivateSync(widget.get());
   EXPECT_TRUE(widget->IsActive());
   EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT,
             widget->GetInputMethod()->GetTextInputType());
 #endif
-  widget->CloseNow();
 }
 
 // Test input method focus changes affected by focus changes cross 2 windows
 // which shares the same top window.
 TEST_F(WidgetInputMethodInteractiveTest, TwoWindows) {
-  Widget* parent = CreateTopLevelNativeWidget();
+  WidgetAutoclosePtr parent(CreateTopLevelNativeWidget());
   parent->SetBounds(gfx::Rect(100, 100, 100, 100));
 
-  Widget* child = CreateChildNativeWidgetWithParent(parent);
+  Widget* child = CreateChildNativeWidgetWithParent(parent.get());
   child->SetBounds(gfx::Rect(0, 0, 50, 50));
   child->Show();
 
@@ -2044,7 +1988,7 @@
   textfield_parent->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
   parent->GetRootView()->AddChildView(textfield_parent);
   child->GetRootView()->AddChildView(textfield_child);
-  ShowSync(parent);
+  ShowSync(parent.get());
 
   EXPECT_EQ(parent->GetInputMethod(), child->GetInputMethod());
 
@@ -2060,33 +2004,31 @@
 // DNWA (which just activates the last active window) and involves the
 // AuraTestHelper which sets the input method as DummyInputMethod.
 #if BUILDFLAG(ENABLE_DESKTOP_AURA) || defined(OS_MACOSX)
-  DeactivateSync(parent);
+  DeactivateSync(parent.get());
   EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE,
             parent->GetInputMethod()->GetTextInputType());
 
-  ActivateSync(parent);
+  ActivateSync(parent.get());
   EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT,
             parent->GetInputMethod()->GetTextInputType());
 
   textfield_parent->RequestFocus();
-  DeactivateSync(parent);
+  DeactivateSync(parent.get());
   EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE,
             parent->GetInputMethod()->GetTextInputType());
 
-  ActivateSync(parent);
+  ActivateSync(parent.get());
   EXPECT_EQ(ui::TEXT_INPUT_TYPE_PASSWORD,
             parent->GetInputMethod()->GetTextInputType());
 #endif
-
-  parent->CloseNow();
 }
 
 // Test input method focus changes affected by textfield's state changes.
 TEST_F(WidgetInputMethodInteractiveTest, TextField) {
-  Widget* widget = CreateTopLevelNativeWidget();
+  WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
   Textfield* textfield = new Textfield;
   widget->GetRootView()->AddChildView(textfield);
-  ShowSync(widget);
+  ShowSync(widget.get());
   EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE,
             widget->GetInputMethod()->GetTextInputType());
 
@@ -2105,15 +2047,14 @@
   textfield->SetReadOnly(true);
   EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE,
             widget->GetInputMethod()->GetTextInputType());
-  widget->CloseNow();
 }
 
 // Test input method should not work for accelerator.
 TEST_F(WidgetInputMethodInteractiveTest, AcceleratorInTextfield) {
-  Widget* widget = CreateTopLevelNativeWidget();
+  WidgetAutoclosePtr widget(CreateTopLevelNativeWidget());
   Textfield* textfield = new Textfield;
   widget->GetRootView()->AddChildView(textfield);
-  ShowSync(widget);
+  ShowSync(widget.get());
   textfield->SetTextInputType(ui::TEXT_INPUT_TYPE_TEXT);
   textfield->RequestFocus();
 
@@ -2130,8 +2071,6 @@
   ui::KeyEvent key_event2(key_event);
   widget->OnKeyEvent(&key_event2);
   EXPECT_FALSE(key_event2.stopped_propagation());
-
-  widget->CloseNow();
 }
 
 }  // namespace test
diff --git a/weblayer/browser/android/javatests/BUILD.gn b/weblayer/browser/android/javatests/BUILD.gn
index bb5a6da8..5770eba 100644
--- a/weblayer/browser/android/javatests/BUILD.gn
+++ b/weblayer/browser/android/javatests/BUILD.gn
@@ -130,3 +130,30 @@
 
   deps = [ ":weblayer_private_java_tests" ]
 }
+
+# Runs WebLayer instrumentation tests against arbitrary versions of tests, the
+# client, and the implementation.
+#
+# Example usage, testing M80 tests and client against master implementation:
+#   autoninja -C out/Release weblayer_instrumentation_test_versions_apk
+#   cipd install --root /tmp/M80 chromium/testing/weblayer-x86 m80
+#   out/Release/bin/run_weblayer_instrumentation_tests_versions_apk \
+#       --tests-outdir /tmp/M80/out/Release
+#       --client-outdir /tmp/M80/out/Release
+#       --implementation-outdir out/Release
+copy("weblayer_instrumentation_test_versions_apk") {
+  testonly = true
+
+  sources = [ "weblayer_instrumentation_test_versions.py" ]
+
+  outputs =
+      [ "$root_build_dir/bin/run_weblayer_instrumentation_test_versions_apk" ]
+
+  # Also explicitly list the output as data so it gets isolated on bots.
+  data =
+      [ "$root_build_dir/bin/run_weblayer_instrumentation_test_versions_apk" ]
+
+  deps = [ ":weblayer_instrumentation_test_apk" ]
+
+  data_deps = [ ":weblayer_instrumentation_test_apk" ]
+}
diff --git a/weblayer/browser/android/javatests/weblayer_instrumentation_test_versions.py b/weblayer/browser/android/javatests/weblayer_instrumentation_test_versions.py
new file mode 100755
index 0000000..bfde31e
--- /dev/null
+++ b/weblayer/browser/android/javatests/weblayer_instrumentation_test_versions.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env vpython
+#
+# 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.
+#
+# Runs WebLayer instrumentation tests against arbitrary versions of tests, the
+# client, and the implementation.
+#
+# Example usage, testing M80 tests and client against master implementation:
+#   autoninja -C out/Release weblayer_instrumentation_test_versions_apk
+#   cipd install --root /tmp/M80 chromium/testing/weblayer-x86 m80
+#   out/Release/bin/run_weblayer_instrumentation_tests_versions_apk \
+#       --tests-outdir /tmp/M80/out/Release
+#       --client-outdir /tmp/M80/out/Release
+#       --implementation-outdir out/Release
+
+import argparse
+import logging
+import os
+import re
+import subprocess
+import sys
+
+
+def main():
+  """Wrapper to call weblayer instrumentation tests with different versions."""
+
+  parser = argparse.ArgumentParser(
+      description='Run weblayer instrumentation tests at different versions.')
+  parser.add_argument(
+      '--tests-outdir',
+      required=True,
+      help=('Build output directory from which to find tests and test ' +
+            'support files. Since test dependencies can reside in both ' +
+            'the build output directory and the source directory, this ' +
+            'script will look two directories up for source files unless ' +
+            '--test-srcdir is also set.'))
+  parser.add_argument(
+      '--tests-srcdir',
+      required=False,
+      default='',
+      help=('Source directory from which to find test data. If unset the ' +
+            'script will use two directories above --test-outdir.'))
+  parser.add_argument(
+      '--client-outdir',
+      required=True,
+      help='Build output directory for WebLayer client.')
+  parser.add_argument(
+      '--implementation-outdir',
+      required=True,
+      help='Build output directory for WebLayer implementation.')
+  args = parser.parse_args()
+
+  logging.basicConfig(level=logging.INFO)
+
+  # The command line is derived from the resulting command line from
+  # run_weblayer_instrumentation_test_apk but with parameterized tests, client,
+  # and implementation.
+  if args.tests_srcdir:
+    tests_srcdir = args.tests_srcdir
+  else:
+    tests_srcdir = os.path.normpath(os.path.join(args.tests_outdir, '..', '..'))
+  executable_path = os.path.join(tests_srcdir, 'build/android/test_runner.py')
+  executable_args = [
+      'instrumentation',
+      '--output-directory',
+      args.tests_outdir,
+      '--runtime-deps-path',
+      os.path.join(args.tests_outdir,
+                   ('gen.runtime/weblayer/browser/android/javatests/' +
+                    'weblayer_instrumentation_test_apk.runtime_deps')),
+      '--test-apk',
+      os.path.join(args.tests_outdir, 'apks/WebLayerInstrumentationTest.apk'),
+      '--test-jar',
+      os.path.join(args.tests_outdir,
+                   'test.lib.java/WebLayerInstrumentationTest.jar'),
+      '--apk-under-test',
+      os.path.join(args.client_outdir, 'apks/WebLayerShellSystemWebView.apk'),
+      '--use-webview-provider',
+      os.path.join(args.implementation_outdir, 'apks/SystemWebView.apk'),
+      '--additional-apk',
+      os.path.join(args.tests_outdir, 'apks/ChromiumNetTestSupport.apk')]
+
+  cmd = [executable_path] + executable_args
+  cmd = [sys.executable] + cmd
+  logging.info(' '.join(cmd))
+  return subprocess.call(cmd)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/weblayer/browser/profile_disk_operations.cc b/weblayer/browser/profile_disk_operations.cc
index ae062a12..3b1a58d 100644
--- a/weblayer/browser/profile_disk_operations.cc
+++ b/weblayer/browser/profile_disk_operations.cc
@@ -107,6 +107,10 @@
   CHECK(data_root_path.AppendRelativePath(info.data_path, &marker_path));
   base::File file(marker_path,
                   base::File::FLAG_CREATE | base::File::FLAG_WRITE);
+  if (!base::PathExists(marker_path)) {
+    LOG(WARNING) << "Failure in deleting profile data. Profile:" << info.name
+                 << " error:" << static_cast<int>(file.error_details());
+  }
 }
 
 void TryNukeProfileFromDisk(const ProfileInfo& info) {