diff --git a/DEPS b/DEPS
index 5a23107..bd8f3d5 100644
--- a/DEPS
+++ b/DEPS
@@ -280,7 +280,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'f4087cb7c415e0fa8e1c27f6092d8e7ce335d711',
+  'skia_revision': '23564bd50042bacd4d22c8ffcee0fd2fb9eaf877',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -288,7 +288,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '5a3e1dba8e6079f2c95493b52ad06c390ba6fe4a',
+  'angle_revision': '1adf46a60a77be9f7fa940a98ad06cbe151b94c9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -307,7 +307,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
-  'fuchsia_version': 'version:8.20220614.1.1',
+  'fuchsia_version': 'version:8.20220614.2.1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
@@ -351,7 +351,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'd854027b5cff510baf7a712c900474d01b1c0701',
+  'catapult_revision': '351bad3feafe6d2ff11b5a3ddc740e38e79f95b4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -846,7 +846,7 @@
       'packages': [
         {
           'package': 'chromium/rts/model/linux-amd64',
-          'version': '2lgLyfFFn1giCzbCBxUtuCWlH8zMQfL7oPoda_slQ7gC',
+          'version': 'fEF-m7iiUlPEMg0VIo-RTRPif-lBGJ0VTUzM_be56K8C',
         },
       ],
       'dep_type': 'cipd',
@@ -1708,7 +1708,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '65ea407597c7781c92a87b6d7fac827ba2c5a478',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'bed8507b95710818e1a4642a269c59a1a5ea07de',
+    Var('webrtc_git') + '/src.git' + '@' + 'ea5a944921af4e1c31aa1e5f4ef28e4a8e942452',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1811,7 +1811,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': '2ofSj7tchb3b7Jor8ZSdo9gC44SSDFvWoIFO24DmY_0C',
+        'version': 'J98AlfpF1UP6dn-WUiCIyYmt4jPVhKO20Ezm7AEeURQC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index b479043..8fa1491 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -801,7 +801,6 @@
     "//components/network_session_configurator/android:network_session_configurator_java",
     "//components/variations:variations_java",
     "//components/viz:viz_java",
-    "//components/webrtc:components_webrtc_java",
     "//content/public/android:content_java",
     "//content/public/common:common_java",
     "//gpu/config:config_java",
diff --git a/android_webview/browser/gfx/output_surface_provider_webview.cc b/android_webview/browser/gfx/output_surface_provider_webview.cc
index 12555ab..4e2c33f 100644
--- a/android_webview/browser/gfx/output_surface_provider_webview.cc
+++ b/android_webview/browser/gfx/output_surface_provider_webview.cc
@@ -25,6 +25,7 @@
 #include "gpu/ipc/single_task_sequence.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/gfx/geometry/size.h"
+#include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_share_group.h"
 #include "ui/gl/gl_surface_egl.h"
@@ -112,7 +113,7 @@
   // If EGL supports EGL_ANGLE_external_context_and_surface, then we will create
   // an ANGLE context for the current native GL context.
   const bool is_angle =
-      !enable_vulkan_ && display->IsANGLEExternalContextAndSurfaceSupported();
+      !enable_vulkan_ && display->ext->b_EGL_ANGLE_external_context_and_surface;
 
   GLSurfaceContextPair real_context;
   if (enable_vulkan_) {
diff --git a/android_webview/browser/gfx/scoped_app_gl_state_restore.cc b/android_webview/browser/gfx/scoped_app_gl_state_restore.cc
index 1289f30..35305c1 100644
--- a/android_webview/browser/gfx/scoped_app_gl_state_restore.cc
+++ b/android_webview/browser/gfx/scoped_app_gl_state_restore.cc
@@ -32,7 +32,7 @@
 
   TRACE_EVENT0("android_webview", "AppGLStateSave");
   if (gl::GLSurfaceEGL::GetGLDisplayEGL()
-          ->IsANGLEExternalContextAndSurfaceSupported()) {
+          ->ext->b_EGL_ANGLE_external_context_and_surface) {
     impl_ = std::make_unique<internal::ScopedAppGLStateRestoreImplAngle>(
         mode, save_restore);
   } else {
diff --git a/android_webview/browser/gfx/skia_output_surface_dependency_webview.cc b/android_webview/browser/gfx/skia_output_surface_dependency_webview.cc
index 8490ffed..7c368a5 100644
--- a/android_webview/browser/gfx/skia_output_surface_dependency_webview.cc
+++ b/android_webview/browser/gfx/skia_output_surface_dependency_webview.cc
@@ -95,9 +95,9 @@
   // There is no way to access the gpu thread here, so leave it no-op for now.
 }
 
-void SkiaOutputSurfaceDependencyWebView::PostTaskToClientThread(
-    base::OnceClosure closure) {
-  task_queue_->ScheduleClientTask(std::move(closure));
+scoped_refptr<base::TaskRunner>
+SkiaOutputSurfaceDependencyWebView::GetClientTaskRunner() {
+  return task_queue_->GetClientTaskRunner();
 }
 
 gpu::ImageFactory* SkiaOutputSurfaceDependencyWebView::GetGpuImageFactory() {
diff --git a/android_webview/browser/gfx/skia_output_surface_dependency_webview.h b/android_webview/browser/gfx/skia_output_surface_dependency_webview.h
index 987cdf8..73dcc21 100644
--- a/android_webview/browser/gfx/skia_output_surface_dependency_webview.h
+++ b/android_webview/browser/gfx/skia_output_surface_dependency_webview.h
@@ -49,7 +49,7 @@
   gpu::ImageFactory* GetGpuImageFactory() override;
   void ScheduleGrContextCleanup() override;
   void ScheduleDelayedGPUTaskFromGPUThread(base::OnceClosure task) override;
-  void PostTaskToClientThread(base::OnceClosure closure) override;
+  scoped_refptr<base::TaskRunner> GetClientTaskRunner() override;
   bool IsOffscreen() override;
   gpu::SurfaceHandle GetSurfaceHandle() override;
   scoped_refptr<gl::GLSurface> CreateGLSurface(
diff --git a/android_webview/browser/gfx/task_queue_webview.cc b/android_webview/browser/gfx/task_queue_webview.cc
index 424cd9e..06cfece 100644
--- a/android_webview/browser/gfx/task_queue_webview.cc
+++ b/android_webview/browser/gfx/task_queue_webview.cc
@@ -42,7 +42,7 @@
   void ScheduleTask(base::OnceClosure task, bool out_of_order) override;
   void ScheduleOrRetainTask(base::OnceClosure task) override;
   void ScheduleIdleTask(base::OnceClosure task) override;
-  void ScheduleClientTask(base::OnceClosure task) override;
+  scoped_refptr<base::TaskRunner> GetClientTaskRunner() override;
   void InitializeVizThread(const scoped_refptr<base::SingleThreadTaskRunner>&
                                viz_task_runner) override;
   void ScheduleOnVizAndBlock(VizTask viz_task) override;
@@ -111,9 +111,9 @@
   EmplaceTask(std::move(task));
 }
 
-void TaskQueueViz::ScheduleClientTask(base::OnceClosure task) {
+scoped_refptr<base::TaskRunner> TaskQueueViz::GetClientTaskRunner() {
   DCHECK(viz_task_runner_);
-  viz_task_runner_->PostTask(FROM_HERE, std::move(task));
+  return viz_task_runner_;
 }
 
 void TaskQueueViz::InitializeVizThread(
diff --git a/android_webview/browser/gfx/task_queue_webview.h b/android_webview/browser/gfx/task_queue_webview.h
index 85bb73f..9ceeb24e 100644
--- a/android_webview/browser/gfx/task_queue_webview.h
+++ b/android_webview/browser/gfx/task_queue_webview.h
@@ -41,7 +41,10 @@
 
   // Called by both DeferredGpuCommandService and
   // SkiaOutputSurfaceDisplayContext to post task to client thread.
-  virtual void ScheduleClientTask(base::OnceClosure task) = 0;
+  void ScheduleClientTask(base::OnceClosure task) {
+    GetClientTaskRunner()->PostTask(FROM_HERE, std::move(task));
+  }
+  virtual scoped_refptr<base::TaskRunner> GetClientTaskRunner() = 0;
 
  protected:
   virtual ~TaskQueueWebView() = default;
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
index 0a3a5be3..9fe24a0 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -14,7 +14,6 @@
 import org.chromium.components.network_session_configurator.NetworkSessionSwitches;
 import org.chromium.components.variations.VariationsSwitches;
 import org.chromium.components.viz.common.VizFeatures;
-import org.chromium.components.webrtc.ComponentsWebRtcFeatures;
 import org.chromium.content_public.common.ContentFeatures;
 import org.chromium.content_public.common.ContentSwitches;
 import org.chromium.gpu.config.GpuFeatures;
@@ -298,8 +297,6 @@
                     AwFeatures.WEBVIEW_SYNTHESIZE_PAGE_LOAD_ONLY_ON_INITIAL_MAIN_DOCUMENT_ACCESS,
                     "Only synthesize page load for URL spoof prevention at most once,"
                             + " on initial main document access."),
-            Flag.baseFeature(ComponentsWebRtcFeatures.THREAD_WRAPPER_USES_METRONOME,
-                    "Makes ThreadWrapper coalesce delayed tasks on metronome ticks."),
             Flag.baseFeature(WebRtcOverridesFeatures.WEB_RTC_TIMER_USES_METRONOME,
                     "Makes WebRtcTimer coalesce delayed tasks on metronome ticks."),
             Flag.baseFeature(BlinkFeatures.VIEWPORT_HEIGHT_CLIENT_HINT_HEADER,
diff --git a/android_webview/javatests/PRESUBMIT.py b/android_webview/javatests/PRESUBMIT.py
index 551251a..47b3dec 100644
--- a/android_webview/javatests/PRESUBMIT.py
+++ b/android_webview/javatests/PRESUBMIT.py
@@ -14,6 +14,7 @@
   results.extend(_CheckAwJUnitTestRunner(input_api, output_api))
   results.extend(_CheckNoSkipCommandLineAnnotation(input_api, output_api))
   results.extend(_CheckNoSandboxedRendererSwitch(input_api, output_api))
+  results.extend(_CheckNoDomUtils(input_api, output_api))
   return results
 
 
@@ -123,3 +124,36 @@
 """, errors))
 
   return results
+
+
+def _CheckNoDomUtils(input_api, output_api):
+  """Checks that tests prefer JSUtils.clickNodeWithUserGesture() over
+  DOMUtils.clickNode().
+  """
+
+  dom_utils_pattern = input_api.re.compile(r'DOMUtils\.clickNode\(')
+  errors = []
+  def _FilterFile(affected_file):
+    return input_api.FilterSourceFile(
+        affected_file,
+        files_to_skip=input_api.DEFAULT_FILES_TO_SKIP,
+        files_to_check=[r'.*\.java$'])
+
+  for f in input_api.AffectedSourceFiles(_FilterFile):
+    for line_num, line in f.ChangedContents():
+      m = dom_utils_pattern.search(line)
+      if m:
+        errors.append("%s:%d" % (f.LocalPath(), line_num))
+
+  results = []
+  if errors:
+    results.append(output_api.PresubmitPromptWarning("""
+DOMUtils.clickNode() has been observed to cause flakiness in WebView tests.
+Prefer using JSUtils.clickNodeWithUserGesture() as a more reliable replacement
+where possible. This is a "soft" warning, so you can bypass this if
+DOMUtils.clickNode() is the only way.
+""", errors))
+
+  return results
+
+
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java
index cd5ce83b..d9abf4f 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java
@@ -40,7 +40,6 @@
 import org.chromium.components.policy.test.PolicyData;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.NavigationHistory;
-import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer.OnEvaluateJavaScriptResultHelper;
 import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer.OnPageStartedHelper;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
@@ -713,7 +712,7 @@
         Assert.assertEquals(indirectLoadCallCount, mShouldOverrideUrlLoadingHelper.getCallCount());
 
         // Simulate touch, hasUserGesture must be true only on the first call.
-        DOMUtils.clickNode(mAwContents.getWebContents(), "link");
+        JSUtils.clickNodeWithUserGesture(mAwContents.getWebContents(), "link");
 
         mShouldOverrideUrlLoadingHelper.waitForCallback(indirectLoadCallCount, 1);
         Assert.assertEquals(
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java
index 51bc664..4d0b52c 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java
@@ -50,7 +50,6 @@
 import org.chromium.components.embedder_support.util.WebResourceResponseInfo;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContentsObserver;
-import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.HistoryUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.content_public.common.ContentSwitches;
@@ -2595,7 +2594,7 @@
             int count = callback.getCallCount();
             mActivityTestRule.loadDataSync(awContents, contentClient.getOnPageFinishedHelper(),
                     pageHtml, "text/html", false);
-            DOMUtils.clickNode(testContainer.getWebContents(), "play");
+            JSUtils.clickNodeWithUserGesture(testContainer.getWebContents(), "play");
             callback.waitForCallback(count, 1);
             Assert.assertEquals(0, webServer.getRequestCount(httpPath));
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java
index 3f2f69c2..6ca3180e 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java
@@ -25,6 +25,7 @@
 import org.chromium.android_webview.AwContentsClient;
 import org.chromium.android_webview.test.util.CommonResources;
 import org.chromium.android_webview.test.util.GraphicsTestUtils;
+import org.chromium.android_webview.test.util.JSUtils;
 import org.chromium.android_webview.test.util.JavascriptEventObserver;
 import org.chromium.base.task.PostTask;
 import org.chromium.base.test.util.CallbackHelper;
@@ -34,7 +35,6 @@
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.browser.WebContents;
-import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
 import java.io.ByteArrayInputStream;
@@ -314,7 +314,7 @@
 
         Assert.assertTrue(readyToUpdateColor.await(
                 AwActivityTestRule.SCALED_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        DOMUtils.clickNode(webContents, UPDATE_COLOR_CONTROL_ID);
+        JSUtils.clickNodeWithUserGesture(webContents, UPDATE_COLOR_CONTROL_ID);
         Assert.assertTrue(jsObserver.waitForEvent(WAIT_TIMEOUT_MS));
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(
@@ -381,7 +381,7 @@
 
         Assert.assertTrue(readyToEnterFullscreenSignal.await(
                 AwActivityTestRule.SCALED_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        DOMUtils.clickNode(webContents, ENTER_FULLSCREEN_CONTROL_ID);
+        JSUtils.clickNodeWithUserGesture(webContents, ENTER_FULLSCREEN_CONTROL_ID);
         Assert.assertTrue(jsObserver.waitForEvent(WAIT_TIMEOUT_MS));
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(
diff --git a/ash/app_list/app_list_metrics.h b/ash/app_list/app_list_metrics.h
index 058b5cd..368edd8 100644
--- a/ash/app_list/app_list_metrics.h
+++ b/ash/app_list/app_list_metrics.h
@@ -223,6 +223,19 @@
   kMaxValue = kOpenSuggestionChip,
 };
 
+// Whether and how user-entered search box text matches up with the first search
+// result. These values are persisted to logs. Entries should not be renumbered
+// and numeric values should never be reused.
+enum class SearchBoxTextMatch {
+  // The user entered query is not a substring of the first search result.
+  kNoMatch = 0,
+  // The user entered query matches the prefix of the first search result.
+  kPrefixMatch = 1,
+  // The user entered query is a substring of the first search result.
+  kSubstringMatch = 2,
+  kMaxValue = kSubstringMatch,
+};
+
 // Parameters to call RecordAppListAppLaunched. Passed to code that does not
 // directly have access to them, such ash AppListMenuModelAdapter.
 struct AppLaunchedMetricParams {
diff --git a/ash/app_list/views/search_box_view.cc b/ash/app_list/views/search_box_view.cc
index 6ce7ab60..cc8a64e 100644
--- a/ash/app_list/views/search_box_view.cc
+++ b/ash/app_list/views/search_box_view.cc
@@ -6,9 +6,11 @@
 
 #include <algorithm>
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
+#include "ash/app_list/app_list_metrics.h"
 #include "ash/app_list/app_list_util.h"
 #include "ash/app_list/app_list_view_delegate.h"
 #include "ash/app_list/model/search/search_box_model.h"
@@ -30,6 +32,7 @@
 #include "ash/search_box/search_box_view_delegate.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/notreached.h"
@@ -112,6 +115,22 @@
   return kDefaultPlaceholders[rand() % std::size(kDefaultPlaceholders)];
 }
 
+bool IsSubstringCaseInsensitive(std::u16string haystack_expr,
+                                std::u16string needle_expr) {
+  // Convert complete given String to lower case
+  std::transform(haystack_expr.begin(), haystack_expr.end(),
+                 haystack_expr.begin(), ::tolower);
+  // Convert complete given Sub String to lower case
+  std::transform(needle_expr.begin(), needle_expr.end(), needle_expr.begin(),
+                 ::tolower);
+  // Find sub string in given string
+  return haystack_expr.find(needle_expr) != std::string::npos;
+}
+
+void RecordAutocompleteMatchMetric(SearchBoxTextMatch match_type) {
+  base::UmaHistogramEnumeration("Apps.AppListSearchAutocomplete", match_type);
+}
+
 }  // namespace
 
 class SearchBoxView::FocusRingLayer : public ui::Layer, ui::LayerDelegate {
@@ -466,13 +485,14 @@
       return;
   }
 
-  UMA_HISTOGRAM_ENUMERATION("Apps.AppListSearchBoxActivated", activation_type);
+  base::UmaHistogramEnumeration("Apps.AppListSearchBoxActivated",
+                                activation_type);
   if (is_tablet_mode_) {
-    UMA_HISTOGRAM_ENUMERATION("Apps.AppListSearchBoxActivated.TabletMode",
-                              activation_type);
+    base::UmaHistogramEnumeration("Apps.AppListSearchBoxActivated.TabletMode",
+                                  activation_type);
   } else {
-    UMA_HISTOGRAM_ENUMERATION("Apps.AppListSearchBoxActivated.ClamshellMode",
-                              activation_type);
+    base::UmaHistogramEnumeration(
+        "Apps.AppListSearchBoxActivated.ClamshellMode", activation_type);
   }
 }
 
@@ -669,21 +689,60 @@
 
   const std::u16string& details = first_visible_result->details();
   const std::u16string& search_text = first_visible_result->title();
+
+  // Don't set autocomplete text if it's the same as user typed text.
+  if (user_typed_text == details || user_typed_text == search_text)
+    return;
+
+  auto is_valid_autocomplete_text =
+      [this](const std::u16string& autocomplete_text) {
+        // Don't set autocomplete text if it's the same as current search box
+        // text.
+        if (autocomplete_text == search_box()->GetText())
+          return false;
+        // Don't set autocomplete text if the highlighted text is the same as
+        // before.
+        if (autocomplete_text.substr(highlight_range_.start()) ==
+            search_box()->GetSelectedText()) {
+          return false;
+        }
+        return true;
+      };
+
   if (base::StartsWith(details, user_typed_text,
-                       base::CompareCase::INSENSITIVE_ASCII)) {
+                       base::CompareCase::INSENSITIVE_ASCII) &&
+      is_valid_autocomplete_text(details)) {
     // Current text in the search_box matches the first result's url.
     SetAutocompleteText(details);
+    RecordAutocompleteMatchMetric(SearchBoxTextMatch::kPrefixMatch);
     return;
   }
+
   if (base::StartsWith(search_text, user_typed_text,
-                       base::CompareCase::INSENSITIVE_ASCII)) {
+                       base::CompareCase::INSENSITIVE_ASCII) &&
+      is_valid_autocomplete_text(search_text)) {
     // Current text in the search_box matches the first result's search result
     // text.
     SetAutocompleteText(search_text);
+    RecordAutocompleteMatchMetric(SearchBoxTextMatch::kPrefixMatch);
     return;
   }
-  // Current text in the search_box does not match the first result's url or
-  // search result text.
+
+  // Record whether the user's query is a substring of the search result. Used
+  // to determine whether we should add substring matching to CrOS search
+  // autocomplete.
+  if (IsSubstringCaseInsensitive(details, user_typed_text) &&
+      is_valid_autocomplete_text(details)) {
+    RecordAutocompleteMatchMetric(SearchBoxTextMatch::kSubstringMatch);
+    // TODO(crbug.com/1334821): Maybe enable substring match autocomplete.
+  } else if (IsSubstringCaseInsensitive(search_text, user_typed_text) &&
+             is_valid_autocomplete_text(search_text)) {
+    RecordAutocompleteMatchMetric(SearchBoxTextMatch::kSubstringMatch);
+    // TODO(crbug.com/1334821): Maybe enable substring match autocomplete.
+  } else {
+    RecordAutocompleteMatchMetric(SearchBoxTextMatch::kNoMatch);
+  }
+
   ClearAutocompleteText();
 }
 
@@ -863,16 +922,12 @@
   // Currrent text is a prefix of autocomplete text.
   DCHECK(base::StartsWith(autocomplete_text, current_text,
                           base::CompareCase::INSENSITIVE_ASCII));
-  // Don't set autocomplete text if it's the same as current search box text.
-  if (autocomplete_text == current_text)
-    return;
-
+  // Autocomplete text should not be the same as current search box text.
+  DCHECK(autocomplete_text != current_text);
+  // Autocomplete text should not be the same as highlighted text.
   const std::u16string& highlighted_text =
       autocomplete_text.substr(highlight_range_.start());
-
-  // Don't set autocomplete text if the highlighted text is the same as before.
-  if (highlighted_text == search_box()->GetSelectedText())
-    return;
+  DCHECK(highlighted_text != current_text);
 
   highlight_range_.set_end(autocomplete_text.length());
   ui::CompositionText composition_text;
diff --git a/ash/components/phonehub/phone_hub_metrics_recorder.cc b/ash/components/phonehub/phone_hub_metrics_recorder.cc
index 80df3fbf..d9cd81d 100644
--- a/ash/components/phonehub/phone_hub_metrics_recorder.cc
+++ b/ash/components/phonehub/phone_hub_metrics_recorder.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "ash/components/phonehub/phone_hub_metrics_recorder.h"
+#include "ash/services/secure_channel/public/mojom/secure_channel.mojom.h"
 #include "base/metrics/histogram_functions.h"
 
 namespace ash::phonehub {
@@ -14,13 +15,19 @@
   base::UmaHistogramBoolean("PhoneHub.Connection.Result", success);
 }
 
+void PhoneHubMetricsRecorder::RecordConnectionFailureReason(
+    secure_channel::mojom::ConnectionAttemptFailureReason reason) {
+  base::UmaHistogramEnumeration("PhoneHub.Connection.Result.FailureReason",
+                                reason);
+}
+
 void PhoneHubMetricsRecorder::RecordConnectionLatency(
-    const base::TimeDelta& latency) {
+    const base::TimeDelta latency) {
   base::UmaHistogramTimes("PhoneHub.Connectivity.Latency", latency);
 }
 
 void PhoneHubMetricsRecorder::RecordConnectionDuration(
-    const base::TimeDelta& duration) {
+    const base::TimeDelta duration) {
   base::UmaHistogramLongTimes100("PhoneHub.Connection.Duration", duration);
 }
 
diff --git a/ash/components/phonehub/phone_hub_metrics_recorder.h b/ash/components/phonehub/phone_hub_metrics_recorder.h
index f7849db..8e30a212 100644
--- a/ash/components/phonehub/phone_hub_metrics_recorder.h
+++ b/ash/components/phonehub/phone_hub_metrics_recorder.h
@@ -20,8 +20,10 @@
 
   // secure_channel::NearbyMetricsRecorder:
   void RecordConnectionResult(bool success) override;
-  void RecordConnectionLatency(const base::TimeDelta& latency) override;
-  void RecordConnectionDuration(const base::TimeDelta& duration) override;
+  void RecordConnectionFailureReason(
+      secure_channel::mojom::ConnectionAttemptFailureReason reason) override;
+  void RecordConnectionLatency(const base::TimeDelta latency) override;
+  void RecordConnectionDuration(const base::TimeDelta duration) override;
 };
 
 }  // namespace ash::phonehub
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 1fab77c..ec1a2e0 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -1298,6 +1298,10 @@
 const base::Feature kScalableStatusArea{"ScalableStatusArea",
                                         base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Enables the rounded corners for the internal display.
+const base::Feature kRoundedDisplay{"RoundedDisplay",
+                                    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Controls whether to enable kSecondaryGoogleAccountUsage policy.
 const base::Feature kSecondaryGoogleAccountUsage{
     "SecondaryGoogleAccountUsage", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -2238,6 +2242,10 @@
   return base::FeatureList::IsEnabled(kScalableStatusArea);
 }
 
+bool IsRoundedDisplayEnabled() {
+  return base::FeatureList::IsEnabled(kRoundedDisplay);
+}
+
 bool IsSeparateNetworkIconsEnabled() {
   return base::FeatureList::IsEnabled(kSeparateNetworkIcons);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 53b1f1f..568b28b 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -517,6 +517,8 @@
 extern const base::Feature kReverseScrollGestures;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kScalableStatusArea;
 COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::Feature kRoundedDisplay;
+COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kSecondaryGoogleAccountUsage;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kSemanticColorsDebugOverride;
@@ -796,6 +798,8 @@
 bool IsSamlReauthenticationOnLockscreenEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsSavedDesksEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsScalableStatusAreaEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS)
+bool IsRoundedDisplayEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsSeparateNetworkIconsEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS)
 bool IsSettingsAppNotificationSettingsEnabled();
diff --git a/ash/services/secure_channel/public/cpp/client/BUILD.gn b/ash/services/secure_channel/public/cpp/client/BUILD.gn
index 5baab3b..77421935 100644
--- a/ash/services/secure_channel/public/cpp/client/BUILD.gn
+++ b/ash/services/secure_channel/public/cpp/client/BUILD.gn
@@ -22,6 +22,7 @@
     "connection_manager_impl.h",
     "nearby_connector.cc",
     "nearby_connector.h",
+    "nearby_metrics_recorder.cc",
     "nearby_metrics_recorder.h",
     "presence_monitor_client.h",
     "presence_monitor_client_impl.cc",
diff --git a/ash/services/secure_channel/public/cpp/client/connection_manager_impl.cc b/ash/services/secure_channel/public/cpp/client/connection_manager_impl.cc
index f1d88fb5..f4fe288 100644
--- a/ash/services/secure_channel/public/cpp/client/connection_manager_impl.cc
+++ b/ash/services/secure_channel/public/cpp/client/connection_manager_impl.cc
@@ -8,6 +8,7 @@
 #include "ash/services/device_sync/public/cpp/device_sync_client.h"
 #include "ash/services/multidevice_setup/public/cpp/multidevice_setup_client.h"
 #include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
+#include "ash/services/secure_channel/public/mojom/secure_channel.mojom-shared.h"
 #include "ash/services/secure_channel/public/mojom/secure_channel.mojom.h"
 #include "ash/services/secure_channel/public/mojom/secure_channel_types.mojom.h"
 #include "base/callback.h"
@@ -119,6 +120,10 @@
 
 void ConnectionManagerImpl::Disconnect() {
   PA_LOG(INFO) << "ConnectionManager disconnecting connection.";
+  if (last_status_ == Status::kConnecting) {
+    metrics_recorder_->RecordConnectionFailure(
+        mojom::ConnectionAttemptFailureReason::CONNECTION_CANCELLED);
+  }
   TearDownConnection();
 }
 
@@ -167,6 +172,7 @@
                   << "error: " << reason << ".";
   timer_->Stop();
   connection_attempt_.reset();
+  metrics_recorder_->RecordConnectionFailure(reason);
   OnStatusChanged();
 }
 
@@ -177,6 +183,11 @@
   timer_->Stop();
   channel_ = std::move(channel);
   channel_->AddObserver(this);
+  if (last_status_ == Status::kConnecting) {
+    metrics_recorder_->RecordConnectionSuccess(clock_->Now() -
+                                               status_change_timestamp_);
+  }
+
   OnStatusChanged();
 }
 
@@ -192,8 +203,8 @@
   PA_LOG(WARNING) << "AttemptConnection() has timed out. Closing connection "
                   << "attempt.";
 
-  connection_attempt_.reset();
-  OnStatusChanged();
+  OnConnectionAttemptFailure(
+      mojom::ConnectionAttemptFailureReason::TIMEOUT_FINDING_DEVICE);
 }
 
 void ConnectionManagerImpl::TearDownConnection() {
@@ -203,39 +214,21 @@
   if (channel_)
     channel_->RemoveObserver(this);
   channel_.reset();
+  if (last_status_ == Status::kConnected) {
+    metrics_recorder_->RecordConnectionDuration(clock_->Now() -
+                                                status_change_timestamp_);
+  }
   OnStatusChanged();
 }
 
 void ConnectionManagerImpl::OnStatusChanged() {
   NotifyStatusChanged();
-  RecordMetrics();
-}
 
-void ConnectionManagerImpl::RecordMetrics() {
-  const base::TimeDelta delta = clock_->Now() - status_change_timestamp_;
-  status_change_timestamp_ = clock_->Now();
-
-  const Status status = GetStatus();
-  switch (status) {
-    case Status::kConnecting:
-      break;
-
-    case ConnectionManager::Status::kDisconnected:
-      if (last_status_ == Status::kConnected) {
-        metrics_recorder_->RecordConnectionDuration(delta);
-      } else if (last_status_ == ConnectionManager::Status::kConnecting) {
-        metrics_recorder_->RecordConnectionResult(false);
-      }
-      break;
-
-    case ConnectionManager::Status::kConnected:
-      if (last_status_ == Status::kConnecting) {
-        metrics_recorder_->RecordConnectionLatency(delta);
-        metrics_recorder_->RecordConnectionResult(true);
-      }
-      break;
+  Status status = GetStatus();
+  if (last_status_ != status) {
+    status_change_timestamp_ = clock_->Now();
+    last_status_ = status;
   }
-  last_status_ = status;
 }
 
 }  // namespace ash::secure_channel
diff --git a/ash/services/secure_channel/public/cpp/client/connection_manager_impl_unittest.cc b/ash/services/secure_channel/public/cpp/client/connection_manager_impl_unittest.cc
index 230e57e..6284455 100644
--- a/ash/services/secure_channel/public/cpp/client/connection_manager_impl_unittest.cc
+++ b/ash/services/secure_channel/public/cpp/client/connection_manager_impl_unittest.cc
@@ -33,6 +33,8 @@
 
 const char kSecureChannelFeatureName[] = "phone_hub";
 const char kConnectionResultMetricName[] = "PhoneHub.Connection.Result";
+const char kConnectionFailureReasonMetricName[] =
+    "PhoneHub.Connection.Result.FailureReason";
 const char kConnectionDurationMetricName[] = "PhoneHub.Connection.Duration";
 const char kConnectionLatencyMetricName[] = "PhoneHub.Connectivity.Latency";
 
@@ -72,10 +74,14 @@
   void RecordConnectionResult(bool success) override {
     base::UmaHistogramBoolean(kConnectionResultMetricName, success);
   }
-  void RecordConnectionLatency(const base::TimeDelta& latency) override {
+  void RecordConnectionFailureReason(
+      secure_channel::mojom::ConnectionAttemptFailureReason reason) override {
+    base::UmaHistogramEnumeration(kConnectionFailureReasonMetricName, reason);
+  }
+  void RecordConnectionLatency(const base::TimeDelta latency) override {
     base::UmaHistogramTimes(kConnectionLatencyMetricName, latency);
   }
-  void RecordConnectionDuration(const base::TimeDelta& duration) override {
+  void RecordConnectionDuration(const base::TimeDelta duration) override {
     base::UmaHistogramLongTimes100(kConnectionDurationMetricName, duration);
   }
 };
@@ -158,6 +164,13 @@
                                         expected_count);
   }
 
+  void VerifyConnectionFailureReasonHistogram(
+      secure_channel::mojom::ConnectionAttemptFailureReason sample,
+      base::HistogramBase::Count expected_count) {
+    histogram_tester_.ExpectBucketCount(kConnectionResultMetricName, sample,
+                                        expected_count);
+  }
+
   base::MockOneShotTimer* mock_timer_;
   multidevice::RemoteDeviceRef test_remote_device_;
   multidevice::RemoteDeviceRef test_local_device_;
@@ -213,6 +226,8 @@
   EXPECT_EQ(ConnectionManager::Status::kDisconnected, GetStatus());
 
   VerifyConnectionResultHistogram(false, 1);
+  VerifyConnectionFailureReasonHistogram(
+      mojom::ConnectionAttemptFailureReason::AUTHENTICATION_ERROR, 1);
 }
 
 TEST_F(ConnectionManagerImplTest, SuccessfulAttemptConnectionButDisconnected) {
diff --git a/ash/services/secure_channel/public/cpp/client/nearby_metrics_recorder.cc b/ash/services/secure_channel/public/cpp/client/nearby_metrics_recorder.cc
new file mode 100644
index 0000000..38bb4069
--- /dev/null
+++ b/ash/services/secure_channel/public/cpp/client/nearby_metrics_recorder.cc
@@ -0,0 +1,25 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/services/secure_channel/public/cpp/client/nearby_metrics_recorder.h"
+
+namespace ash::secure_channel {
+
+NearbyMetricsRecorder::NearbyMetricsRecorder() = default;
+
+NearbyMetricsRecorder::~NearbyMetricsRecorder() = default;
+
+void NearbyMetricsRecorder::RecordConnectionSuccess(
+    const base::TimeDelta latency) {
+  RecordConnectionResult(true);
+  RecordConnectionLatency(latency);
+}
+
+void NearbyMetricsRecorder::RecordConnectionFailure(
+    mojom::ConnectionAttemptFailureReason reason) {
+  RecordConnectionResult(false);
+  RecordConnectionFailureReason(reason);
+}
+
+}  // namespace ash::secure_channel
diff --git a/ash/services/secure_channel/public/cpp/client/nearby_metrics_recorder.h b/ash/services/secure_channel/public/cpp/client/nearby_metrics_recorder.h
index c41d5c66..88628f6 100644
--- a/ash/services/secure_channel/public/cpp/client/nearby_metrics_recorder.h
+++ b/ash/services/secure_channel/public/cpp/client/nearby_metrics_recorder.h
@@ -9,15 +9,31 @@
 
 namespace ash::secure_channel {
 
+namespace mojom {
+enum class ConnectionAttemptFailureReason;
+}
+
 // Interface for recording connection metrics.
 class NearbyMetricsRecorder {
  public:
-  NearbyMetricsRecorder() = default;
-  virtual ~NearbyMetricsRecorder() = default;
+  NearbyMetricsRecorder();
+  virtual ~NearbyMetricsRecorder();
 
+  // Records connection success and the latency from the start of the
+  // connection attempt.
+  void RecordConnectionSuccess(const base::TimeDelta latency);
+
+  // Records connection failure and the specific reason.
+  void RecordConnectionFailure(mojom::ConnectionAttemptFailureReason reason);
+
+  // Records the length of time that we stayed connected.
+  virtual void RecordConnectionDuration(const base::TimeDelta duration) = 0;
+
+ protected:
+  virtual void RecordConnectionLatency(const base::TimeDelta latency) = 0;
   virtual void RecordConnectionResult(bool success) = 0;
-  virtual void RecordConnectionLatency(const base::TimeDelta& latency) = 0;
-  virtual void RecordConnectionDuration(const base::TimeDelta& duration) = 0;
+  virtual void RecordConnectionFailureReason(
+      mojom::ConnectionAttemptFailureReason reason) = 0;
 };
 
 }  // namespace ash::secure_channel
diff --git a/ash/services/secure_channel/public/mojom/secure_channel.mojom b/ash/services/secure_channel/public/mojom/secure_channel.mojom
index 45bcc10..37eb6223 100644
--- a/ash/services/secure_channel/public/mojom/secure_channel.mojom
+++ b/ash/services/secure_channel/public/mojom/secure_channel.mojom
@@ -9,60 +9,65 @@
 import "ash/services/secure_channel/public/mojom/secure_channel_types.mojom";
 import "mojo/public/mojom/base/time.mojom";
 
+// Keep in sync with SecureChannelConnectionAttemptFailureReason in
+// tools/metrics/histograms/enums.xml
 enum ConnectionAttemptFailureReason {
   // The local device could not authenticate with the remote device. This likely
   // means that one (or both) devices have not synced their keys recently.
-  AUTHENTICATION_ERROR,
+  AUTHENTICATION_ERROR = 0,
 
   // An advertisement could not be generated for this connection. This likely
   // means that one (or both) devices have not synced their BeaconSeeds
   // recently.
-  COULD_NOT_GENERATE_ADVERTISEMENT,
+  COULD_NOT_GENERATE_ADVERTISEMENT = 1,
 
   // GATT connections were attempted, but they failed. This could be caused by
   // errors creating GATT connections, dropped GATT connections, or an issue
   // relating to GATT services being unavailable.
-  GATT_CONNECTION_ERROR,
+  GATT_CONNECTION_ERROR = 2,
 
   // A Nearby Connection was attempted, but it failed. Potential causes include
   // internal API errors and flaky Bluetooth/WebRTC connections.
-  NEARBY_CONNECTION_ERROR,
+  NEARBY_CONNECTION_ERROR = 3,
 
   // The provided local device does not have a public key set.
-  LOCAL_DEVICE_INVALID_PUBLIC_KEY,
+  LOCAL_DEVICE_INVALID_PUBLIC_KEY = 4,
 
   // The provided local device does not have a persistent symmetric key set.
-  LOCAL_DEVICE_INVALID_PSK,
+  LOCAL_DEVICE_INVALID_PSK = 5,
 
   // The provided local device does not have a valid Bluetooth address.
-  LOCAL_DEVICE_INVALID_BLUETOOTH_ADDRESS,
+  LOCAL_DEVICE_INVALID_BLUETOOTH_ADDRESS = 6,
 
   // The provided remote device does not have a public key set.
-  REMOTE_DEVICE_INVALID_PUBLIC_KEY,
+  REMOTE_DEVICE_INVALID_PUBLIC_KEY = 7,
 
   // The provided remote device does not have a persistent symmetric key set.
-  REMOTE_DEVICE_INVALID_PSK,
+  REMOTE_DEVICE_INVALID_PSK = 8,
 
   // The provided remote device does not have a valid Bluetooth address.
-  REMOTE_DEVICE_INVALID_BLUETOOTH_ADDRESS,
+  REMOTE_DEVICE_INVALID_BLUETOOTH_ADDRESS = 9,
 
   // Timeouts occurred trying to contact the remote device.
-  TIMEOUT_FINDING_DEVICE,
+  TIMEOUT_FINDING_DEVICE = 10,
 
   // The local Bluetooth adapter is disabled (turned off).
-  ADAPTER_DISABLED,
+  ADAPTER_DISABLED = 11,
 
   // The local Bluetooth adapter is not present.
-  ADAPTER_NOT_PRESENT,
+  ADAPTER_NOT_PRESENT = 12,
 
   // Tried to connect using a role which is unsupported for the connection
   // medium (e.g., Nearby Connections only supports the listener role, not the
   // initiator role).
-  UNSUPPORTED_ROLE_FOR_MEDIUM,
+  UNSUPPORTED_ROLE_FOR_MEDIUM = 13,
 
   // Tried requesting a connection via Nearby Connections, but no
   // NearbyConnector was provided.
-  MISSING_NEARBY_CONNECTOR
+  MISSING_NEARBY_CONNECTOR = 14,
+
+  // The attempt was intentionally interrupted.
+  CONNECTION_CANCELLED = 15,
 };
 
 enum ConnectionCreationDetail {
diff --git a/ash/system/network/network_detailed_view_controller.cc b/ash/system/network/network_detailed_view_controller.cc
index 0f92f76..4d1590c 100644
--- a/ash/system/network/network_detailed_view_controller.cc
+++ b/ash/system/network/network_detailed_view_controller.cc
@@ -5,15 +5,108 @@
 #include "ash/system/network/network_detailed_view_controller.h"
 
 #include "ash/constants/ash_features.h"
+#include "ash/public/cpp/system_tray_client.h"
+#include "ash/session/session_controller_impl.h"
+#include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
+#include "ash/system/machine_learning/user_settings_event_logger.h"
+#include "ash/system/model/system_tray_model.h"
 #include "ash/system/network/network_detailed_network_view.h"
 #include "ash/system/network/network_list_view_controller.h"
+#include "ash/system/network/tray_network_state_model.h"
 #include "ash/system/tray/detailed_view_delegate.h"
+#include "base/metrics/user_metrics.h"
+#include "chromeos/network/network_connect.h"
+#include "chromeos/services/network_config/public/cpp/cros_network_config_util.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/views/view.h"
 
 namespace ash {
+namespace {
+
+using base::UserMetricsAction;
+
+using chromeos::network_config::NetworkTypeMatchesType;
+
+using chromeos::network_config::mojom::ActivationStateType;
+using chromeos::network_config::mojom::CellularStateProperties;
+using chromeos::network_config::mojom::ConnectionStateType;
+using chromeos::network_config::mojom::NetworkStateProperties;
+using chromeos::network_config::mojom::NetworkStatePropertiesPtr;
+using chromeos::network_config::mojom::NetworkType;
+
+void LogUserNetworkEvent(const NetworkStateProperties& network) {
+  auto* const logger = ml::UserSettingsEventLogger::Get();
+  if (logger) {
+    logger->LogNetworkUkmEvent(network);
+  }
+}
+
+bool IsSecondaryUser() {
+  SessionControllerImpl* session_controller =
+      Shell::Get()->session_controller();
+  return session_controller->IsActiveUserSessionStarted() &&
+         !session_controller->IsUserPrimary();
+}
+
+bool NetworkTypeIsConfigurable(NetworkType type) {
+  switch (type) {
+    case NetworkType::kVPN:
+    case NetworkType::kWiFi:
+      return true;
+    case NetworkType::kAll:
+    case NetworkType::kCellular:
+    case NetworkType::kEthernet:
+    case NetworkType::kMobile:
+    case NetworkType::kTether:
+    case NetworkType::kWireless:
+      return false;
+  }
+  NOTREACHED();
+  return false;
+}
+
+bool IsNetworkConnectable(const NetworkStatePropertiesPtr& network_properties) {
+  // The network must not already be connected to be able to be connected to.
+  if (network_properties->connection_state !=
+      ConnectionStateType::kNotConnected) {
+    return false;
+  }
+
+  if (NetworkTypeMatchesType(network_properties->type,
+                             NetworkType::kCellular)) {
+    // Cellular networks must be activated, uninhibited, and have an unlocked
+    // SIM to be able to be connected to.
+    const CellularStateProperties* cellular =
+        network_properties->type_state->get_cellular().get();
+
+    if (cellular->activation_state == ActivationStateType::kNotActivated &&
+        !cellular->eid.empty()) {
+      return false;
+    }
+
+    if (cellular->activation_state == ActivationStateType::kActivated) {
+      return true;
+    }
+  }
+
+  // The network can be connected to if the network is connectable.
+  if (network_properties->connectable) {
+    return true;
+  }
+
+  // Network can be connected to if the active user is the primary user and the
+  // network is configurable.
+  if (!IsSecondaryUser() &&
+      NetworkTypeIsConfigurable(network_properties->type)) {
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace
 
 NetworkDetailedViewController::NetworkDetailedViewController(
     UnifiedSystemTrayController* tray_controller)
@@ -44,7 +137,36 @@
 }
 
 void NetworkDetailedViewController::OnNetworkListItemSelected(
-    const chromeos::network_config::mojom::NetworkStatePropertiesPtr& network) {
+    const NetworkStatePropertiesPtr& network) {
+  if (Shell::Get()->session_controller()->login_status() == LoginStatus::LOCKED)
+    return;
+
+  if (network) {
+    // If the network is locked and is cellular show SIM unlock dialog in OS
+    // Settings.
+    if (network->type == NetworkType::kCellular &&
+        network->type_state->get_cellular()->sim_locked) {
+      if (!Shell::Get()->session_controller()->ShouldEnableSettings()) {
+        return;
+      }
+      Shell::Get()->system_tray_model()->client()->ShowSettingsSimUnlock();
+      return;
+    }
+
+    if (IsNetworkConnectable(network)) {
+      base::RecordAction(
+          UserMetricsAction("StatusArea_Network_ConnectConfigured"));
+      LogUserNetworkEvent(*network.get());
+      chromeos::NetworkConnect::Get()->ConnectToNetworkId(network->guid);
+      return;
+    }
+  }
+
+  // If the network is no longer available or not connectable or configurable,
+  // show the Settings UI.
+  base::RecordAction(UserMetricsAction("StatusArea_Network_ConnectionDetails"));
+  Shell::Get()->system_tray_model()->client()->ShowNetworkSettings(
+      network ? network->guid : std::string());
 }
 
 void NetworkDetailedViewController::OnMobileToggleClicked(bool new_state) {}
diff --git a/ash/system/network/network_detailed_view_controller_unittest.cc b/ash/system/network/network_detailed_view_controller_unittest.cc
index dab81ef..ff67cce 100644
--- a/ash/system/network/network_detailed_view_controller_unittest.cc
+++ b/ash/system/network/network_detailed_view_controller_unittest.cc
@@ -7,14 +7,79 @@
 #include <memory>
 
 #include "ash/constants/ash_features.h"
+#include "ash/public/cpp/test/test_system_tray_client.h"
+#include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
+#include "base/test/metrics/user_action_tester.h"
 #include "base/test/scoped_feature_list.h"
+#include "chromeos/network/network_connect.h"
+#include "chromeos/network/network_handler.h"
+#include "chromeos/services/network_config/public/cpp/cros_network_config_test_helper.h"
+#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
 
 namespace ash {
 
+using chromeos::network_config::mojom::ActivationStateType;
+using chromeos::network_config::mojom::ConnectionStateType;
+using chromeos::network_config::mojom::NetworkStatePropertiesPtr;
+using chromeos::network_config::mojom::NetworkType;
+
+const std::string kCellular = "cellular";
+constexpr char kWifi[] = "WifiGuid";
+
+const int kSignalStrength = 50;
+constexpr char kUser1Email[] = "user1@quicksettings.com";
+
+const char kNetworkConnectConfigured[] = "StatusArea_Network_ConnectConfigured";
+const char kNetworkConnectionDetails[] = "StatusArea_Network_ConnectionDetails";
+
+class NetworkConnectTestDelegate : public chromeos::NetworkConnect::Delegate {
+ public:
+  NetworkConnectTestDelegate() {}
+
+  NetworkConnectTestDelegate(const NetworkConnectTestDelegate&) = delete;
+  NetworkConnectTestDelegate& operator=(const NetworkConnectTestDelegate&) =
+      delete;
+
+  ~NetworkConnectTestDelegate() override {}
+
+  void ShowNetworkConfigure(const std::string& network_id) override {}
+  void ShowNetworkSettings(const std::string& network_id) override {}
+  bool ShowEnrollNetwork(const std::string& network_id) override {
+    return false;
+  }
+  void ShowMobileSetupDialog(const std::string& network_id) override {}
+  void ShowCarrierAccountDetail(const std::string& network_id) override {}
+  void ShowNetworkConnectError(const std::string& error_name,
+                               const std::string& network_id) override {}
+  void ShowMobileActivationError(const std::string& network_id) override {}
+};
+
 class NetworkDetailedViewControllerTest : public AshTestBase {
  public:
   void SetUp() override {
+    // Initialize CrosNetworkConfigTestHelper here, so we can initialize
+    // a unique network handler and also use NetworkConnectTestDelegate to
+    // initialize NetworkConnect.
+    network_config_helper_ = std::make_unique<
+        chromeos::network_config::CrosNetworkConfigTestHelper>();
+
+    chromeos::NetworkHandler::Initialize();
+    base::RunLoop().RunUntilIdle();
+
+    // Creating a service here, since we would be testing that wifi,
+    // networks which can be connected to are actually connected to. This
+    // checks that chromeos::NetworkConnect eventually connects us to the
+    // network.
+    wifi_service_path_ =
+        network_state_helper()->ConfigureService(base::StringPrintf(
+            R"({"GUID": "%s", "Type": "wifi",
+            "State": "idle", "Strength": 100,
+            "Connectable": true})",
+            kWifi));
+
+    network_connect_delegate_ = std::make_unique<NetworkConnectTestDelegate>();
+    chromeos::NetworkConnect::Initialize(network_connect_delegate_.get());
     AshTestBase::SetUp();
 
     feature_list_.InitAndEnableFeature(features::kQuickSettingsNetworkRevamp);
@@ -26,18 +91,201 @@
 
   void TearDown() override {
     network_detailed_view_controller_.reset();
-
     AshTestBase::TearDown();
+    chromeos::NetworkConnect::Shutdown();
+    chromeos::NetworkHandler::Shutdown();
+    network_connect_delegate_.reset();
+  }
+
+  void SelectNetworkListItem(const NetworkStatePropertiesPtr& network) {
+    (static_cast<NetworkDetailedView::Delegate*>(
+         network_detailed_view_controller_.get()))
+        ->OnNetworkListItemSelected(mojo::Clone(network));
+  }
+
+  NetworkStatePropertiesPtr CreateStandaloneNetworkProperties(
+      const std::string& id,
+      NetworkType type,
+      ConnectionStateType connection_state) {
+    return network_config_helper_->CreateStandaloneNetworkProperties(
+        id, type, connection_state, kSignalStrength);
+  }
+
+  std::string GetWifiNetworkState() {
+    return network_state_helper()->GetServiceStringProperty(
+        wifi_service_path_, shill::kStateProperty);
+  }
+
+  void DisconnectWifiNetwork() {
+    network_state_helper()->SetServiceProperty(
+        wifi_service_path_, std::string(shill::kStateProperty),
+        base::Value(shill::kStateIdle));
+    base::RunLoop().RunUntilIdle();
   }
 
  private:
+  chromeos::NetworkStateTestHelper* network_state_helper() {
+    return &network_config_helper_->network_state_helper();
+  }
+
   base::test::ScopedFeatureList feature_list_;
+  std::unique_ptr<chromeos::network_config::CrosNetworkConfigTestHelper>
+      network_config_helper_;
+  std::unique_ptr<NetworkConnectTestDelegate> network_connect_delegate_;
   std::unique_ptr<NetworkDetailedViewController>
       network_detailed_view_controller_;
+  std::string wifi_service_path_;
 };
 
-TEST_F(NetworkDetailedViewControllerTest, CanConstruct) {
-  EXPECT_TRUE(true);
+TEST_F(NetworkDetailedViewControllerTest,
+       NetworkListItemSelectedWithLockedScreen) {
+  base::UserActionTester user_action_tester;
+
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kNetworkConnectionDetails));
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kNetworkConnectConfigured));
+
+  NetworkStatePropertiesPtr cellular_network =
+      CreateStandaloneNetworkProperties(kCellular, NetworkType::kCellular,
+                                        ConnectionStateType::kConnected);
+
+  EXPECT_EQ(0, GetSystemTrayClient()->show_network_settings_count());
+
+  // Set login status to locked.
+  GetSessionControllerClient()->SetSessionState(
+      session_manager::SessionState::LOCKED);
+  SelectNetworkListItem(cellular_network);
+  EXPECT_EQ(0, GetSystemTrayClient()->show_network_settings_count());
+  EXPECT_EQ(0, GetSystemTrayClient()->show_sim_unlock_settings_count());
+
+  // Show network details page for a connected cellular network.
+  GetSessionControllerClient()->SetSessionState(
+      session_manager::SessionState::ACTIVE);
+  SelectNetworkListItem(cellular_network);
+  EXPECT_EQ(1, GetSystemTrayClient()->show_network_settings_count());
+  EXPECT_EQ(0, GetSystemTrayClient()->show_sim_unlock_settings_count());
+  EXPECT_EQ(1, user_action_tester.GetActionCount(kNetworkConnectionDetails));
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kNetworkConnectConfigured));
+}
+
+TEST_F(NetworkDetailedViewControllerTest, EmptyNetworkListItemSelected) {
+  base::UserActionTester user_action_tester;
+
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kNetworkConnectionDetails));
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kNetworkConnectConfigured));
+  EXPECT_EQ(0, GetSystemTrayClient()->show_network_settings_count());
+  EXPECT_EQ(0, GetSystemTrayClient()->show_sim_unlock_settings_count());
+
+  SelectNetworkListItem(/*network=*/nullptr);
+  EXPECT_EQ(1, GetSystemTrayClient()->show_network_settings_count());
+  EXPECT_EQ(0, GetSystemTrayClient()->show_sim_unlock_settings_count());
+  EXPECT_EQ(1, user_action_tester.GetActionCount(kNetworkConnectionDetails));
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kNetworkConnectConfigured));
+}
+
+TEST_F(NetworkDetailedViewControllerTest, CellularNetworkListItemSelected) {
+  base::UserActionTester user_action_tester;
+
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kNetworkConnectionDetails));
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kNetworkConnectConfigured));
+  EXPECT_EQ(0, GetSystemTrayClient()->show_network_settings_count());
+  EXPECT_EQ(0, GetSystemTrayClient()->show_sim_unlock_settings_count());
+
+  NetworkStatePropertiesPtr cellular_network =
+      CreateStandaloneNetworkProperties(kCellular, NetworkType::kCellular,
+                                        ConnectionStateType::kConnected);
+
+  // When cellular eSIM network is not activated open network details page.
+  cellular_network->connection_state = ConnectionStateType::kNotConnected;
+  cellular_network->type_state->get_cellular()->activation_state =
+      ActivationStateType::kNotActivated;
+  cellular_network->type_state->get_cellular()->eid = "eid";
+  SelectNetworkListItem(cellular_network);
+  EXPECT_EQ(1, GetSystemTrayClient()->show_network_settings_count());
+  EXPECT_EQ(0, GetSystemTrayClient()->show_sim_unlock_settings_count());
+  EXPECT_EQ(1, user_action_tester.GetActionCount(kNetworkConnectionDetails));
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kNetworkConnectConfigured));
+
+  // When cellular network is SIM locked, we show the SIM unlock settings page.
+  cellular_network->type_state->get_cellular()->sim_locked = true;
+  SelectNetworkListItem(cellular_network);
+  EXPECT_EQ(1, GetSystemTrayClient()->show_network_settings_count());
+  EXPECT_EQ(1, GetSystemTrayClient()->show_sim_unlock_settings_count());
+  EXPECT_EQ(1, user_action_tester.GetActionCount(kNetworkConnectionDetails));
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kNetworkConnectConfigured));
+}
+
+TEST_F(NetworkDetailedViewControllerTest, WifiNetworkListItemSelected) {
+  base::UserActionTester user_action_tester;
+
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kNetworkConnectionDetails));
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kNetworkConnectConfigured));
+  EXPECT_EQ(0, GetSystemTrayClient()->show_network_settings_count());
+  EXPECT_EQ(0, GetSystemTrayClient()->show_sim_unlock_settings_count());
+
+  // Clicking on an already connected network opens settings page.
+  // Since this network is already connected, selecting this network
+  // in network list vew should result in no change in NetworkState of
+  // the network service.
+  NetworkStatePropertiesPtr wifi_network = CreateStandaloneNetworkProperties(
+      kWifi, NetworkType::kWiFi, ConnectionStateType::kOnline);
+
+  SelectNetworkListItem(wifi_network);
+  EXPECT_EQ(1, GetSystemTrayClient()->show_network_settings_count());
+  EXPECT_EQ(0, GetSystemTrayClient()->show_sim_unlock_settings_count());
+  EXPECT_EQ(1, user_action_tester.GetActionCount(kNetworkConnectionDetails));
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kNetworkConnectConfigured));
+  EXPECT_EQ(shill::kStateIdle, GetWifiNetworkState());
+
+  // Set to be connectable and make sure network is connected to.
+  wifi_network->connection_state = ConnectionStateType::kNotConnected;
+  wifi_network->connectable = true;
+  SelectNetworkListItem(wifi_network);
+
+  // Wait for Network to be connected to.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1, GetSystemTrayClient()->show_network_settings_count());
+  EXPECT_EQ(0, GetSystemTrayClient()->show_sim_unlock_settings_count());
+  EXPECT_EQ(1, user_action_tester.GetActionCount(kNetworkConnectionDetails));
+  EXPECT_EQ(1, user_action_tester.GetActionCount(kNetworkConnectConfigured));
+  EXPECT_EQ(shill::kStateOnline, GetWifiNetworkState());
+
+  // Reset network state to idle.
+  DisconnectWifiNetwork();
+  EXPECT_EQ(shill::kStateIdle, GetWifiNetworkState());
+
+  /// Network can be connected to since active user is primary and the
+  // network is configurable.
+  wifi_network->connection_state = ConnectionStateType::kNotConnected;
+  wifi_network->connectable = false;
+
+  SelectNetworkListItem(wifi_network);
+
+  // Wait for network to be connected to.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1, GetSystemTrayClient()->show_network_settings_count());
+  EXPECT_EQ(0, GetSystemTrayClient()->show_sim_unlock_settings_count());
+  EXPECT_EQ(1, user_action_tester.GetActionCount(kNetworkConnectionDetails));
+  EXPECT_EQ(2, user_action_tester.GetActionCount(kNetworkConnectConfigured));
+  EXPECT_EQ(shill::kStateOnline, GetWifiNetworkState());
+
+  // Reset network to idle.
+  DisconnectWifiNetwork();
+  EXPECT_EQ(shill::kStateIdle, GetWifiNetworkState());
+
+  // Login as secondary user, and make sure network is not connected to,
+  // but settings page is opened.
+  GetSessionControllerClient()->AddUserSession(kUser1Email);
+  SimulateUserLogin(kUser1Email);
+  GetSessionControllerClient()->SetSessionState(
+      session_manager::SessionState::LOGIN_SECONDARY);
+  base::RunLoop().RunUntilIdle();
+
+  SelectNetworkListItem(wifi_network);
+  EXPECT_EQ(2, GetSystemTrayClient()->show_network_settings_count());
+  EXPECT_EQ(0, GetSystemTrayClient()->show_sim_unlock_settings_count());
+  EXPECT_EQ(2, user_action_tester.GetActionCount(kNetworkConnectionDetails));
+  EXPECT_EQ(2, user_action_tester.GetActionCount(kNetworkConnectConfigured));
+  EXPECT_EQ(shill::kStateIdle, GetWifiNetworkState());
 }
 
 }  // namespace ash
diff --git a/ash/system/network/network_list_mobile_header_view_impl.cc b/ash/system/network/network_list_mobile_header_view_impl.cc
index 685e727..8d53909e 100644
--- a/ash/system/network/network_list_mobile_header_view_impl.cc
+++ b/ash/system/network/network_list_mobile_header_view_impl.cc
@@ -36,8 +36,8 @@
   const DeviceStateProperties* cellular_device =
       Shell::Get()->system_tray_model()->network_state_model()->GetDevice(
           NetworkType::kCellular);
-  if (!cellular_device)
-    return 0;
+
+  DCHECK(cellular_device);
 
   switch (cellular_device->inhibit_reason) {
     case chromeos::network_config::mojom::InhibitReason::kInstallingProfile:
diff --git a/ash/system/network/network_section_header_view.cc b/ash/system/network/network_section_header_view.cc
index 5e5f060..2f8a2ad 100644
--- a/ash/system/network/network_section_header_view.cc
+++ b/ash/system/network/network_section_header_view.cc
@@ -110,9 +110,8 @@
   const DeviceStateProperties* cellular_device =
       Shell::Get()->system_tray_model()->network_state_model()->GetDevice(
           NetworkType::kCellular);
-  if (!cellular_device) {
-    return 0;
-  }
+
+  DCHECK(cellular_device);
 
   switch (cellular_device->inhibit_reason) {
     case chromeos::network_config::mojom::InhibitReason::kInstallingProfile:
@@ -370,6 +369,12 @@
 void MobileSectionHeaderView::DeviceStateListChanged() {
   if (!add_esim_button_)
     return;
+
+  if (!IsESimSupported()) {
+    add_esim_button_->SetVisible(/*visible=*/false);
+    return;
+  }
+
   add_esim_button_->SetEnabled(can_add_esim_button_be_enabled_ &&
                                !IsCellularDeviceInhibited());
   add_esim_button_->SetTooltipText(
diff --git a/ash/system/palette/tools/metalayer_mode.cc b/ash/system/palette/tools/metalayer_mode.cc
index 62fd0821..73a1936 100644
--- a/ash/system/palette/tools/metalayer_mode.cc
+++ b/ash/system/palette/tools/metalayer_mode.cc
@@ -19,6 +19,7 @@
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_popup_utils.h"
 #include "base/bind.h"
+#include "base/metrics/histogram_functions.h"
 #include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/events/event.h"
@@ -38,6 +39,10 @@
 // mode is deprecated.
 const char kDeprecateAssistantStylusToastId[] = "deprecate_assistant_stylus";
 
+// Histogram for Assistant stylus features deprecation toast events.
+const char kDeprecateStylusFeaturesToastEvent[] =
+    "Ash.Shelf.Palette.Assistant.DeprecateStylusFeaturesToastEvent";
+
 // If the last stroke happened within this amount of time,
 // assume writing/sketching usage.
 const int kMaxStrokeGapWhenWritingMs = 1000;
@@ -148,12 +153,15 @@
   if (palette_utils::PaletteContainsPointInScreen(event->root_location()))
     return;
 
+  DeprecateStylusFeaturesToastEvent toast_event = kNotDeprecatedToastNotShown;
+
   // Assistant stylus features are in the process of being deprecated.
   // After deprecation, which is currently gated by a feature flag, long
   // press stylus events will not trigger the metalayer mode.
   if (ash::features::IsDeprecateAssistantStylusFeaturesEnabled()) {
     // Only show the toast once when the metalayer is triggered for the first
     // time.
+    toast_event = kDeprecatedToastNotShown;
     if (!GetPrefs()->GetBoolean(
             chromeos::assistant::prefs::kAssistantDeprecateStylusToast)) {
       // Set the deprecate stylus toast assistant pref so that the toast doesn't
@@ -168,10 +176,18 @@
                     ToastData::kDefaultToastDuration,
                     /*visible_on_lock_screen=*/false,
                     /*has_dismiss_button=*/true));
+      toast_event = kDeprecatedToastShown;
     }
+    // Record toast event (feature is deprecated).
+    base::UmaHistogramEnumeration(kDeprecateStylusFeaturesToastEvent,
+                                  toast_event);
     return;
   }
 
+  // Record toast event (feature is not deprecated).
+  base::UmaHistogramEnumeration(kDeprecateStylusFeaturesToastEvent,
+                                toast_event);
+
   if (loading()) {
     // Repetitive presses will create toasts with the same id which will be
     // ignored.
diff --git a/ash/system/palette/tools/metalayer_mode.h b/ash/system/palette/tools/metalayer_mode.h
index 3e0e3b0..ae01a04 100644
--- a/ash/system/palette/tools/metalayer_mode.h
+++ b/ash/system/palette/tools/metalayer_mode.h
@@ -15,6 +15,24 @@
 
 namespace ash {
 
+// This will be used for the UMA stats to note deprecation toast events
+// for Assistant stylus features.
+
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused. Also remember to update the
+// DeprecateStylusFeaturesToastEvent enum listing in
+// tools/metrics/histograms/enums.xml.
+enum DeprecateStylusFeaturesToastEvent {
+  // Features not deprecated, toast not shown.
+  kNotDeprecatedToastNotShown = 0,
+  // Features deprecated, toast shown (first time).
+  kDeprecatedToastShown = 1,
+  // Features deprecated, toast not shown (already shown).
+  kDeprecatedToastNotShown = 2,
+
+  kMaxValue = kDeprecatedToastNotShown
+};
+
 // A palette tool that lets the user select a screen region to be passed
 // to the Assistant framework.
 //
diff --git a/ash/webui/eche_app_ui/BUILD.gn b/ash/webui/eche_app_ui/BUILD.gn
index f71a772..36e3237 100644
--- a/ash/webui/eche_app_ui/BUILD.gn
+++ b/ash/webui/eche_app_ui/BUILD.gn
@@ -93,6 +93,7 @@
     "//ash/services/multidevice_setup/public/cpp:prefs",
     "//ash/services/secure_channel/public/cpp/client",
     "//ash/services/secure_channel/public/cpp/shared",
+    "//ash/services/secure_channel/public/mojom",
     "//ash/webui/eche_app_ui/mojom",
     "//ash/webui/eche_app_ui/proto",
     "//ash/webui/resources:eche_app_resources",
diff --git a/ash/webui/eche_app_ui/eche_connection_metrics_recorder.cc b/ash/webui/eche_app_ui/eche_connection_metrics_recorder.cc
index 19dde78..be2b350 100644
--- a/ash/webui/eche_app_ui/eche_connection_metrics_recorder.cc
+++ b/ash/webui/eche_app_ui/eche_connection_metrics_recorder.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "ash/webui/eche_app_ui/eche_connection_metrics_recorder.h"
+#include "ash/services/secure_channel/public/mojom/secure_channel.mojom.h"
 #include "base/metrics/histogram_functions.h"
 
 namespace ash::eche_app {
@@ -14,13 +15,18 @@
   base::UmaHistogramBoolean("Eche.Connection.Result", success);
 }
 
+void EcheConnectionMetricsRecorder::RecordConnectionFailureReason(
+    secure_channel::mojom::ConnectionAttemptFailureReason reason) {
+  base::UmaHistogramEnumeration("Eche.Connection.Result.FailureReason", reason);
+}
+
 void EcheConnectionMetricsRecorder::RecordConnectionLatency(
-    const base::TimeDelta& latency) {
+    const base::TimeDelta latency) {
   base::UmaHistogramTimes("Eche.Connectivity.Latency", latency);
 }
 
 void EcheConnectionMetricsRecorder::RecordConnectionDuration(
-    const base::TimeDelta& duration) {
+    const base::TimeDelta duration) {
   base::UmaHistogramLongTimes100("Eche.Connection.Duration", duration);
 }
 
diff --git a/ash/webui/eche_app_ui/eche_connection_metrics_recorder.h b/ash/webui/eche_app_ui/eche_connection_metrics_recorder.h
index 90504e2..ab14d62 100644
--- a/ash/webui/eche_app_ui/eche_connection_metrics_recorder.h
+++ b/ash/webui/eche_app_ui/eche_connection_metrics_recorder.h
@@ -22,8 +22,10 @@
 
   // secure_channel::NearbyMetricsRecorder:
   void RecordConnectionResult(bool success) override;
-  void RecordConnectionLatency(const base::TimeDelta& latency) override;
-  void RecordConnectionDuration(const base::TimeDelta& duration) override;
+  void RecordConnectionFailureReason(
+      secure_channel::mojom::ConnectionAttemptFailureReason reason) override;
+  void RecordConnectionLatency(const base::TimeDelta latency) override;
+  void RecordConnectionDuration(const base::TimeDelta duration) override;
 };
 
 }  // namespace ash::eche_app
diff --git a/base/json/json_parser.cc b/base/json/json_parser.cc
index 91824d9e..c011e14 100644
--- a/base/json/json_parser.cc
+++ b/base/json/json_parser.cc
@@ -5,6 +5,7 @@
 #include "base/json/json_parser.h"
 
 #include <cmath>
+#include <iterator>
 #include <utility>
 #include <vector>
 
@@ -423,7 +424,7 @@
     return absl::nullopt;
   }
 
-  std::vector<Value::DeprecatedDictStorage::value_type> dict_storage;
+  std::vector<std::pair<std::string, Value>> values;
 
   Token token = GetNextToken();
   while (token != T_OBJECT_END) {
@@ -453,7 +454,7 @@
       return absl::nullopt;
     }
 
-    dict_storage.emplace_back(key.DestructiveAsString(), std::move(*value));
+    values.emplace_back(key.DestructiveAsString(), std::move(*value));
 
     token = GetNextToken();
     if (token == T_LIST_SEPARATOR) {
@@ -472,8 +473,9 @@
   ConsumeChar();  // Closing '}'.
   // Reverse |dict_storage| to keep the last of elements with the same key in
   // the input.
-  ranges::reverse(dict_storage);
-  return Value(Value::DeprecatedDictStorage(std::move(dict_storage)));
+  ranges::reverse(values);
+  return Value(Value::Dict(std::make_move_iterator(values.begin()),
+                           std::make_move_iterator(values.end())));
 }
 
 absl::optional<Value> JSONParser::ConsumeList() {
diff --git a/base/message_loop/message_pump_mac.h b/base/message_loop/message_pump_mac.h
index 4d38358..96881f96 100644
--- a/base/message_loop/message_pump_mac.h
+++ b/base/message_loop/message_pump_mac.h
@@ -83,6 +83,8 @@
   MessagePumpCFRunLoopBase(const MessagePumpCFRunLoopBase&) = delete;
   MessagePumpCFRunLoopBase& operator=(const MessagePumpCFRunLoopBase&) = delete;
 
+  static void InitializeFeatures();
+
   // MessagePump:
   void Run(Delegate* delegate) override;
   void Quit() override;
@@ -157,10 +159,6 @@
   // The maximum number of run loop modes that can be monitored.
   static constexpr int kNumModes = 4;
 
-  // All sources of delayed work scheduling converge to this, using TimeDelta
-  // avoids querying Now() for key callers.
-  void ScheduleDelayedWorkImpl(TimeDelta delta);
-
   // Timer callback scheduled by ScheduleDelayedWork.  This does not do any
   // work, but it signals |work_source_| so that delayed work can be performed
   // within the appropriate priority constraints.
@@ -252,6 +250,9 @@
 
   base::TimerSlack timer_slack_;
 
+  // Time at which `delayed_work_timer_` is set to fire.
+  base::TimeTicks delayed_work_scheduled_at_ = base::TimeTicks::Max();
+
   // The recursion depth of the currently-executing CFRunLoopRun loop on the
   // run loop's thread.  0 if no run loops are running inside of whatever scope
   // the object was created in.
diff --git a/base/message_loop/message_pump_mac.mm b/base/message_loop/message_pump_mac.mm
index 8ce36eaa..1cf2edf 100644
--- a/base/message_loop/message_pump_mac.mm
+++ b/base/message_loop/message_pump_mac.mm
@@ -6,6 +6,7 @@
 
 #import <Foundation/Foundation.h>
 
+#include <atomic>
 #include <limits>
 #include <memory>
 
@@ -34,6 +35,18 @@
 
 namespace {
 
+// Enables two optimizations in MessagePumpCFRunLoop:
+// - Skip calling CFRunLoopTimerSetNextFireDate if the next delayed wake up
+//  time hasn't changed.
+// - Cancel an already scheduled timer wake up if there is no delayed work.
+const base::Feature kMessagePumpMacDelayedWorkOptimizations{
+    "MessagePumpMacDelayedWorkOptimizations",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Caches the state of the "MessagePumpMacDelayedWorkOptimizations"
+// feature for efficiency.
+std::atomic_bool g_enable_optimizations = false;
+
 // Mask that determines which modes to use.
 enum { kCommonModeMask = 0x1, kAllModesMask = 0xf };
 
@@ -180,20 +193,38 @@
 void MessagePumpCFRunLoopBase::ScheduleDelayedWork(
     const Delegate::NextWorkInfo& next_work_info) {
   DCHECK(!next_work_info.is_immediate());
-  if (!next_work_info.delayed_run_time.is_max())
-    ScheduleDelayedWorkImpl(next_work_info.remaining_delay());
-}
 
-void MessagePumpCFRunLoopBase::ScheduleDelayedWorkImpl(TimeDelta delta) {
-  // The tolerance needs to be set before the fire date or it may be ignored.
-
-  if (timer_slack_ == TIMER_SLACK_MAXIMUM) {
-    CFRunLoopTimerSetTolerance(delayed_work_timer_, delta.InSecondsF() * 0.5);
+  if (g_enable_optimizations.load(std::memory_order_relaxed)) {
+    // No-op if the delayed run time hasn't changed.
+    if (next_work_info.delayed_run_time == delayed_work_scheduled_at_)
+      return;
   } else {
-    CFRunLoopTimerSetTolerance(delayed_work_timer_, 0);
+    // Preserve the old behavior of not adjusting the timer when
+    // `delayed_run_time.is_max()`.
+    //
+    // TODO(crbug.com/1335524): Remove this once the
+    // "MessagePumpMacDelayedWorkOptimizations" feature is shipped.
+    if (next_work_info.delayed_run_time.is_max())
+      return;
   }
-  CFRunLoopTimerSetNextFireDate(
-      delayed_work_timer_, CFAbsoluteTimeGetCurrent() + delta.InSecondsF());
+
+  if (next_work_info.delayed_run_time.is_max()) {
+    CFRunLoopTimerSetNextFireDate(delayed_work_timer_, kCFTimeIntervalMax);
+  } else {
+    const double delay_seconds = next_work_info.remaining_delay().InSecondsF();
+
+    // The tolerance needs to be set before the fire date or it may be ignored.
+    if (timer_slack_ == TIMER_SLACK_MAXIMUM) {
+      CFRunLoopTimerSetTolerance(delayed_work_timer_, delay_seconds * 0.5);
+    } else {
+      CFRunLoopTimerSetTolerance(delayed_work_timer_, 0);
+    }
+
+    CFRunLoopTimerSetNextFireDate(delayed_work_timer_,
+                                  CFAbsoluteTimeGetCurrent() + delay_seconds);
+  }
+
+  delayed_work_scheduled_at_ = next_work_info.delayed_run_time;
 }
 
 void MessagePumpCFRunLoopBase::SetTimerSlack(TimerSlack timer_slack) {
@@ -293,6 +324,13 @@
   CFRelease(run_loop_);
 }
 
+// static
+void MessagePumpCFRunLoopBase::InitializeFeatures() {
+  g_enable_optimizations.store(
+      base::FeatureList::IsEnabled(kMessagePumpMacDelayedWorkOptimizations),
+      std::memory_order_relaxed);
+}
+
 void MessagePumpCFRunLoopBase::OnAttach() {
   CHECK_EQ(nesting_level_, 0);
   // On iOS: the MessagePump is attached while it's already running.
@@ -379,6 +417,8 @@
   // The timer fired, assume we have work and let RunWork() figure out what to
   // do and what to schedule after.
   base::mac::CallWithEHFrame(^{
+    DCHECK_GE(base::TimeTicks::Now(), self->delayed_work_scheduled_at_);
+    self->delayed_work_scheduled_at_ = base::TimeTicks::Max();
     self->RunWork();
   });
 }
@@ -423,11 +463,12 @@
   if (next_work_info.is_immediate()) {
     CFRunLoopSourceSignal(work_source_);
     return true;
+  } else {
+    // This adjusts the next delayed wake up time (potentially cancels an
+    // already scheduled wake up if there is no delayed work).
+    ScheduleDelayedWork(next_work_info);
+    return false;
   }
-
-  if (!next_work_info.delayed_run_time.is_max())
-    ScheduleDelayedWorkImpl(next_work_info.remaining_delay());
-  return false;
 }
 
 // Called from the run loop.
diff --git a/base/test/values_test_util.cc b/base/test/values_test_util.cc
index c2c2dae..3a1b563b 100644
--- a/base/test/values_test_util.cc
+++ b/base/test/values_test_util.cc
@@ -17,32 +17,34 @@
 namespace base {
 
 void ExpectDictBooleanValue(bool expected_value,
-                            const Value& value,
-                            const std::string& key) {
-  EXPECT_EQ(value.FindBoolPath(key), absl::optional<bool>(expected_value))
-      << key;
+                            const Value::Dict& dict,
+                            StringPiece path) {
+  EXPECT_EQ(dict.FindBoolByDottedPath(path),
+            absl::make_optional(expected_value))
+      << path;
 }
 
 void ExpectDictIntegerValue(int expected_value,
-                            const Value& value,
-                            const std::string& key) {
-  EXPECT_EQ(value.FindIntPath(key), absl::optional<int>(expected_value)) << key;
+                            const Value::Dict& dict,
+                            StringPiece path) {
+  EXPECT_EQ(dict.FindIntByDottedPath(path), absl::make_optional(expected_value))
+      << path;
 }
 
-void ExpectDictStringValue(const std::string& expected_value,
-                           const Value& value,
-                           const std::string& key) {
-  EXPECT_EQ(OptionalFromPtr(value.FindStringPath(key)),
-            absl::optional<std::string>(expected_value))
-      << key;
+void ExpectDictStringValue(StringPiece expected_value,
+                           const Value::Dict& dict,
+                           StringPiece path) {
+  EXPECT_EQ(OptionalFromPtr(dict.FindStringByDottedPath(path)),
+            absl::make_optional(expected_value))
+      << path;
 }
 
 void ExpectDictValue(const Value& expected_value,
-                     const Value& value,
-                     const std::string& key) {
-  const Value* found_value = value.FindPath(key);
-  EXPECT_TRUE(found_value) << key;
-  EXPECT_EQ(*found_value, expected_value) << key;
+                     const Value::Dict& dict,
+                     StringPiece path) {
+  const Value* found_value = dict.FindByDottedPath(path);
+  ASSERT_TRUE(found_value) << path;
+  EXPECT_EQ(*found_value, expected_value) << path;
 }
 
 void ExpectStringValue(const std::string& expected_str, const Value& actual) {
diff --git a/base/test/values_test_util.h b/base/test/values_test_util.h
index da798bdb..0b36be7d 100644
--- a/base/test/values_test_util.h
+++ b/base/test/values_test_util.h
@@ -15,24 +15,24 @@
 
 namespace base {
 
-// All the functions below expect that the value for the given key in
+// All the functions below expect that the value for the given path in
 // the given dictionary equals the given expected value.
 
 void ExpectDictBooleanValue(bool expected_value,
-                            const Value& value,
-                            const std::string& key);
+                            const Value::Dict& dict,
+                            StringPiece path);
 
 void ExpectDictIntegerValue(int expected_value,
-                            const Value& value,
-                            const std::string& key);
+                            const Value::Dict& dict,
+                            StringPiece path);
 
-void ExpectDictStringValue(const std::string& expected_value,
-                           const Value& value,
-                           const std::string& key);
+void ExpectDictStringValue(StringPiece expected_value,
+                           const Value::Dict& dict,
+                           StringPiece path);
 
 void ExpectDictValue(const Value& expected_value,
-                     const Value& value,
-                     const std::string& key);
+                     const Value::Dict& dict,
+                     StringPiece path);
 
 void ExpectStringValue(const std::string& expected_str, const Value& actual);
 
diff --git a/base/values.cc b/base/values.cc
index 42857cc..09f92b0 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -231,24 +231,6 @@
 
 Value::Value(List&& value) noexcept : data_(std::move(value)) {}
 
-Value::Value(const DeprecatedDictStorage& value)
-    : data_(absl::in_place_type_t<Dict>()) {
-  dict().reserve(value.size());
-  for (const auto& it : value) {
-    dict().try_emplace(dict().end(), it.first,
-                       std::make_unique<Value>(it.second.Clone()));
-  }
-}
-
-Value::Value(DeprecatedDictStorage&& value)
-    : data_(absl::in_place_type_t<Dict>()) {
-  dict().reserve(value.size());
-  for (auto& it : value) {
-    dict().try_emplace(dict().end(), std::move(it.first),
-                       std::make_unique<Value>(std::move(it.second)));
-  }
-}
-
 Value::Value(span<const Value> value) : data_(absl::in_place_type_t<List>()) {
   list().reserve(value.size());
   for (const auto& val : value)
@@ -1400,18 +1382,6 @@
   return const_dict_iterator_proxy(&dict());
 }
 
-Value::DeprecatedDictStorage Value::TakeDictDeprecated() && {
-  DeprecatedDictStorage storage;
-  storage.reserve(dict().size());
-  for (auto& pair : dict()) {
-    storage.try_emplace(storage.end(), std::move(pair.first),
-                        std::move(*pair.second));
-  }
-
-  dict().clear();
-  return storage;
-}
-
 size_t Value::DictSize() const {
   return GetDict().size();
 }
diff --git a/base/values.h b/base/values.h
index 727328f..ddab7ac 100644
--- a/base/values.h
+++ b/base/values.h
@@ -11,6 +11,7 @@
 #include <array>
 #include <initializer_list>
 #include <iosfwd>
+#include <iterator>
 #include <memory>
 #include <string>
 #include <utility>
@@ -206,13 +207,12 @@
   using BlobStorage = std::vector<uint8_t>;
 
   using DeprecatedListStorage = std::vector<Value>;
-  using DeprecatedDictStorage = flat_map<std::string, Value>;
   // TODO(https://crbug.com/1291666): Make this private.
   using ListStorage = DeprecatedListStorage;
 
   // Like `DictStorage`, but with std::unique_ptr in the mapped type. This is
-  // due to legacy reasons, and should be replaced with a private version of
-  // DeprecatedDictStorage once no caller relies on stability of pointers
+  // due to legacy reasons, and should be replaced with
+  // flat_map<std::string, Value> once no caller relies on stability of pointers
   // anymore.
   using LegacyDictStorage = flat_map<std::string, std::unique_ptr<Value>>;
 
@@ -302,10 +302,6 @@
   // Constructor for `Value::Type::LIST`.
   explicit Value(List&& value) noexcept;
 
-  // DEPRECATED: prefer `Value(Dict&&)`.
-  explicit Value(const DeprecatedDictStorage& value);
-  explicit Value(DeprecatedDictStorage&& value);
-
   // DEPRECATED: prefer `Value(List&&)`.
   explicit Value(span<const Value> value);
   explicit Value(ListStorage&& value) noexcept;
@@ -376,6 +372,28 @@
     Dict(const Dict&) = delete;
     Dict& operator=(const Dict&) = delete;
 
+    // Takes move_iterators iterators that return std::pair<std::string, Value>,
+    // and moves their values into a new Dict. Adding all entries at once
+    // results in a faster initial sort operation. Takes move iterators to avoid
+    // having to clone the input.
+    template <class IteratorType>
+    explicit Dict(std::move_iterator<IteratorType> first,
+                  std::move_iterator<IteratorType> last) {
+      // Need to move into a vector first, since `storage_` currently uses
+      // unique_ptrs.
+      std::vector<std::pair<std::string, std::unique_ptr<Value>>> values;
+      for (auto current = first; current != last; ++current) {
+        // With move iterators, no need to call Clone(), but do need to move
+        // to a temporary first, as accessing either field individually will
+        // directly from the iterator will delete the other field.
+        auto value = *current;
+        values.emplace_back(std::move(value.first),
+                            std::make_unique<Value>(std::move(value.second)));
+      }
+      storage_ =
+          flat_map<std::string, std::unique_ptr<Value>>(std::move(values));
+    }
+
     ~Dict();
 
     // TODO(dcheng): Probably need to allow construction from a pair of
@@ -997,13 +1015,6 @@
   dict_iterator_proxy DictItems();
   const_dict_iterator_proxy DictItems() const;
 
-  // Transfers ownership of the underlying dict to the caller. Subsequent
-  // calls to DictItems() will return an empty dict.
-  //
-  // DEPRECATED: prefer direct use of `base::Value::Dict` where possible, or
-  // `std::move(value.GetDict())` otherwise.
-  DeprecatedDictStorage TakeDictDeprecated() &&;
-
   // DEPRECATED: prefer `Value::Dict::size()`.
   size_t DictSize() const;
 
diff --git a/base/values_unittest.cc b/base/values_unittest.cc
index 8a518c2..df16e4a 100644
--- a/base/values_unittest.cc
+++ b/base/values_unittest.cc
@@ -8,6 +8,7 @@
 
 #include <algorithm>
 #include <functional>
+#include <iterator>
 #include <limits>
 #include <memory>
 #include <string>
@@ -214,25 +215,6 @@
   }
 }
 
-TEST(ValuesTest, ConstructDictFromDeprecatedDictStorage) {
-  Value::DeprecatedDictStorage storage;
-  storage.emplace("foo", "bar");
-  {
-    Value value(storage);
-    EXPECT_EQ(Value::Type::DICTIONARY, value.type());
-    EXPECT_EQ(Value::Type::STRING, value.FindKey("foo")->type());
-    EXPECT_EQ("bar", value.FindKey("foo")->GetString());
-  }
-
-  storage["foo"] = base::Value("baz");
-  {
-    Value value(std::move(storage));
-    EXPECT_EQ(Value::Type::DICTIONARY, value.type());
-    EXPECT_EQ(Value::Type::STRING, value.FindKey("foo")->type());
-    EXPECT_EQ("baz", value.FindKey("foo")->GetString());
-  }
-}
-
 TEST(ValuesTest, ConstructList) {
   ListValue value;
   EXPECT_EQ(Value::Type::LIST, value.type());
@@ -470,55 +452,17 @@
   EXPECT_EQ(123, blank.FindKey("Int")->GetInt());
 }
 
-TEST(ValuesTest, MoveConstructDeprecatedDictStorage) {
-  Value::DeprecatedDictStorage storage;
-  storage.emplace("Int", 123);
-
-  Value value(std::move(storage));
-  Value moved_value(std::move(value));
-  EXPECT_EQ(Value::Type::DICTIONARY, moved_value.type());
-  EXPECT_EQ(123, moved_value.FindKey("Int")->GetInt());
-}
-
-TEST(ValuesTest, MoveAssignDeprecatedDictStorage) {
-  Value::DeprecatedDictStorage storage;
-  storage.emplace("Int", 123);
+TEST(ValuesTest, ConstructDictWithIterators) {
+  std::vector<std::pair<std::string, Value>> values;
+  values.emplace_back(std::make_pair("Int", 123));
 
   Value blank;
-  blank = Value(std::move(storage));
+  blank = Value(Value::Dict(std::make_move_iterator(values.begin()),
+                            std::make_move_iterator(values.end())));
   EXPECT_EQ(Value::Type::DICTIONARY, blank.type());
   EXPECT_EQ(123, blank.FindKey("Int")->GetInt());
 }
 
-TEST(ValuesTest, TakeDictDeprecated) {
-  // Prepare a dict with a value of each type.
-  Value::DeprecatedDictStorage storage;
-  storage.emplace("null", Value::Type::NONE);
-  storage.emplace("bool", Value::Type::BOOLEAN);
-  storage.emplace("int", Value::Type::INTEGER);
-  storage.emplace("double", Value::Type::DOUBLE);
-  storage.emplace("string", Value::Type::STRING);
-  storage.emplace("blob", Value::Type::BINARY);
-  storage.emplace("list", Value::Type::LIST);
-  storage.emplace("dict", Value::Type::DICTIONARY);
-  Value value(std::move(storage));
-
-  // Take ownership of the dict and make sure its contents are what we expect.
-  auto dict = std::move(value).TakeDictDeprecated();
-  EXPECT_EQ(8u, dict.size());
-  EXPECT_TRUE(dict["null"].is_none());
-  EXPECT_TRUE(dict["bool"].is_bool());
-  EXPECT_TRUE(dict["int"].is_int());
-  EXPECT_TRUE(dict["double"].is_double());
-  EXPECT_TRUE(dict["string"].is_string());
-  EXPECT_TRUE(dict["blob"].is_blob());
-  EXPECT_TRUE(dict["list"].is_list());
-  EXPECT_TRUE(dict["dict"].is_dict());
-
-  // Validate that |value| no longer contains values.
-  EXPECT_TRUE(value.DictEmpty());
-}
-
 TEST(ValuesTest, MoveList) {
   Value::ListStorage storage;
   storage.emplace_back(123);
diff --git a/build/config/compiler/pgo/pgo.gni b/build/config/compiler/pgo/pgo.gni
index c053eb5..a5bb86b 100644
--- a/build/config/compiler/pgo/pgo.gni
+++ b/build/config/compiler/pgo/pgo.gni
@@ -4,6 +4,7 @@
 
 import("//build/config/chromecast_build.gni")
 import("//build/config/chromeos/ui_mode.gni")
+import("//build/config/dcheck_always_on.gni")
 
 declare_args() {
   # Specify the current PGO phase.
@@ -11,8 +12,12 @@
   #     0 : Means that PGO is turned off.
   #     1 : Used during the PGI (instrumentation) phase.
   #     2 : Used during the PGO (optimization) phase.
+  # PGO profiles are generated from `dcheck_always_on = false` builds. Mixing
+  # those profiles with `dcheck_always_on = true` builds can cause the compiler
+  # to think some code is hotter than it actually is, potentially causing very
+  # bad compile times.
   chrome_pgo_phase = 0
-  if (is_official_build &&
+  if (!dcheck_always_on && is_official_build &&
       # TODO(crbug.com/1052397): Remove chromeos_is_browser_only once
       # target_os switch for lacros-chrome is completed.
       (is_win || is_mac ||
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 6a51620..6f8ab04 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1311,9 +1311,11 @@
   testonly = true
   resources_package = "org.chromium.chrome.test"
   sources = [
+    "javatests/src/org/chromium/chrome/browser/IntentFilterUnitTest.java",
     "javatests/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkShoppingItemRowTest.java",
     "javatests/src/org/chromium/chrome/browser/bookmarks/PowerBookmarkUtilsTest.java",
     "javatests/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java",
+    "javatests/src/org/chromium/chrome/browser/crypto/CipherFactoryTest.java",
     "javatests/src/org/chromium/chrome/browser/download/DownloadForegroundServiceManagerTest.java",
     "javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java",
     "javatests/src/org/chromium/chrome/browser/init/FirstDrawDetectorTest.java",
@@ -1330,6 +1332,7 @@
     "//base:base_java_test_support",
     "//chrome/android:chrome_java",
     "//chrome/android/features/autofill_assistant:unit_test_java",
+    "//chrome/browser/android/crypto:java",
     "//chrome/browser/contextmenu:java",
     "//chrome/browser/first_run/android:java",
     "//chrome/browser/flags:java",
@@ -1628,7 +1631,6 @@
     "//components/page_info/android:page_info_action_enum_java",
     "//components/page_info/core:proto_java",
     "//components/paint_preview/player/android:java",
-    "//components/paint_preview/player/android:javatests",
     "//components/password_manager/core/browser:password_manager_java_enums",
     "//components/payments/content/android:java",
     "//components/payments/content/android:javatests",
@@ -3156,6 +3158,7 @@
     "//chrome/browser/ui/messages/android:unit_device_javatests",
     "//chrome/browser/user_education:javatests",
     "//chrome/browser/video_tutorials/internal:javatests",
+    "//components/paint_preview/player/android:javatests",
     "//components/signin/public/android:javatests",
   ]
 
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index c260675..13e26c88 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -21,7 +21,6 @@
   "javatests/src/org/chromium/chrome/browser/HTTPSTabsOpenedFromExternalAppTest.java",
   "javatests/src/org/chromium/chrome/browser/ImageFetcherIntegrationTest.java",
   "javatests/src/org/chromium/chrome/browser/InstalledAppTest.java",
-  "javatests/src/org/chromium/chrome/browser/IntentFilterUnitTest.java",
   "javatests/src/org/chromium/chrome/browser/IntentHandlerBrowserTest.java",
   "javatests/src/org/chromium/chrome/browser/IntentHandlerUnitTest.java",
   "javatests/src/org/chromium/chrome/browser/JavaScriptEvalChromeTest.java",
@@ -137,7 +136,6 @@
   "javatests/src/org/chromium/chrome/browser/continuous_search/ContinuousSearchFullUiTest.java",
   "javatests/src/org/chromium/chrome/browser/crash/LogcatExtractionRunnableTest.java",
   "javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java",
-  "javatests/src/org/chromium/chrome/browser/crypto/CipherFactoryTest.java",
   "javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityAppMenuTest.java",
   "javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoMetricTest.java",
   "javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java",
@@ -336,7 +334,6 @@
   "javatests/src/org/chromium/chrome/browser/omnibox/suggestions/SwitchToTabTest.java",
   "javatests/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerSuggestionProcessorUnitTest.java",
   "javatests/src/org/chromium/chrome/browser/omnibox/suggestions/base/BaseSuggestionProcessorTest.java",
-  "javatests/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessorUnitTest.java",
   "javatests/src/org/chromium/chrome/browser/omnibox/suggestions/clipboard/ClipboardSuggestionProcessorTest.java",
   "javatests/src/org/chromium/chrome/browser/omnibox/suggestions/editurl/EditUrlSuggestionUnitTest.java",
   "javatests/src/org/chromium/chrome/browser/omnibox/suggestions/entity/EntitySuggestionProcessorUnitTest.java",
diff --git a/chrome/android/features/start_surface/javatests/start_surface_test_java_sources.gni b/chrome/android/features/start_surface/javatests/start_surface_test_java_sources.gni
index 2157dfc..5979c32c 100644
--- a/chrome/android/features/start_surface/javatests/start_surface_test_java_sources.gni
+++ b/chrome/android/features/start_surface/javatests/start_surface_test_java_sources.gni
@@ -9,7 +9,6 @@
   "//chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTabSwitcherTest.java",
   "//chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java",
   "//chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/InstantStartToolbarTest.java",
-  "//chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/SecondaryTasksSurfaceViewBinderTest.java",
   "//chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceBackButtonTest.java",
   "//chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceMVTilesTest.java",
   "//chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java",
@@ -18,7 +17,6 @@
   "//chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTestUtils.java",
   "//chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayoutPerfTest.java",
   "//chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TabSwitcherAndStartSurfaceLayoutTest.java",
-  "//chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TasksSurfaceViewBinderTest.java",
   "//chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/tasks/SingleTabViewBinderTest.java",
   "//chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/tasks/TasksViewBinderTest.java",
 ]
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/SecondaryTasksSurfaceViewBinderTest.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/SecondaryTasksSurfaceViewBinderUnitTest.java
similarity index 74%
rename from chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/SecondaryTasksSurfaceViewBinderTest.java
rename to chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/SecondaryTasksSurfaceViewBinderUnitTest.java
index 9e53515..229313a 100644
--- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/SecondaryTasksSurfaceViewBinderTest.java
+++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/SecondaryTasksSurfaceViewBinderUnitTest.java
@@ -12,6 +12,7 @@
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_SECONDARY_SURFACE_VISIBLE;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.TOP_MARGIN;
 
+import android.app.Activity;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.view.View;
@@ -21,42 +22,43 @@
 
 import androidx.test.filters.SmallTest;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.annotation.Config;
 
+import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.UiThreadTest;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
-import org.chromium.ui.test.util.BlankUiTestActivityTestCase;
 
 /** Tests for {@link SecondaryTasksSurfaceViewBinder}. */
-@RunWith(ChromeJUnit4ClassRunner.class)
-public class SecondaryTasksSurfaceViewBinderTest extends BlankUiTestActivityTestCase {
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class SecondaryTasksSurfaceViewBinderUnitTest {
+    private Activity mActivity;
     private ViewGroup mParentView;
     private View mTasksSurfaceView;
     private PropertyModel mPropertyModel;
     @SuppressWarnings({"FieldCanBeLocal", "unused"})
     private PropertyModelChangeProcessor mPropertyModelChangeProcessor;
 
-    @Override
-    public void setUpTest() throws Exception {
-        super.setUpTest();
+    @Before
+    public void setUp() throws Exception {
+        mActivity = Robolectric.buildActivity(Activity.class).setup().get();
 
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            // Note that the specific type of the parent view and tasks surface view do not matter
-            // for the SecondaryTasksSurfaceViewBinderTest.
-            mParentView = new FrameLayout(getActivity());
-            mTasksSurfaceView = new View(getActivity());
-            mTasksSurfaceView.setBackground(new ColorDrawable(Color.WHITE));
-            getActivity().setContentView(mParentView);
+        // Note that the specific type of the parent view and tasks surface view do not matter for
+        // the SecondaryTasksSurfaceViewBinderTest.
+        mParentView = new FrameLayout(mActivity);
+        mTasksSurfaceView = new View(mActivity);
+        mTasksSurfaceView.setBackground(new ColorDrawable(Color.WHITE));
+        mActivity.setContentView(mParentView);
 
-            mPropertyModel = new PropertyModel(StartSurfaceProperties.ALL_KEYS);
-            mPropertyModelChangeProcessor = PropertyModelChangeProcessor.create(mPropertyModel,
-                    new TasksSurfaceViewBinder.ViewHolder(mParentView, mTasksSurfaceView),
-                    SecondaryTasksSurfaceViewBinder::bind);
-        });
+        mPropertyModel = new PropertyModel(StartSurfaceProperties.ALL_KEYS);
+        mPropertyModelChangeProcessor = PropertyModelChangeProcessor.create(mPropertyModel,
+                new TasksSurfaceViewBinder.ViewHolder(mParentView, mTasksSurfaceView),
+                SecondaryTasksSurfaceViewBinder::bind);
     }
 
     @Test
diff --git a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TasksSurfaceViewBinderTest.java b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/TasksSurfaceViewBinderUnitTest.java
similarity index 74%
rename from chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TasksSurfaceViewBinderTest.java
rename to chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/TasksSurfaceViewBinderUnitTest.java
index d017592..4d3b56e9d 100644
--- a/chrome/android/features/start_surface/javatests/src/org/chromium/chrome/features/start_surface/TasksSurfaceViewBinderTest.java
+++ b/chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/TasksSurfaceViewBinderUnitTest.java
@@ -13,6 +13,7 @@
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.IS_SHOWING_OVERVIEW;
 import static org.chromium.chrome.features.start_surface.StartSurfaceProperties.TOP_MARGIN;
 
+import android.app.Activity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.MarginLayoutParams;
@@ -20,41 +21,42 @@
 
 import androidx.test.filters.SmallTest;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.annotation.Config;
 
+import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.UiThreadTest;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
-import org.chromium.ui.test.util.BlankUiTestActivityTestCase;
 
 /** Tests for {@link TasksSurfaceViewBinder}. */
-@RunWith(ChromeJUnit4ClassRunner.class)
-public class TasksSurfaceViewBinderTest extends BlankUiTestActivityTestCase {
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class TasksSurfaceViewBinderUnitTest {
+    private Activity mActivity;
     private ViewGroup mParentView;
     private ViewGroup mTasksSurfaceView;
     private PropertyModel mPropertyModel;
     @SuppressWarnings({"FieldCanBeLocal", "unused"})
     private PropertyModelChangeProcessor mPropertyModelChangeProcessor;
 
-    @Override
-    public void setUpTest() throws Exception {
-        super.setUpTest();
+    @Before
+    public void setUp() {
+        mActivity = Robolectric.buildActivity(Activity.class).setup().get();
 
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            // Note that the specific type of the parent view and tasks surface view do not matter
-            // for the TasksSurfaceViewBinder.
-            mParentView = new FrameLayout(getActivity());
-            mTasksSurfaceView = new FrameLayout(getActivity());
-            getActivity().setContentView(mParentView);
+        // Note that the specific type of the parent view and tasks surface view do not matter for
+        // the TasksSurfaceViewBinder.
+        mParentView = new FrameLayout(mActivity);
+        mTasksSurfaceView = new FrameLayout(mActivity);
+        mActivity.setContentView(mParentView);
 
-            mPropertyModel = new PropertyModel(StartSurfaceProperties.ALL_KEYS);
-            mPropertyModelChangeProcessor = PropertyModelChangeProcessor.create(mPropertyModel,
-                    new TasksSurfaceViewBinder.ViewHolder(mParentView, mTasksSurfaceView),
-                    TasksSurfaceViewBinder::bind);
-        });
+        mPropertyModel = new PropertyModel(StartSurfaceProperties.ALL_KEYS);
+        mPropertyModelChangeProcessor = PropertyModelChangeProcessor.create(mPropertyModel,
+                new TasksSurfaceViewBinder.ViewHolder(mParentView, mTasksSurfaceView),
+                TasksSurfaceViewBinder::bind);
     }
 
     @Test
diff --git a/chrome/android/features/start_surface/junit/start_surface_junit_java_sources.gni b/chrome/android/features/start_surface/junit/start_surface_junit_java_sources.gni
index 622e98c..90ea96f 100644
--- a/chrome/android/features/start_surface/junit/start_surface_junit_java_sources.gni
+++ b/chrome/android/features/start_surface/junit/start_surface_junit_java_sources.gni
@@ -3,7 +3,9 @@
 # found in the LICENSE file.
 
 start_surface_junit_java_sources = [
+  "//chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/SecondaryTasksSurfaceViewBinderUnitTest.java",
   "//chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java",
+  "//chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/start_surface/TasksSurfaceViewBinderUnitTest.java",
   "//chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/tasks/SingleTabSwitcherMediatorUnitTest.java",
   "//chrome/android/features/start_surface/junit/src/org/chromium/chrome/features/tasks/TasksSurfaceMediatorUnitTest.java",
 ]
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index dfecfa80..ca7ad4b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -642,6 +642,7 @@
                 public void didAddTab(
                         Tab tab, @TabLaunchType int type, @TabCreationState int creationState) {
                     if (type == TabLaunchType.FROM_LONGPRESS_BACKGROUND
+                            || type == TabLaunchType.FROM_LONGPRESS_BACKGROUND_IN_GROUP
                             || type == TabLaunchType.FROM_RECENT_TABS
                                     && !DeviceClassManager.enableAnimations()) {
                         Toast.makeText(ChromeTabbedActivity.this, R.string.open_in_new_tab_toast,
@@ -2335,6 +2336,7 @@
                 || type == TabLaunchType.FROM_LONGPRESS_FOREGROUND
                 || type == TabLaunchType.FROM_LONGPRESS_INCOGNITO
                 || type == TabLaunchType.FROM_LONGPRESS_BACKGROUND
+                || type == TabLaunchType.FROM_LONGPRESS_BACKGROUND_IN_GROUP
                 || type == TabLaunchType.FROM_RECENT_TABS
                 || (type == TabLaunchType.FROM_RESTORE
                         && CriticalPersistedTabData.from(tab).getParentId() != Tab.INVALID_TAB_ID);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index 5340fb22..5bee253 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -1988,11 +1988,6 @@
         return mIsBottomSheetVisible || mIsAccessibilityModeEnabled;
     }
 
-    @VisibleForTesting
-    public void setVisibilityStateForTesting(boolean isVisible) {
-        getOverlayContentDelegate().onVisibilityChanged(isVisible);
-    }
-
     @NativeMethods
     interface Natives {
         long init(ContextualSearchManager caller);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
index 02a5997c..e3cdc957 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
@@ -452,6 +452,11 @@
             // CustomTabActivityNavigationController#FinishHandler. Pass the mode enum into
             // CustomTabActivityModule, so that it can provide the correct implementation.
             getComponent().resolveTwaFinishHandler().onFinish(defaultBehavior);
+        } else if (intentDataProvider.isPartialHeightCustomTab()
+                && intentDataProvider.shouldAnimateOnFinish()) {
+            // WebContents is missing during the close animation due to android:windowIsTranslucent.
+            // We let partial CCT handle the animation.
+            mBaseCustomTabRootUiCoordinator.handleCloseAnimation(defaultBehavior);
         } else {
             defaultBehavior.run();
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java
index 2a7879c..5f3c0e6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabRootUiCoordinator.java
@@ -55,7 +55,6 @@
  * A {@link RootUiCoordinator} variant that controls UI for {@link BaseCustomTabActivity}.
  */
 public class BaseCustomTabRootUiCoordinator extends RootUiCoordinator {
-    private final ObservableSupplier<CompositorViewHolder> mCompositorViewHolderSupplier;
     private final Supplier<CustomTabToolbarCoordinator> mToolbarCoordinator;
     private final Supplier<CustomTabActivityNavigationController> mNavigationController;
     private final Supplier<BrowserServicesIntentDataProvider> mIntentDataProvider;
@@ -149,7 +148,6 @@
                 ephemeralTabCoordinatorSupplier, false, null,
                 /* unblockDrawForOverviewPageRunnable= */ null);
         // clang-format on
-        mCompositorViewHolderSupplier = compositorViewHolderSupplier;
         mToolbarCoordinator = customTabToolbarCoordinator;
         mNavigationController = customTabNavigationController;
         mIntentDataProvider = intentDataProvider;
@@ -205,14 +203,19 @@
                 != null : "IntentDataProvider needs to be non-null after preInflationStartup";
 
         mCustomTabHeightStrategy = CustomTabHeightStrategy.createStrategy(mActivity,
-                mCompositorViewHolderSupplier, intentDataProvider.getInitialActivityHeight(),
-                mMultiWindowModeStateDispatcher,
+                intentDataProvider.getInitialActivityHeight(), mMultiWindowModeStateDispatcher,
                 intentDataProvider.getColorProvider().getNavigationBarColor(),
                 intentDataProvider.getColorProvider().getNavigationBarDividerColor(),
                 CustomTabsConnection.getInstance(), intentDataProvider.getSession(),
                 mActivityLifecycleDispatcher);
     }
 
+    @Override
+    public void onPostInflationStartup() {
+        super.onPostInflationStartup();
+        mCustomTabHeightStrategy.onPostInflationStartup();
+    }
+
     /**
      * Delegates changing the background color to the {@link CustomTabHeightStrategy}.
      * Returns {@code true} if any action were taken, {@code false} if not.
@@ -222,4 +225,12 @@
 
         return mCustomTabHeightStrategy.changeBackgroundColorForResizing();
     }
+
+    /**
+     * Perform slide-down animation on closing.
+     * @param finishRunnable Runnable finishing the activity after the animation.
+     */
+    void handleCloseAnimation(Runnable finishRunnable) {
+        mCustomTabHeightStrategy.handleCloseAnimation(finishRunnable);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabHeightStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabHeightStrategy.java
index f3d06f6..f819ab5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabHeightStrategy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabHeightStrategy.java
@@ -6,13 +6,11 @@
 
 import android.app.Activity;
 import android.view.View;
-import android.widget.FrameLayout;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.Px;
 import androidx.browser.customtabs.CustomTabsSessionToken;
 
-import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher;
@@ -21,8 +19,7 @@
  * The default strategy for setting the height of the custom tab.
  */
 public class CustomTabHeightStrategy {
-    public static CustomTabHeightStrategy createStrategy(Activity activity,
-            ObservableSupplier<? extends FrameLayout> parentViewSupplier, @Px int initialHeight,
+    public static CustomTabHeightStrategy createStrategy(Activity activity, @Px int initialHeight,
             MultiWindowModeStateDispatcher multiWindowModeStateDispatcher,
             Integer navigationBarColor, Integer navigationBarDividerColor,
             CustomTabsConnection connection, @Nullable CustomTabsSessionToken session,
@@ -31,12 +28,17 @@
             return new CustomTabHeightStrategy();
         }
 
-        return new PartialCustomTabHeightStrategy(activity, parentViewSupplier, initialHeight,
+        return new PartialCustomTabHeightStrategy(activity, initialHeight,
                 multiWindowModeStateDispatcher, navigationBarColor, navigationBarDividerColor,
                 size -> connection.onResized(session, size), lifecycleDispatcher);
     }
 
     /**
+     * @see {@link org.chromium.chrome.browser.lifecycle.InflationObserver#onPostInflationStartup()}
+     */
+    public void onPostInflationStartup() {}
+
+    /**
      * Returns false if we didn't change the Window background color, true otherwise.
      */
     public boolean changeBackgroundColorForResizing() {
@@ -53,4 +55,12 @@
      */
     public void onToolbarInitialized(
             View coordinatorView, CustomTabToolbar toolbar, @Px int toolbarCornerRadius) {}
+
+    /**
+     * @see {@link BaseCustomTabRootUiCoordinator#handleCloseAnimation()}
+     */
+    public void handleCloseAnimation(Runnable finishRunnable) {
+        throw new IllegalStateException(
+                "Custom close animation should be performed only on partial CCT.");
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
index c6f7979..229cbc3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -637,8 +637,9 @@
 
     @Override
     public int getAnimationExitRes() {
-        return shouldAnimateOnFinish() ? mAnimationBundle.getInt(BUNDLE_EXIT_ANIMATION_RESOURCE)
-                                       : 0;
+        return shouldAnimateOnFinish() && !isPartialHeightCustomTab()
+                ? mAnimationBundle.getInt(BUNDLE_EXIT_ANIMATION_RESOURCE)
+                : 0;
     }
 
     @Deprecated
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java
index d274372..0ee12c7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java
@@ -14,25 +14,24 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Color;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.GradientDrawable;
 import android.os.Build;
 import android.util.DisplayMetrics;
-import android.view.Display;
 import android.view.GestureDetector;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewStub;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.view.WindowInsets;
 import android.view.WindowManager;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
 import androidx.annotation.IntDef;
+import androidx.annotation.Nullable;
 import androidx.annotation.Px;
 import androidx.annotation.VisibleForTesting;
 import androidx.core.view.MotionEventCompat;
@@ -44,7 +43,6 @@
 import org.chromium.base.MathUtils;
 import org.chromium.base.SysUtils;
 import org.chromium.base.ThreadUtils;
-import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.customtabs.features.CustomTabNavigationBarController;
 import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar;
@@ -88,7 +86,6 @@
     }
 
     private final Activity mActivity;
-    private final @Px int mInitialHeight;
     private final @Px int mMaxHeight;
 
     private final @Px int mFullyExpandedAdjustmentHeight;
@@ -97,6 +94,7 @@
     private final OnResizedCallback mOnResizedCallback;
     private final AnimatorListener mSpinnerFadeoutAnimatorListener;
     private final int mHandleHeight;
+    private @Px int mInitialHeight;
     private ValueAnimator mAnimator;
     private int mShadowOffset;
     private boolean mDrawOutlineShadow;
@@ -124,6 +122,11 @@
     private CircularProgressDrawable mSpinner;
     private View mToolbarView;
     private View mToolbarCoordinator;
+    private Runnable mPositionUpdater;
+
+    // Runnable finishing the activity after the exit animation. Non-null when PCCT is closing.
+    @Nullable
+    private Runnable mFinishRunnable;
 
     /** A callback to be called once the Custom Tab has been resized. */
     interface OnResizedCallback {
@@ -259,8 +262,7 @@
         }
     }
 
-    public PartialCustomTabHeightStrategy(Activity activity,
-            ObservableSupplier<? extends FrameLayout> parentViewSupplier, @Px int initialHeight,
+    public PartialCustomTabHeightStrategy(Activity activity, @Px int initialHeight,
             MultiWindowModeStateDispatcher multiWindowModeStateDispatcher,
             Integer navigationBarColor, Integer navigationBarDividerColor,
             OnResizedCallback onResizedCallback, ActivityLifecycleDispatcher lifecycleDispatcher) {
@@ -268,31 +270,6 @@
         mMaxHeight = getMaximumPossibleHeight();
         mInitialHeight = MathUtils.clamp(
                 initialHeight, mMaxHeight, (int) (mMaxHeight * MINIMAL_HEIGHT_RATIO));
-
-        // Invoked twice - when populated/destroyed(null)
-        // TODO(jinsukkim): Obtain the CoordinatorLayout and ContentFrame directly,
-        //                  not through CompositorViewHolder which is not in use.
-        parentViewSupplier.addObserver(parentView -> {
-            if (parentView == null) {
-                mCoordinatorLayout = null;
-                mContentFrame = null;
-                return;
-            }
-
-            mCoordinatorLayout = (ViewGroup) parentView.getParent();
-            mContentFrame = (ViewGroup) mCoordinatorLayout.getParent();
-
-            // Elevate the main web contents area as high as the handle bar to have the shadow
-            // effect look right.
-            int ev = mActivity.getResources().getDimensionPixelSize(R.dimen.custom_tabs_elevation);
-            mCoordinatorLayout.setElevation(ev);
-
-            // When the navigation bar on the right side (not at the bottom), no need to set
-            // contents height since it is fixed to the max height.
-            if (mNavbarHeight != 0) setContentsHeight();
-            updateNavbarVisibility(true);
-        });
-
         mOnResizedCallback = onResizedCallback;
         // When the flag is enabled, we make the max snap point 10% shorter, so it will only occupy
         // 90% of the height.
@@ -337,7 +314,49 @@
             @Override
             public void onAnimationCancel(Animator animator) {}
         };
+
+        // On pre-R devices, We wait till the layout is complete and get the content
+        // |android.R.id.content| view height. See |getAppUsableScreenHeight|.
+        mPositionUpdater =
+                Build.VERSION.SDK_INT >= Build.VERSION_CODES.R ? this::updatePosition : () -> {
+            // Maybe invoked before layout inflation? Simply return here - postion update will be
+            // executed by |onPostInflationStartUp| anyway.
+            if (mContentFrame == null) return;
+
+            mContentFrame.getViewTreeObserver().addOnGlobalLayoutListener(
+                    new OnGlobalLayoutListener() {
+                        @Override
+                        public void onGlobalLayout() {
+                            mContentFrame.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+                            updatePosition();
+                        }
+                    });
+        };
+    }
+
+    @Override
+    public void onPostInflationStartup() {
+        mContentFrame = (ViewGroup) mActivity.findViewById(android.R.id.content);
+        mCoordinatorLayout = (ViewGroup) mActivity.findViewById(R.id.coordinator);
+
+        // Elevate the main web contents area as high as the handle bar to have the shadow
+        // effect look right.
+        int ev = mActivity.getResources().getDimensionPixelSize(R.dimen.custom_tabs_elevation);
+        mCoordinatorLayout.setElevation(ev);
+
+        mPositionUpdater.run();
+    }
+
+    private void updatePosition() {
+        if (mContentFrame == null) return;
+
         initializeHeight();
+        updateShadowOffset();
+
+        // When the navigation bar on the right side (not at the bottom), no need to
+        // set contents height since it is fixed to the max height.
+        if (mNavbarHeight != 0) setContentsHeight();
+        updateNavbarVisibility(true);
     }
 
     private @Px int getNavbarHeight() {
@@ -348,14 +367,19 @@
                     .getInsets(WindowInsets.Type.navigationBars())
                     .bottom;
         }
+        // On pre-R devices, there is no official way to get the navigation bar height. A common way
+        // was to get it from a resource definition('navigation_bar_height') but it fails on some
+        // vendor-customized devices. A workaround here is to subtract the app-usable height
+        // (client view height + status bar height) from the whole display height.
         return getDisplayHeight() - getAppUsableScreenHeight();
     }
 
     private int getAppUsableScreenHeight() {
-        Display display = mActivity.getWindowManager().getDefaultDisplay();
-        Point size = new Point();
-        display.getSize(size);
-        return size.y;
+        // A correct way to get the client area height would be to use |decor_content_parent|,
+        // the parent of |content|, to make sure to include the top action bar dimension. But
+        // CCT (or Chrome for that matter) doesn't have the top action bar. So getting the height
+        // of |content| is enough.
+        return mContentFrame.getHeight() + getStatusBarHeight();
     }
 
     @Override
@@ -378,10 +402,12 @@
     public void onConfigurationChanged(Configuration newConfig) {
         if (newConfig.orientation != mOrientation) {
             mOrientation = newConfig.orientation;
-            initializeHeight();
-            updateShadowOffset();
-            setContentsHeight();
-            updateNavbarVisibility(true);
+            if (mOrientation == Configuration.ORIENTATION_LANDSCAPE) {
+                // We should update CCT position before Window#FLAG_LAYOUT_NO_LIMITS is set,
+                // otherwise it is not possible to get the correct content height.
+                mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
+            }
+            mPositionUpdater.run();
         }
     }
 
@@ -454,9 +480,9 @@
         // TODO(jinsukkim): Handle multi-window mode.
         if (attributes.height == height) return;
 
-        // We do not resize Window but just translate its vertical offset, and resize the parent
-        // view of WebContents (CompositorViewHolder) instead. This helps us work around the round-
-        // corner bug in Android S. See b/223536648.
+        // We do not resize Window but just translate its vertical offset, and resize Coordinator-
+        // LayoutForPointer instead. This helps us work around the round-corner bug in Android S.
+        // See b/223536648.
         attributes.y = Math.max(maxExpandedY, maxHeight - height - mNavbarHeight);
         mActivity.getWindow().setAttributes(attributes);
     }
@@ -488,8 +514,11 @@
                 mMaxHeight - mInitialHeight - mNavbarHeight);
         WindowManager.LayoutParams attributes = mActivity.getWindow().getAttributes();
         if (attributes.y == y) return;
+
         attributes.y = y;
         mActivity.getWindow().setAttributes(attributes);
+        if (mFinishRunnable != null) return;
+
         assert mSpinnerView != null;
         centerSpinnerVertically((ViewGroup.LayoutParams) mSpinnerView.getLayoutParams());
     }
@@ -500,6 +529,10 @@
     }
 
     private void onMoveEnd() {
+        if (mFinishRunnable != null) {
+            mFinishRunnable.run();
+            return;
+        }
         setContentsHeight();
 
         // TODO(crbug.com/1328555): Look into observing a view resize event to ensure the fade
@@ -523,7 +556,6 @@
             // Toolbar should not be hidden by spinner screen.
             ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(MATCH_PARENT, 0);
             lp.setMargins(0, mToolbarView.getHeight() + mHandleHeight + mShadowOffset, 0, 0);
-
             mSpinner = new CircularProgressDrawable(mActivity);
             mSpinner.setStyle(CircularProgressDrawable.LARGE);
             mSpinnerView.setImageDrawable(mSpinner);
@@ -571,9 +603,7 @@
     // Show or hide our own navigation bar.
     private void updateNavbarVisibility(boolean show) {
         if (show) {
-            // No need draw its own navigation bar when it is located on the right side since
-            // the system navigation bar is visible and can handle API #setNavigationBarColor.
-            if (mNavbarHeight == 0) {
+            if (shouldShowSystemNavbar()) {
                 setNavigationBarAndDividerColor();
                 if (mNavbar != null) mNavbar.setVisibility(View.GONE);
                 return;
@@ -599,6 +629,14 @@
         showNavbarButtons(show);
     }
 
+    /**
+     * Return whether we need to show not its own custom navigation bar but the system-provided
+     * one that can handle the API |setNavigationBarColor()|.
+     */
+    private boolean shouldShowSystemNavbar() {
+        return mNavbarHeight == 0 || mOrientation == Configuration.ORIENTATION_LANDSCAPE;
+    }
+
     // Position our own navbar where the system navigation bar which is obscured by WebContents
     // rendered over it due to Window#FLAGS_LAYOUT_NO_LIMITS would be shown.
     private void setNavbarOffset() {
@@ -616,7 +654,7 @@
         // the bad contrast against buttons when they are both white.
         boolean needsDarkButtons = !ColorUtils.shouldUseLightForegroundOnBackground(color);
         if (needsDarkButtons) color = ColorUtils.getDarkenedColorForStatusBar(color);
-        if (mNavbarHeight == 0) {
+        if (shouldShowSystemNavbar()) {
             mActivity.getWindow().setNavigationBarColor(color);
         } else {
             // Use our own navbar where the system navigation bar which is obscured by WebContents
@@ -629,7 +667,7 @@
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) return;
         Integer dividerColor = CustomTabNavigationBarController.getDividerColor(
                 mActivity, mNavigationBarColor, mNavigationBarDividerColor, needsDarkButtons);
-        if (mNavbarHeight == 0) {
+        if (shouldShowSystemNavbar()) {
             if (dividerColor != null) {
                 mActivity.getWindow().setNavigationBarDividerColor(dividerColor);
             }
@@ -692,7 +730,7 @@
         return displayMetrics.heightPixels;
     }
 
-    private @Px int getFullyExpandedYCoordinate() {
+    private @Px int getStatusBarHeight() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
             return mActivity.getWindowManager()
                     .getCurrentWindowMetrics()
@@ -710,6 +748,10 @@
         return statusBarHeight;
     }
 
+    private @Px int getFullyExpandedYCoordinate() {
+        return getStatusBarHeight();
+    }
+
     private @Px int getFullyExpandedYCoordinateWithAdjustment() {
         // Adding |mFullyExpandedAdjustmentHeight| to the y coordinate because the
         // coordinates system's origin is at the top left and y is growing in downward, larger y
@@ -723,16 +765,36 @@
         return true;
     }
 
+    @Override
+    public void handleCloseAnimation(Runnable finishRunnable) {
+        if (mFinishRunnable != null) return;
+
+        mFinishRunnable = finishRunnable;
+
+        int start = mActivity.getWindow().getAttributes().y;
+        int end = getDisplayHeight() - mNavbarHeight;
+        mInitialHeight = 0;
+
+        if (mOrientation == Configuration.ORIENTATION_LANDSCAPE) {
+            mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
+        }
+        mAnimator.setDuration(
+                mActivity.getResources().getInteger(android.R.integer.config_mediumAnimTime));
+        mAnimator.setIntValues(start, end);
+        mAnimator.start();
+    }
+
     @VisibleForTesting
     void setMockViewForTesting(LinearLayout navbar, ImageView spinnerView,
-            CircularProgressDrawable spinner, View toolbar, View toolbarCoordinator,
-            ViewGroup coordinatorLayout) {
+            CircularProgressDrawable spinner, View toolbar, View toolbarCoordinator) {
         mNavbar = navbar;
         mSpinnerView = spinnerView;
         mSpinner = spinner;
         mToolbarView = toolbar;
         mToolbarCoordinator = toolbarCoordinator;
-        mCoordinatorLayout = coordinatorLayout;
+
+        mPositionUpdater = this::updatePosition;
+        onPostInflationStartup();
     }
 
     @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/StatusIndicatorCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/StatusIndicatorCoordinator.java
index eaf5a13..2c73dfd0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/StatusIndicatorCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/StatusIndicatorCoordinator.java
@@ -11,6 +11,7 @@
 
 import androidx.annotation.ColorInt;
 import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.Callback;
 import org.chromium.base.supplier.Supplier;
@@ -205,4 +206,9 @@
         mResourceManager.getDynamicResourceLoader().unregisterResource(mResourceId);
         mResourceRegistered = false;
     }
+
+    @VisibleForTesting
+    StatusIndicatorMediator getMediatorForTesting() {
+        return mMediator;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/StatusIndicatorMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/StatusIndicatorMediator.java
index 944f0a4..0c2e6a57 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/StatusIndicatorMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/StatusIndicatorMediator.java
@@ -442,4 +442,20 @@
     void updateVisibilityForTesting(boolean hiding) {
         updateVisibility(hiding);
     }
-}
+
+    @VisibleForTesting
+    void finishAnimationsForTesting() {
+        if (mStatusBarAnimation != null && mStatusBarAnimation.isRunning()) {
+            mStatusBarAnimation.end();
+        }
+        if (mTextFadeInAnimation != null && mTextFadeInAnimation.isRunning()) {
+            mTextFadeInAnimation.end();
+        }
+        if (mUpdateAnimatorSet != null && mUpdateAnimatorSet.isRunning()) {
+            mUpdateAnimatorSet.end();
+        }
+        if (mHideAnimatorSet != null && mHideAnimatorSet.isRunning()) {
+            mHideAnimatorSet.end();
+        }
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
index 919652f..caa3d27 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -134,6 +134,7 @@
  * A {@link RootUiCoordinator} variant that controls tabbed-mode specific UI.
  */
 public class TabbedRootUiCoordinator extends RootUiCoordinator {
+    private static boolean sDisableStatusIndicatorAnimations;
     private final RootUiTabObserver mRootUiTabObserver;
     private TabbedSystemUiCoordinator mSystemUiCoordinator;
     private @Nullable EmptyBackgroundViewWrapper mEmptyBackgroundViewWrapper;
@@ -765,7 +766,8 @@
             @Override
             public void onStatusIndicatorHeightChanged(int indicatorHeight) {
                 mStatusIndicatorHeight = indicatorHeight;
-                updateTopControlsHeight(/*animate=*/true);
+                boolean animate = sDisableStatusIndicatorAnimations ? false : true;
+                updateTopControlsHeight(animate);
             }
         };
         mStatusIndicatorCoordinator.addObserver(mStatusIndicatorObserver);
@@ -933,4 +935,9 @@
         }
         return LanguageAskPrompt.maybeShowLanguageAskPrompt(mActivity, mModalDialogManagerSupplier);
     }
+
+    @VisibleForTesting
+    public static void setDisableStatusIndicatorAnimationsForTesting(boolean disable) {
+        sDisableStatusIndicatorAnimations = disable;
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInstrumentationBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInstrumentationBase.java
index 02660e6..09269e3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInstrumentationBase.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInstrumentationBase.java
@@ -1388,7 +1388,7 @@
      */
     protected void expandPanelAndAssert() throws TimeoutException {
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mManager.setVisibilityStateForTesting(true);
+            mPanel.notifyBarTouched(0);
             mFakeServer.getContentsObserver().wasShown();
             mPanel.animatePanelToState(PanelState.EXPANDED, StateChangeReason.UNKNOWN,
                     PANEL_INTERACTION_RETRY_DELAY_MS);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSystemTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSystemTest.java
index 53ad5c2..3de909c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSystemTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSystemTest.java
@@ -155,7 +155,8 @@
     @SmallTest
     @Feature({"ContextualSearch"})
     @ParameterAnnotations.UseMethodParameter(FeatureParamProvider.class)
-    @FlakyTest(message = "Disabled 4/2021.  https://crbug.com/1192285, /https://crbug.com/1192561")
+    // Revived 6/2022 based on reviver: https://crbug.com/1333277
+    // Previously disabled: https://crbug.com/1192285, https://crbug.com/1192561
     public void testContextualSearchNotDismissedOnBackgroundTabCrash(
             @EnabledFeature int enabledFeature) throws Exception {
         ChromeTabUtils.newTabFromMenu(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUnbatchedTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUnbatchedTest.java
index 53b88bbf..a455e8f1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUnbatchedTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUnbatchedTest.java
@@ -18,9 +18,7 @@
 import org.chromium.base.test.params.ParameterAnnotations;
 import org.chromium.base.test.params.ParameterizedRunner;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.RelatedSearchesControl;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchFakeServer.FakeResolveSearch;
@@ -228,8 +226,7 @@
         Assert.assertTrue("Related Searches results should have been returned but were not!",
                 !resolvedSearchTerm.relatedSearchesJson().isEmpty());
         // Expand the panel and assert that it ends up in the right place.
-        // TODO(crbug.com/1258165): switch to expandPanelAndAssert();
-        tapPeekingBarToExpandAndAssert();
+        expandPanelAndAssert();
 
         // Don't select any Related Searches suggestion, and close the panel
         closePanel();
@@ -239,8 +236,6 @@
     @Test
     @SmallTest
     @Feature({"ContextualSearch"})
-    @FlakyTest(message = "https://crbug.com/1182040")
-    @DisableIf.Build(supported_abis_includes = "arm64-v8a", message = "crbug.com/1240342")
     public void testRelatedSearchesItemSelected() throws Exception {
         FeatureList.setTestFeatures(ENABLE_RELATED_SEARCHES_IN_BAR);
         mFakeServer.reset();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/status_indicator/StatusIndicatorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/status_indicator/StatusIndicatorTest.java
index a29c145..6deaf21 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/status_indicator/StatusIndicatorTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/status_indicator/StatusIndicatorTest.java
@@ -25,6 +25,7 @@
 import org.hamcrest.Matcher;
 import org.hamcrest.Matchers;
 import org.hamcrest.TypeSafeMatcher;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
@@ -73,6 +74,7 @@
 
     @Before
     public void setUp() throws InterruptedException {
+        TabbedRootUiCoordinator.setDisableStatusIndicatorAnimationsForTesting(true);
         mActivityTestRule.startMainActivityOnBlankPage();
         mStatusIndicatorCoordinator = ((TabbedRootUiCoordinator) mActivityTestRule.getActivity()
                                                .getRootUiCoordinatorForTesting())
@@ -82,6 +84,11 @@
         mBrowserControlsStateProvider = mActivityTestRule.getActivity().getBrowserControlsManager();
     }
 
+    @After
+    public void tearDown() {
+        TabbedRootUiCoordinator.setDisableStatusIndicatorAnimationsForTesting(false);
+    }
+
     @Test
     @MediumTest
     public void testInitialState() {
@@ -106,9 +113,6 @@
         "Status", null, Color.BLACK, Color.WHITE, Color.WHITE));
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
-        // TODO(sinansahin): Investigate setting the duration for the browser controls animations to
-        // 0 for testing.
-
         // Wait until the status indicator finishes animating, or becomes fully visible.
         CriteriaHelper.pollUiThread(() -> {
             Criteria.checkThat(mBrowserControlsStateProvider.getTopControlsMinHeightOffset(),
@@ -202,7 +206,7 @@
     @CommandLineFlags.Add({"enable-features=" + ChromeFeatureList.START_SURFACE_ANDROID + "<Study",
             "force-fieldtrials=Study/Group",
             "force-fieldtrial-params=Study.Group:start_surface_variation/single"})
-    @DisabledTest(message = "https://crbug.com/1109965")
+    @DisabledTest(message = "https://crbug.com/1331065")
     public void testShowAndHideOnStartSurface() {
         // clang-format on
         TabUiTestHelper.enterTabSwitcher(mActivityTestRule.getActivity());
@@ -215,8 +219,10 @@
         Assert.assertFalse("Wrong initial composited view visibility.",
                 mStatusIndicatorSceneLayer.isSceneOverlayTreeShowing());
 
-        TestThreadUtils.runOnUiThreadBlocking(() -> mStatusIndicatorCoordinator.show(
-                "Status", null, Color.BLACK, Color.WHITE, Color.WHITE));
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mStatusIndicatorCoordinator.show("Status", null, Color.BLACK, Color.WHITE, Color.WHITE);
+            mStatusIndicatorCoordinator.getMediatorForTesting().finishAnimationsForTesting();
+        });
 
         // The status indicator will be immediately visible.
         onView(withId(R.id.status_indicator)).check(matches(withEffectiveVisibility(VISIBLE)));
@@ -232,9 +238,11 @@
                 .check(matches(
                         withTopMargin(mBrowserControlsStateProvider.getTopControlsHeight())));
 
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> mStatusIndicatorCoordinator.updateContent("Exit status", null,
-                        Color.WHITE, Color.BLACK, Color.BLACK, () -> {}));
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mStatusIndicatorCoordinator.updateContent(
+                    "Exit status", null, Color.WHITE, Color.BLACK, Color.BLACK, () -> {});
+            mStatusIndicatorCoordinator.getMediatorForTesting().finishAnimationsForTesting();
+        });
 
         // #updateContent shouldn't change the layout.
         onView(withId(R.id.status_indicator)).check(matches(withEffectiveVisibility(VISIBLE)));
@@ -244,7 +252,16 @@
                 .check(matches(
                         withTopMargin(mBrowserControlsStateProvider.getTopControlsHeight())));
 
-        TestThreadUtils.runOnUiThreadBlocking(() -> mStatusIndicatorCoordinator.hide());
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mStatusIndicatorCoordinator.hide();
+            mStatusIndicatorCoordinator.getMediatorForTesting().finishAnimationsForTesting();
+        });
+
+        // Wait until the status indicator finishes animating, or becomes fully hidden.
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(
+                    mBrowserControlsStateProvider.getTopControlsMinHeightOffset(), Matchers.is(0));
+        });
 
         onView(withId(R.id.status_indicator)).check(matches(withEffectiveVisibility(GONE)));
         onView(withId(R.id.control_container)).check(matches(withTopMargin(0)));
@@ -255,7 +272,6 @@
 
     @Test
     @MediumTest
-    @DisabledTest(message = "https://crbug.com/1109965")
     public void testShowAndHideOnNTP() {
         mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
         Tab tab = mActivityTestRule.getActivity().getActivityTab();
@@ -272,8 +288,16 @@
         Assert.assertFalse("Wrong initial composited view visibility.",
                 mStatusIndicatorSceneLayer.isSceneOverlayTreeShowing());
 
-        TestThreadUtils.runOnUiThreadBlocking(() -> mStatusIndicatorCoordinator.show(
-                "Status", null, Color.BLACK, Color.WHITE, Color.WHITE));
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mStatusIndicatorCoordinator.show("Status", null, Color.BLACK, Color.WHITE, Color.WHITE);
+            mStatusIndicatorCoordinator.getMediatorForTesting().finishAnimationsForTesting();
+        });
+
+        // Wait until the status indicator finishes animating.
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(mBrowserControlsStateProvider.getTopControlsMinHeightOffset(),
+                    Matchers.is(getStatusIndicator().getHeight()));
+        });
 
         // The status indicator will be immediately visible.
         onView(withId(R.id.status_indicator)).check(matches(withEffectiveVisibility(VISIBLE)));
@@ -281,9 +305,11 @@
                 .check(matches(withTopMargin(getStatusIndicator().getHeight())));
         onView(withId(viewId)).check(matches(withTopMargin(getStatusIndicator().getHeight())));
 
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> mStatusIndicatorCoordinator.updateContent("Exit status", null,
-                        Color.WHITE, Color.BLACK, Color.BLACK, () -> {}));
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mStatusIndicatorCoordinator.updateContent(
+                    "Exit status", null, Color.WHITE, Color.BLACK, Color.BLACK, () -> {});
+            mStatusIndicatorCoordinator.getMediatorForTesting().finishAnimationsForTesting();
+        });
 
         // #updateContent shouldn't change the layout.
         onView(withId(R.id.status_indicator)).check(matches(withEffectiveVisibility(VISIBLE)));
@@ -291,7 +317,16 @@
                 .check(matches(withTopMargin(getStatusIndicator().getHeight())));
         onView(withId(viewId)).check(matches(withTopMargin(getStatusIndicator().getHeight())));
 
-        TestThreadUtils.runOnUiThreadBlocking(() -> mStatusIndicatorCoordinator.hide());
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mStatusIndicatorCoordinator.hide();
+            mStatusIndicatorCoordinator.getMediatorForTesting().finishAnimationsForTesting();
+        });
+
+        // Wait until the status indicator finishes animating, or becomes fully hidden.
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(
+                    mBrowserControlsStateProvider.getTopControlsMinHeightOffset(), Matchers.is(0));
+        });
 
         onView(withId(R.id.status_indicator)).check(matches(withEffectiveVisibility(GONE)));
         onView(withId(R.id.control_container)).check(matches(withTopMargin(0)));
@@ -300,7 +335,6 @@
 
     @Test
     @MediumTest
-    @DisabledTest(message = "https://crbug.com/1109965")
     public void testShowAndHideOnRecentTabsPage() {
         mActivityTestRule.loadUrl(UrlConstants.RECENT_TABS_URL);
         final Tab tab = mActivityTestRule.getActivity().getActivityTab();
@@ -314,11 +348,17 @@
                 .check(matches(
                         withTopMargin(mBrowserControlsStateProvider.getTopControlsHeight())));
 
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> mStatusIndicatorCoordinator.show(
-                        "Status", null, Color.BLACK, Color.WHITE, Color.WHITE));
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mStatusIndicatorCoordinator.show("Status", null, Color.BLACK, Color.WHITE, Color.WHITE);
+            mStatusIndicatorCoordinator.getMediatorForTesting().finishAnimationsForTesting();
+        });
 
-        // The status indicator will be immediately visible.
+        // Wait until the status indicator finishes animating.
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(mBrowserControlsStateProvider.getTopControlsMinHeightOffset(),
+                    Matchers.is(getStatusIndicator().getHeight()));
+        });
+
         onView(withId(R.id.status_indicator)).check(matches(withEffectiveVisibility(VISIBLE)));
         onView(withId(R.id.control_container))
                 .check(matches(withTopMargin(getStatusIndicator().getHeight())));
@@ -326,9 +366,11 @@
                 .check(matches(
                         withTopMargin(mBrowserControlsStateProvider.getTopControlsHeight())));
 
-        TestThreadUtils.runOnUiThreadBlocking(
-                () -> mStatusIndicatorCoordinator.updateContent("Exit status", null,
-                        Color.WHITE, Color.BLACK, Color.BLACK, () -> {}));
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mStatusIndicatorCoordinator.updateContent(
+                    "Exit status", null, Color.WHITE, Color.BLACK, Color.BLACK, () -> {});
+            mStatusIndicatorCoordinator.getMediatorForTesting().finishAnimationsForTesting();
+        });
 
         // #updateContent shouldn't change the layout.
         onView(withId(R.id.status_indicator)).check(matches(withEffectiveVisibility(VISIBLE)));
@@ -338,7 +380,16 @@
                 .check(matches(
                         withTopMargin(mBrowserControlsStateProvider.getTopControlsHeight())));
 
-        TestThreadUtils.runOnUiThreadBlocking(() -> mStatusIndicatorCoordinator.hide());
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mStatusIndicatorCoordinator.hide();
+            mStatusIndicatorCoordinator.getMediatorForTesting().finishAnimationsForTesting();
+        });
+
+        // Wait until the status indicator finishes animating, or becomes fully hidden.
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(
+                    mBrowserControlsStateProvider.getTopControlsMinHeightOffset(), Matchers.is(0));
+        });
 
         onView(withId(R.id.status_indicator)).check(matches(withEffectiveVisibility(GONE)));
         onView(withId(R.id.control_container)).check(matches(withTopMargin(0)));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGroupUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGroupUnitTest.java
index f8abd7f8..119b326 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGroupUnitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGroupUnitTest.java
@@ -43,6 +43,7 @@
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.UiThreadTest;
 import org.chromium.base.test.util.Batch;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.FlakyTest;
 import org.chromium.chrome.browser.native_page.ContextMenuManager;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
@@ -201,6 +202,7 @@
     @Test
     @UiThreadTest
     @SmallTest
+    @DisabledTest(message = "https://crbug.com/1330627, https://crbug.com/1293208")
     public void testReceiveNewTilesWithDataChanges_TrackLoad() {
         TileGroup tileGroup = initialiseTileGroup(/* deferLoad: */ true, URLS);
 
@@ -294,6 +296,7 @@
     @Test
     @UiThreadTest
     @SmallTest
+    @DisabledTest(message = "https://crbug.com/1330627, https://crbug.com/1293208")
     public void testRenderTileView() {
         SuggestionsUiDelegate uiDelegate = mSuggestionsUiDelegate;
         when(uiDelegate.getImageFetcher()).thenReturn(mImageFetcher);
@@ -390,6 +393,7 @@
     @Test
     @UiThreadTest
     @SmallTest
+    @DisabledTest(message = "https://crbug.com/1330627, https://crbug.com/1293208")
     public void testIconLoadingForInit() {
         TileGroup tileGroup = initialiseTileGroup(URLS);
         Tile tile = tileGroup.getTileSections().get(TileSectionType.PERSONALIZED).get(0);
@@ -426,6 +430,7 @@
     @Test
     @UiThreadTest
     @SmallTest
+    @DisabledTest(message = "https://crbug.com/1330627, https://crbug.com/1293208")
     public void testIconLoading_Sync() {
         TileGroup tileGroup = initialiseTileGroup();
         mImageFetcher.fulfillLargeIconRequests();
@@ -445,6 +450,7 @@
     @Test
     @UiThreadTest
     @SmallTest
+    @DisabledTest(message = "https://crbug.com/1330627, https://crbug.com/1293208")
     public void testIconLoading_AsyncNoTrack() {
         TileGroup tileGroup = initialiseTileGroup(/* deferLoad: */ true);
         mImageFetcher.fulfillLargeIconRequests();
@@ -465,6 +471,7 @@
     @Test
     @UiThreadTest
     @SmallTest
+    @DisabledTest(message = "https://crbug.com/1330627, https://crbug.com/1293208")
     public void testIconLoading_AsyncTrack() {
         TileGroup tileGroup = initialiseTileGroup(/* deferLoad: */ true);
         mImageFetcher.fulfillLargeIconRequests();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java
index 5d6b065..fd4450c 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategyTest.java
@@ -20,7 +20,6 @@
 import android.app.Activity;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.Point;
 import android.os.Looper;
 import android.os.SystemClock;
 import android.util.DisplayMetrics;
@@ -51,7 +50,6 @@
 import org.robolectric.shadows.ShadowLog;
 
 import org.chromium.base.Callback;
-import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -119,15 +117,12 @@
     @Mock
     private View mToolbarCoordinator;
     @Mock
-    private FrameLayout mParentView;
+    private ViewGroup mContentFrame;
     @Mock
     private ViewGroup mCoordinatorLayout;
 
     private List<WindowManager.LayoutParams> mAttributeResults;
     private DisplayMetrics mRealMetrics;
-    private Point mDisplaySize;
-    private ObservableSupplierImpl<FrameLayout> mParentViewSupplier =
-            new ObservableSupplierImpl<>();
     private Callback<Integer> mBottomInsetCallback = inset -> {};
     private FrameLayout.LayoutParams mLayoutParams = new FrameLayout.LayoutParams(
             FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
@@ -141,6 +136,8 @@
         when(mActivity.getWindowManager()).thenReturn(mWindowManager);
         when(mActivity.findViewById(R.id.custom_tabs_handle_view_stub)).thenReturn(mHandleViewStub);
         when(mActivity.findViewById(R.id.custom_tabs_handle_view)).thenReturn(mHandleView);
+        when(mActivity.findViewById(R.id.coordinator)).thenReturn(mCoordinatorLayout);
+        when(mActivity.findViewById(android.R.id.content)).thenReturn(mContentFrame);
         when(mHandleView.getLayoutParams()).thenReturn(mLayoutParams);
         when(mToolbarCoordinator.getLayoutParams()).thenReturn(mLayoutParams);
         mAttributes = new WindowManager.LayoutParams();
@@ -156,14 +153,12 @@
         when(mViewAnimator.setDuration(anyLong())).thenReturn(mViewAnimator);
         when(mViewAnimator.setListener(anyObject())).thenReturn(mViewAnimator);
         when(mSpinnerView.getLayoutParams()).thenReturn(mLayoutParams);
-        when(mSpinnerView.getParent()).thenReturn(mParentView);
+        when(mSpinnerView.getParent()).thenReturn(mContentFrame);
         when(mSpinnerView.animate()).thenReturn(mViewAnimator);
-        when(mParentView.getLayoutParams()).thenReturn(mLayoutParams);
-        when(mParentView.getParent()).thenReturn(mCoordinatorLayout);
+        when(mContentFrame.getLayoutParams()).thenReturn(mLayoutParams);
+        when(mContentFrame.getHeight()).thenReturn(DEVICE_HEIGHT - NAVBAR_HEIGHT);
         when(mCoordinatorLayout.getLayoutParams()).thenReturn(mLayoutParams);
 
-        mParentViewSupplier.set(mParentView);
-
         mConfiguration.orientation = Configuration.ORIENTATION_PORTRAIT;
 
         mAttributeResults = new ArrayList<>();
@@ -186,26 +181,20 @@
         })
                 .when(mDisplay)
                 .getRealMetrics(any(DisplayMetrics.class));
+    }
 
-        mDisplaySize = new Point();
-        mDisplaySize.x = DEVICE_WIDTH;
-        mDisplaySize.y = DEVICE_HEIGHT - NAVBAR_HEIGHT;
-        doAnswer(invocation -> {
-            Point point = invocation.getArgument(0);
-            point.x = mDisplaySize.x;
-            point.y = mDisplaySize.y;
-            return null;
-        })
-                .when(mDisplay)
-                .getSize(any(Point.class));
+    private PartialCustomTabHeightStrategy createPcctAtHeight(int heightPx) {
+        PartialCustomTabHeightStrategy pcct = new PartialCustomTabHeightStrategy(mActivity,
+                heightPx, mMultiWindowModeStateDispatcher, null, null, mOnResizedCallback,
+                mActivityLifecycleDispatcher);
+        pcct.setMockViewForTesting(
+                mNavbar, mSpinnerView, mSpinner, mToolbarView, mToolbarCoordinator);
+        return pcct;
     }
 
     @Test
     public void create_heightIsCappedToHalfOfDeviceHeight() {
-        new PartialCustomTabHeightStrategy(mActivity, mParentViewSupplier, 500,
-                mMultiWindowModeStateDispatcher, null, null, mOnResizedCallback,
-                mActivityLifecycleDispatcher);
-
+        createPcctAtHeight(500);
         verifyWindowFlagsSet();
 
         assertEquals(1, mAttributeResults.size());
@@ -214,10 +203,7 @@
 
     @Test
     public void create_largeInitialHeight() {
-        new PartialCustomTabHeightStrategy(mActivity, mParentViewSupplier, 5000,
-                mMultiWindowModeStateDispatcher, null, null, mOnResizedCallback,
-                mActivityLifecycleDispatcher);
-
+        createPcctAtHeight(5000);
         verifyWindowFlagsSet();
 
         assertEquals(1, mAttributeResults.size());
@@ -226,10 +212,7 @@
 
     @Test
     public void create_heightIsCappedToDeviceHeight() {
-        new PartialCustomTabHeightStrategy(mActivity, mParentViewSupplier, DEVICE_HEIGHT + 100,
-                mMultiWindowModeStateDispatcher, null, null, mOnResizedCallback,
-                mActivityLifecycleDispatcher);
-
+        createPcctAtHeight(DEVICE_HEIGHT + 100);
         verifyWindowFlagsSet();
 
         assertEquals(1, mAttributeResults.size());
@@ -241,12 +224,8 @@
         mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
         mRealMetrics.widthPixels = DEVICE_HEIGHT;
         mRealMetrics.heightPixels = DEVICE_WIDTH;
-        mDisplaySize.x = DEVICE_HEIGHT - NAVBAR_HEIGHT;
-        mDisplaySize.y = DEVICE_WIDTH;
-        new PartialCustomTabHeightStrategy(mActivity, mParentViewSupplier, 800,
-                mMultiWindowModeStateDispatcher, null, null, mOnResizedCallback,
-                mActivityLifecycleDispatcher);
-
+        when(mContentFrame.getHeight()).thenReturn(DEVICE_WIDTH);
+        createPcctAtHeight(800);
         verifyWindowFlagsSet();
 
         // Full height when in landscape mode.
@@ -256,12 +235,7 @@
 
     @Test
     public void moveUp() {
-        PartialCustomTabHeightStrategy strategy = new PartialCustomTabHeightStrategy(mActivity,
-                mParentViewSupplier, 500, mMultiWindowModeStateDispatcher, null, null,
-                mOnResizedCallback, mActivityLifecycleDispatcher);
-        strategy.setMockViewForTesting(mNavbar, mSpinnerView, mSpinner, mToolbarView,
-                mToolbarCoordinator, mCoordinatorLayout);
-
+        PartialCustomTabHeightStrategy strategy = createPcctAtHeight(500);
         verifyWindowFlagsSet();
 
         assertEquals(1, mAttributeResults.size());
@@ -299,9 +273,7 @@
         mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
         mRealMetrics.widthPixels = DEVICE_HEIGHT;
         mRealMetrics.heightPixels = DEVICE_WIDTH;
-        PartialCustomTabHeightStrategy strategy = new PartialCustomTabHeightStrategy(mActivity,
-                mParentViewSupplier, 800, mMultiWindowModeStateDispatcher, null, null,
-                mOnResizedCallback, mActivityLifecycleDispatcher);
+        PartialCustomTabHeightStrategy strategy = createPcctAtHeight(800);
 
         // Pass null because we have a mock Activity and we don't depend on the GestureDetector
         // inside as we test MotionEvents directly.
@@ -317,9 +289,7 @@
     @Test
     public void moveUp_multiwindowModeUnresizable() {
         when(mMultiWindowModeStateDispatcher.isInMultiWindowMode()).thenReturn(true);
-        PartialCustomTabHeightStrategy strategy = new PartialCustomTabHeightStrategy(mActivity,
-                mParentViewSupplier, 800, mMultiWindowModeStateDispatcher, null, null,
-                mOnResizedCallback, mActivityLifecycleDispatcher);
+        PartialCustomTabHeightStrategy strategy = createPcctAtHeight(800);
 
         // Pass null because we have a mock Activity and we don't depend on the GestureDetector
         // inside as we test MotionEvents directly.
@@ -334,11 +304,7 @@
 
     @Test
     public void rotateToLandescapeUnresizable() {
-        PartialCustomTabHeightStrategy strategy = new PartialCustomTabHeightStrategy(mActivity,
-                mParentViewSupplier, 800, mMultiWindowModeStateDispatcher, null, null,
-                mOnResizedCallback, mActivityLifecycleDispatcher);
-        strategy.setMockViewForTesting(mNavbar, mSpinnerView, mSpinner, mToolbarView,
-                mToolbarCoordinator, mCoordinatorLayout);
+        PartialCustomTabHeightStrategy strategy = createPcctAtHeight(800);
 
         // Pass null because we have a mock Activity and we don't depend on the GestureDetector
         // inside as we test MotionEvents directly.
@@ -356,17 +322,12 @@
 
     @Test
     public void rotateToLandescapeHideCustomNavbar() {
-        PartialCustomTabHeightStrategy strategy = new PartialCustomTabHeightStrategy(mActivity,
-                mParentViewSupplier, 800, mMultiWindowModeStateDispatcher, null, null,
-                mOnResizedCallback, mActivityLifecycleDispatcher);
-        strategy.setMockViewForTesting(mNavbar, mSpinnerView, mSpinner, mToolbarView,
-                mToolbarCoordinator, mCoordinatorLayout);
+        PartialCustomTabHeightStrategy strategy = createPcctAtHeight(800);
 
         mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
         mRealMetrics.widthPixels = DEVICE_HEIGHT;
         mRealMetrics.heightPixels = DEVICE_WIDTH;
-        mDisplaySize.x = DEVICE_HEIGHT - NAVBAR_HEIGHT;
-        mDisplaySize.y = DEVICE_WIDTH;
+        when(mContentFrame.getHeight()).thenReturn(DEVICE_WIDTH);
 
         strategy.onConfigurationChanged(mConfiguration);
 
@@ -376,9 +337,7 @@
 
     @Test
     public void enterMultiwindowModeUnresizable() {
-        PartialCustomTabHeightStrategy strategy = new PartialCustomTabHeightStrategy(mActivity,
-                mParentViewSupplier, 800, mMultiWindowModeStateDispatcher, null, null,
-                mOnResizedCallback, mActivityLifecycleDispatcher);
+        PartialCustomTabHeightStrategy strategy = createPcctAtHeight(800);
 
         // Pass null because we have a mock Activity and we don't depend on the GestureDetector
         // inside as we test MotionEvents directly.
@@ -395,11 +354,7 @@
 
     @Test
     public void moveUpThenDown() {
-        PartialCustomTabHeightStrategy strategy = new PartialCustomTabHeightStrategy(mActivity,
-                mParentViewSupplier, 500, mMultiWindowModeStateDispatcher, null, null,
-                mOnResizedCallback, mActivityLifecycleDispatcher);
-        strategy.setMockViewForTesting(mNavbar, mSpinnerView, mSpinner, mToolbarView,
-                mToolbarCoordinator, mCoordinatorLayout);
+        PartialCustomTabHeightStrategy strategy = createPcctAtHeight(500);
 
         verify(mWindow).addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
         verify(mWindow).clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
@@ -436,11 +391,7 @@
 
     @Test
     public void moveToTopThenMoveDown() {
-        PartialCustomTabHeightStrategy strategy = new PartialCustomTabHeightStrategy(mActivity,
-                mParentViewSupplier, 500, mMultiWindowModeStateDispatcher, null, null,
-                mOnResizedCallback, mActivityLifecycleDispatcher);
-        strategy.setMockViewForTesting(mNavbar, mSpinnerView, mSpinner, mToolbarView,
-                mToolbarCoordinator, mCoordinatorLayout);
+        PartialCustomTabHeightStrategy strategy = createPcctAtHeight(500);
 
         verify(mWindow).addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
         verify(mWindow).clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
@@ -499,12 +450,7 @@
 
     @Test
     public void moveDownToDismiss() {
-        PartialCustomTabHeightStrategy strategy = new PartialCustomTabHeightStrategy(mActivity,
-                mParentViewSupplier, 500, mMultiWindowModeStateDispatcher, null, null,
-                mOnResizedCallback, mActivityLifecycleDispatcher);
-        strategy.setMockViewForTesting(mNavbar, mSpinnerView, mSpinner, mToolbarView,
-                mToolbarCoordinator, mCoordinatorLayout);
-
+        PartialCustomTabHeightStrategy strategy = createPcctAtHeight(500);
         verifyWindowFlagsSet();
 
         assertEquals(1, mAttributeResults.size());
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index 980f8730..97fabc4 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -109,6 +109,7 @@
 
 #if BUILDFLAG(IS_MAC)
 #include "base/mac/foundation_util.h"
+#include "base/message_loop/message_pump_mac.h"
 #include "chrome/app/chrome_main_mac.h"
 #include "chrome/browser/chrome_browser_application_mac.h"
 #include "chrome/browser/mac/relauncher.h"
@@ -794,6 +795,7 @@
   base::sequence_manager::internal::SequenceManagerImpl::InitializeFeatures();
 #if BUILDFLAG(IS_MAC)
   base::PlatformThread::InitializeOptimizedRealtimeThreadingFeature();
+  base::MessagePumpCFRunLoopBase::InitializeFeatures();
 #endif
 }
 
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 31f4dd7c..b135144 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1883,6 +1883,9 @@
     "//chrome/browser/devtools",
     "//chrome/browser/favicon",
     "//chrome/browser/profiling_host",
+
+    # TODO(crbug.com/1335199): break this dep when favicon is in its own target
+    "//chrome/browser/share",
     "//chrome/browser/ui",
     "//chrome/browser/ui/webui/bluetooth_internals",
     "//chrome/browser/storage_access_api:permissions",
@@ -3418,8 +3421,6 @@
       "//url:origin_android",
     ]
 
-    allow_circular_includes_from += [ "//chrome/browser/share" ]
-
     deps -= [ "//components/storage_monitor" ]
 
     if (enable_supervised_users) {
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 7f19cec..89ad5d4 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3521,6 +3521,9 @@
      flag_descriptions::kAshEnableUnifiedDesktopName,
      flag_descriptions::kAshEnableUnifiedDesktopDescription, kOsCrOS,
      SINGLE_VALUE_TYPE(switches::kEnableUnifiedDesktop)},
+    {"rounded-display", flag_descriptions::kRoundedDisplay,
+     flag_descriptions::kRoundedDisplayDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(ash::features::kRoundedDisplay)},
     {"bluetooth-fix-a2dp-packet-size",
      flag_descriptions::kBluetoothFixA2dpPacketSizeName,
      flag_descriptions::kBluetoothFixA2dpPacketSizeDescription, kOsCrOS,
diff --git a/chrome/browser/app_controller_mac_browsertest.mm b/chrome/browser/app_controller_mac_browsertest.mm
index 77cef98..b44a9a95a1 100644
--- a/chrome/browser/app_controller_mac_browsertest.mm
+++ b/chrome/browser/app_controller_mac_browsertest.mm
@@ -1234,7 +1234,7 @@
   content::TestActivationManager navigation_manager(GetActiveWebContents(),
                                                     prerender_url);
   ASSERT_TRUE(
-      content::ExecJs(GetActiveWebContents()->GetMainFrame(),
+      content::ExecJs(GetActiveWebContents()->GetPrimaryMainFrame(),
                       content::JsReplace("location = $1", prerender_url)));
   navigation_manager.WaitForNavigationFinished();
   EXPECT_TRUE(navigation_manager.was_activated());
diff --git a/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.cc b/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.cc
index 0d2988c..e986093 100644
--- a/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.cc
+++ b/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager.cc
@@ -224,10 +224,15 @@
 }
 
 void ArcInputOverlayManager::RegisterWindow(aura::Window* window) {
+  // Only register the focused window that is not registered.
   if (!window || window != window->GetToplevelWindow() ||
       registered_top_level_window_ == window) {
     return;
   }
+  DCHECK_EQ(ash::window_util::GetFocusedWindow()->GetToplevelWindow(), window);
+  if (ash::window_util::GetFocusedWindow()->GetToplevelWindow() != window)
+    return;
+
   auto it = input_overlay_enabled_windows_.find(window);
   if (it == input_overlay_enabled_windows_.end())
     return;
@@ -327,8 +332,10 @@
 }
 
 void ArcInputOverlayManager::OnWindowAddedToRootWindow(aura::Window* window) {
-  if (!window)
+  if (!window ||
+      ash::window_util::GetFocusedWindow()->GetToplevelWindow() != window) {
     return;
+  }
   RegisterWindow(window);
 }
 
diff --git a/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager_unittest.cc b/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager_unittest.cc
index 9f501641..62d7bbb 100644
--- a/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager_unittest.cc
+++ b/chrome/browser/ash/arc/input_overlay/arc_input_overlay_manager_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "ash/shell.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
+#include "ash/wm/window_util.h"
 #include "chrome/browser/ash/arc/input_overlay/test/arc_test_window.h"
 #include "chrome/browser/ash/arc/input_overlay/test/event_capturer.h"
 #include "components/exo/test/exo_test_base.h"
@@ -75,10 +76,6 @@
     return arc_test_input_overlay_manager_->display_overlay_controller_.get();
   }
 
-  void WindowFocus(aura::Window* gain_focus, aura::Window* lost_focus) {
-    arc_test_input_overlay_manager_->OnWindowFocused(gain_focus, lost_focus);
-  }
-
   // TODO(djacobo): Maybe move all tests inside input_overlay namespace.
   void DismissEducationalDialog(input_overlay::TouchInjector* injector) {
     injector->GetControllerForTesting()->DismissEducationalViewForTesting();
@@ -104,6 +101,8 @@
 };
 
 TEST_F(ArcInputOverlayManagerTest, TestPropertyChangeAndWindowDestroy) {
+  aura::client::FocusClient* focus_client =
+      aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
   // Test app with input overlay data.
   auto arc_window = std::make_unique<input_overlay::test::ArcTestWindow>(
       exo_test_helper(), ash::Shell::GetPrimaryRootWindow(),
@@ -114,7 +113,7 @@
   // Input overlay registers the window after reading the data when the window
   // is still focused. In the test, the arc_window is considered as focused now.
   EXPECT_TRUE(GetRegisteredWindow());
-  WindowFocus(arc_window->GetWindow(), nullptr);
+  focus_client->FocusWindow(arc_window->GetWindow());
   EXPECT_TRUE(GetRegisteredWindow());
 
   // Test app with input overlay data when window is destroyed.
@@ -133,12 +132,14 @@
 TEST_F(ArcInputOverlayManagerTest, TestInputMethodObsever) {
   ASSERT_FALSE(GetInputMethod());
   ASSERT_FALSE(IsTextInputActive());
+  aura::client::FocusClient* focus_client =
+      aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
   auto arc_window = std::make_unique<input_overlay::test::ArcTestWindow>(
       exo_test_helper(), ash::Shell::GetPrimaryRootWindow(),
       kEnabledPackageName);
   // I/O takes time here.
   task_environment()->FastForwardBy(kIORead);
-  WindowFocus(arc_window->GetWindow(), nullptr);
+  focus_client->FocusWindow(arc_window->GetWindow());
   ui::InputMethod* input_method = GetInputMethod();
   EXPECT_TRUE(GetInputMethod());
   input_method->SetFocusedTextInputClient(nullptr);
@@ -154,6 +155,8 @@
 }
 
 TEST_F(ArcInputOverlayManagerTest, TestWindowFocusChange) {
+  aura::client::FocusClient* focus_client =
+      aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
   auto arc_window = std::make_unique<input_overlay::test::ArcTestWindow>(
       exo_test_helper(), ash::Shell::GetPrimaryRootWindow(),
       kEnabledPackageName);
@@ -172,10 +175,10 @@
   EXPECT_EQ(3, (int)injector->actions().size());
 
   EXPECT_TRUE(!GetRegisteredWindow() && !GetDisplayOverlayController());
-  WindowFocus(arc_window->GetWindow(), nullptr);
+  focus_client->FocusWindow(arc_window->GetWindow());
   EXPECT_EQ(arc_window->GetWindow(), GetRegisteredWindow());
   EXPECT_TRUE(GetDisplayOverlayController());
-  WindowFocus(arc_window_no_data->GetWindow(), arc_window->GetWindow());
+  focus_client->FocusWindow(arc_window_no_data->GetWindow());
   EXPECT_TRUE(!GetRegisteredWindow() && !GetDisplayOverlayController());
 }
 
@@ -207,6 +210,8 @@
 }
 
 TEST_F(ArcInputOverlayManagerTest, TestKeyEventSourceRewriterForMultiDisplay) {
+  aura::client::FocusClient* focus_client =
+      aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
   UpdateDisplay("1000x900,1000x900");
   aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
   display::Display display0 = display::Screen::GetScreen()->GetDisplayMatching(
@@ -226,7 +231,7 @@
   // Make sure to dismiss the educational dialog in beforehand.
   auto* injector = GetTouchInjector(arc_window->GetWindow());
   EXPECT_TRUE(injector);
-  WindowFocus(arc_window->GetWindow(), nullptr);
+  focus_client->FocusWindow(arc_window->GetWindow());
   DismissEducationalDialog(injector);
   EXPECT_TRUE(GetKeyEventSourceRewriter());
   // Simulate the fact that key events are only sent to primary root window
@@ -264,7 +269,7 @@
   arc_window->SetBounds(display1, gfx::Rect(10, 10, 100, 100));
   EXPECT_TRUE(GetKeyEventSourceRewriter());
   // When losing focus, |key_event_source_rewriter_| should be destroyed too.
-  WindowFocus(nullptr, arc_window->GetWindow());
+  focus_client->FocusWindow(nullptr);
   EXPECT_FALSE(GetKeyEventSourceRewriter());
   arc_window.reset();
 
@@ -273,7 +278,7 @@
   auto arc_window_no_data =
       std::make_unique<input_overlay::test::ArcTestWindow>(
           exo_test_helper(), root_windows[1], kRandomPackageName);
-  WindowFocus(arc_window_no_data->GetWindow(), nullptr);
+  focus_client->FocusWindow(arc_window_no_data->GetWindow());
   EXPECT_FALSE(GetKeyEventSourceRewriter());
   arc_window_no_data.reset();
 
@@ -289,13 +294,13 @@
   arc_window_no_data = std::make_unique<input_overlay::test::ArcTestWindow>(
       exo_test_helper(), root_windows[0], kRandomPackageName);
   // Focus on window without input overlay.
-  WindowFocus(arc_window_no_data->GetWindow(), nullptr);
+  focus_client->FocusWindow(arc_window_no_data->GetWindow());
   event_generator->PressKey(ui::VKEY_A, ui::EF_NONE, 1 /* keyboard id */);
   event_generator->ReleaseKey(ui::VKEY_A, ui::EF_NONE, 1 /* keyboard id */);
   EXPECT_EQ(2u, event_capturer.key_events().size());
   event_capturer.Clear();
   // Focus input overlay window.
-  WindowFocus(arc_window->GetWindow(), arc_window_no_data->GetWindow());
+  focus_client->FocusWindow(arc_window->GetWindow());
   EXPECT_TRUE(GetKeyEventSourceRewriter());
   event_generator->PressKey(ui::VKEY_A, ui::EF_NONE, 1 /* keyboard id */);
   event_generator->ReleaseKey(ui::VKEY_A, ui::EF_NONE, 1 /* keyboard id */);
diff --git a/chrome/browser/ash/dbus/ash_dbus_helper.cc b/chrome/browser/ash/dbus/ash_dbus_helper.cc
index 1fe45e1..4b8f5973 100644
--- a/chrome/browser/ash/dbus/ash_dbus_helper.cc
+++ b/chrome/browser/ash/dbus/ash_dbus_helper.cc
@@ -53,6 +53,7 @@
 #include "chromeos/dbus/hermes/hermes_clients.h"
 #include "chromeos/dbus/human_presence/human_presence_dbus_client.h"
 #include "chromeos/dbus/init/initialize_dbus_client.h"
+#include "chromeos/dbus/lorgnette_manager/lorgnette_manager_client.h"
 #include "chromeos/dbus/machine_learning/machine_learning_client.h"
 #include "chromeos/dbus/missive/missive_client.h"
 #include "chromeos/dbus/permission_broker/permission_broker_client.h"
@@ -139,6 +140,7 @@
   InitializeDBusClient<chromeos::InstallAttributesClient>(bus);
   InitializeDBusClient<IpPeripheralServiceClient>(bus);
   InitializeDBusClient<KerberosClient>(bus);
+  InitializeDBusClient<chromeos::LorgnetteManagerClient>(bus);
   InitializeDBusClient<chromeos::MachineLearningClient>(bus);
   InitializeDBusClient<MediaAnalyticsClient>(bus);
   InitializeDBusClient<chromeos::MissiveClient>(bus);
@@ -238,6 +240,7 @@
   chromeos::MissiveClient::Shutdown();
   MediaAnalyticsClient::Shutdown();
   chromeos::MachineLearningClient::Shutdown();
+  chromeos::LorgnetteManagerClient::Shutdown();
   KerberosClient::Shutdown();
   IpPeripheralServiceClient::Shutdown();
   chromeos::InstallAttributesClient::Shutdown();
diff --git a/chrome/browser/ash/events/OWNERS b/chrome/browser/ash/events/OWNERS
index 3b4e32e6..637480f 100644
--- a/chrome/browser/ash/events/OWNERS
+++ b/chrome/browser/ash/events/OWNERS
@@ -1,3 +1,2 @@
-sadrul@chromium.org
 
 per-file *event_rewriter* = kpschoedel@chromium.org
diff --git a/chrome/browser/ash/printing/bulk_printers_calculator.cc b/chrome/browser/ash/printing/bulk_printers_calculator.cc
index 7a85e54..d077d0e 100644
--- a/chrome/browser/ash/printing/bulk_printers_calculator.cc
+++ b/chrome/browser/ash/printing/bulk_printers_calculator.cc
@@ -79,14 +79,12 @@
   auto parsed_printers = std::make_unique<PrinterCache>();
   parsed_printers->reserve(printer_list.size());
   for (const base::Value& val : printer_list) {
-    // TODO(skau): Convert to the new Value APIs.
-    const base::DictionaryValue* printer_dict;
-    if (!val.GetAsDictionary(&printer_dict)) {
+    if (!val.is_dict()) {
       LOG(WARNING) << "Entry in printers policy skipped.  Not a dictionary.";
       continue;
     }
 
-    auto printer = chromeos::RecommendedPrinterToPrinter(*printer_dict);
+    auto printer = chromeos::RecommendedPrinterToPrinter(val.GetDict());
     if (!printer) {
       LOG(WARNING) << "Failed to parse printer configuration.  Skipped.";
       continue;
diff --git a/chrome/browser/ash/printing/enterprise_printers_provider.cc b/chrome/browser/ash/printing/enterprise_printers_provider.cc
index ca0484f..32b25a5 100644
--- a/chrome/browser/ash/printing/enterprise_printers_provider.cc
+++ b/chrome/browser/ash/printing/enterprise_printers_provider.cc
@@ -135,10 +135,9 @@
     recommended_printers_.clear();
     std::vector<std::string> data = FromPrefs(prefs::kRecommendedPrinters);
     for (const auto& printer_json : data) {
-      absl::optional<base::Value> printer_dictionary = base::JSONReader::Read(
+      absl::optional<base::Value> printer_value = base::JSONReader::Read(
           printer_json, base::JSON_ALLOW_TRAILING_COMMAS);
-      if (!printer_dictionary.has_value() ||
-          !printer_dictionary.value().is_dict()) {
+      if (!printer_value.has_value() || !printer_value.value().is_dict()) {
         LOG(WARNING) << "Ignoring invalid printer.  Invalid JSON object: "
                      << printer_json;
         continue;
@@ -148,10 +147,11 @@
       // unique so we'll hash the record.  This will not collide with the
       // UUIDs generated for user entries.
       std::string id = base::MD5String(printer_json);
-      printer_dictionary.value().SetStringKey(chromeos::kPrinterId, id);
+      base::Value::Dict& printer_dictionary = printer_value.value().GetDict();
+      printer_dictionary.Set(chromeos::kPrinterId, id);
 
-      auto new_printer = chromeos::RecommendedPrinterToPrinter(
-          base::Value::AsDictionaryValue(printer_dictionary.value()));
+      auto new_printer =
+          chromeos::RecommendedPrinterToPrinter(printer_dictionary);
       if (!new_printer) {
         LOG(WARNING) << "Recommended printer is malformed.";
         continue;
diff --git a/chrome/browser/ash/printing/oauth2/http_exchange.cc b/chrome/browser/ash/printing/oauth2/http_exchange.cc
index 640757c..e7a256c 100644
--- a/chrome/browser/ash/printing/oauth2/http_exchange.cc
+++ b/chrome/browser/ash/printing/oauth2/http_exchange.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ash/printing/oauth2/http_exchange.h"
 
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/json/json_reader.h"
@@ -42,13 +43,12 @@
 
 HttpExchange::HttpExchange(
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
-    : url_loader_factory_(url_loader_factory),
-      content_(base::Value::Type::DICTIONARY) {}
+    : url_loader_factory_(url_loader_factory) {}
 
 HttpExchange::~HttpExchange() {}
 
 void HttpExchange::Clear() {
-  content_ = base::Value(base::Value::Type::DICTIONARY);
+  content_.clear();
   error_msg_.clear();
   url_loader_.reset();
 }
@@ -56,17 +56,17 @@
 void HttpExchange::AddParamString(const std::string& name,
                                   const std::string& value) {
   DCHECK(!name.empty());
-  content_.SetStringKey(name, value);
+  content_.Set(name, value);
 }
 
 void HttpExchange::AddParamArrayString(const std::string& name,
                                        const std::vector<std::string>& value) {
   DCHECK(!name.empty());
-  base::Value* list_node =
-      content_.SetKey(name, base::Value(base::Value::Type::LIST));
-  for (auto& value_element : value) {
-    list_node->Append(value_element);
+  base::Value::List list_node;
+  for (const auto& value_element : value) {
+    list_node.Append(value_element);
   }
+  content_.Set(name, std::move(list_node));
 }
 
 void HttpExchange::Exchange(
@@ -86,7 +86,7 @@
       return;
     }
   } else if (request_format == ContentFormat::kXWwwFormUrlencoded) {
-    for (const auto kv : content_.DictItems()) {
+    for (const auto kv : content_) {
       if (!data.empty()) {
         data += "&";
       }
@@ -221,7 +221,7 @@
     std::move(callback).Run(StatusCode::kInvalidResponse);
     return;
   }
-  content_ = std::move(parsed.value());
+  content_ = std::move(parsed->GetDict());
 
   // Exits if success.
   if (http_status == success_http_status) {
@@ -406,7 +406,7 @@
 }
 
 base::Value* HttpExchange::FindNode(const std::string& name, bool required) {
-  base::Value* value = content_.FindKey(name);
+  base::Value* value = content_.Find(name);
   if (required && !value) {
     error_msg_ = "Field " + name + " is missing";
   }
diff --git a/chrome/browser/ash/printing/oauth2/http_exchange.h b/chrome/browser/ash/printing/oauth2/http_exchange.h
index 1c5bbf8..17d92e2 100644
--- a/chrome/browser/ash/printing/oauth2/http_exchange.h
+++ b/chrome/browser/ash/printing/oauth2/http_exchange.h
@@ -185,7 +185,7 @@
   std::unique_ptr<network::SimpleURLLoader> url_loader_;
 
   // Stores parameters for a request or parameters parsed from a response.
-  base::Value content_;
+  base::Value::Dict content_;
 
   // Error message.
   std::string error_msg_;
diff --git a/chrome/browser/ash/scanning/lorgnette_scanner_manager.cc b/chrome/browser/ash/scanning/lorgnette_scanner_manager.cc
index 446c34c..79ce87c 100644
--- a/chrome/browser/ash/scanning/lorgnette_scanner_manager.cc
+++ b/chrome/browser/ash/scanning/lorgnette_scanner_manager.cc
@@ -89,8 +89,7 @@
 // Returns a pointer to LorgnetteManagerClient, which is used to detect and
 // interact with scanners via the lorgnette D-Bus service.
 chromeos::LorgnetteManagerClient* GetLorgnetteManagerClient() {
-  DCHECK(DBusThreadManager::IsInitialized());
-  return DBusThreadManager::Get()->GetLorgnetteManagerClient();
+  return chromeos::LorgnetteManagerClient::Get();
 }
 
 // Creates a base name by concatenating the manufacturer and model, if the
diff --git a/chrome/browser/ash/scanning/lorgnette_scanner_manager_unittest.cc b/chrome/browser/ash/scanning/lorgnette_scanner_manager_unittest.cc
index af275c53..da43179 100644
--- a/chrome/browser/ash/scanning/lorgnette_scanner_manager_unittest.cc
+++ b/chrome/browser/ash/scanning/lorgnette_scanner_manager_unittest.cc
@@ -23,6 +23,7 @@
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/lorgnette/lorgnette_service.pb.h"
 #include "chromeos/dbus/lorgnette_manager/fake_lorgnette_manager_client.h"
+#include "chromeos/dbus/lorgnette_manager/lorgnette_manager_client.h"
 #include "net/base/ip_address.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -166,6 +167,7 @@
   LorgnetteScannerManagerTest() {
     run_loop_ = std::make_unique<base::RunLoop>();
     DBusThreadManager::Initialize();
+    chromeos::LorgnetteManagerClient::InitializeFake();
     auto fake_zeroconf_scanner_detector =
         std::make_unique<FakeZeroconfScannerDetector>();
     fake_zeroconf_scanner_detector_ = fake_zeroconf_scanner_detector.get();
@@ -176,13 +178,16 @@
     GetLorgnetteManagerClient()->SetScannerCapabilitiesResponse(capabilities);
   }
 
-  ~LorgnetteScannerManagerTest() override { DBusThreadManager::Shutdown(); }
+  ~LorgnetteScannerManagerTest() override {
+    chromeos::LorgnetteManagerClient::Shutdown();
+    DBusThreadManager::Shutdown();
+  }
 
   // Returns a FakeLorgnetteManagerClient with an empty but successful
   // GetCapabilities response by default.
   FakeLorgnetteManagerClient* GetLorgnetteManagerClient() {
     return static_cast<FakeLorgnetteManagerClient*>(
-        DBusThreadManager::Get()->GetLorgnetteManagerClient());
+        chromeos::LorgnetteManagerClient::Get());
   }
 
   // Calls LorgnetteScannerManager::GetScannerNames() and binds a callback to
diff --git a/chrome/browser/banners/app_banner_manager_browsertest.cc b/chrome/browser/banners/app_banner_manager_browsertest.cc
index 7612355..45d6d4b 100644
--- a/chrome/browser/banners/app_banner_manager_browsertest.cc
+++ b/chrome/browser/banners/app_banner_manager_browsertest.cc
@@ -789,7 +789,7 @@
   }
 
   content::RenderFrameHost* current_frame_host() {
-    return web_contents()->GetMainFrame();
+    return web_contents()->GetPrimaryMainFrame();
   }
 
   GURL Get2ndInstallableURL() {
diff --git a/chrome/browser/chrome_browser_main_mac.mm b/chrome/browser/chrome_browser_main_mac.mm
index 341458a..7ef669d5 100644
--- a/chrome/browser/chrome_browser_main_mac.mm
+++ b/chrome/browser/chrome_browser_main_mac.mm
@@ -37,7 +37,6 @@
 #include "components/version_info/channel.h"
 #include "content/public/common/main_function_params.h"
 #include "content/public/common/result_codes.h"
-#include "net/base/features.h"
 #include "net/cert/internal/system_trust_store.h"
 #include "services/network/public/cpp/features.h"
 #include "ui/base/cocoa/permissions_utils.h"
@@ -139,10 +138,7 @@
       MacStartupProfiler::POST_MAIN_MESSAGE_LOOP_START);
   ChromeBrowserMainPartsPosix::PostCreateMainMessageLoop();
 
-  if (base::FeatureList::IsEnabled(
-          net::features::kCertVerifierBuiltinFeature)) {
-    net::InitializeTrustStoreMacCache();
-  }
+  net::InitializeTrustStoreMacCache();
 }
 
 void ChromeBrowserMainPartsMac::PreProfileInit() {
diff --git a/chrome/browser/dips/dips_bounce_detector_browsertest.cc b/chrome/browser/dips/dips_bounce_detector_browsertest.cc
index 3eda0022..5123d0f9 100644
--- a/chrome/browser/dips/dips_bounce_detector_browsertest.cc
+++ b/chrome/browser/dips/dips_bounce_detector_browsertest.cc
@@ -202,7 +202,8 @@
 
   void CreateImageAndWaitForCookieAccess(const GURL& image_url) {
     WebContents* web_contents = GetActiveWebContents();
-    CookieAccessObserver observer(web_contents, web_contents->GetMainFrame());
+    CookieAccessObserver observer(web_contents,
+                                  web_contents->GetPrimaryMainFrame());
     ASSERT_TRUE(content::ExecJs(web_contents,
                                 content::JsReplace(
                                     R"(
@@ -445,7 +446,7 @@
 
   // Visit initial page
   ASSERT_TRUE(content::NavigateToURL(web_contents, initial_url));
-  frame = web_contents->GetMainFrame();
+  frame = web_contents->GetPrimaryMainFrame();
   // Wait for navigation to finish to initial page
   EXPECT_TRUE(content::WaitForLoadStop(web_contents));
   // Wait until we can click.
@@ -461,7 +462,7 @@
 
   // Wait for navigation to finish to interstitial page
   EXPECT_TRUE(content::WaitForLoadStop(web_contents));
-  frame = web_contents->GetMainFrame();
+  frame = web_contents->GetPrimaryMainFrame();
   // Advance TimeTicks by 1 second
   AdvanceDIPSTime(base::TimeDelta(base::Seconds(1)));
   // Write Cookie via JS on bounce page
@@ -564,7 +565,7 @@
 
   // Wait for navigation to finish to bounce page (b.test).
   EXPECT_TRUE(content::WaitForLoadStop(web_contents));
-  frame = web_contents->GetMainFrame();
+  frame = web_contents->GetPrimaryMainFrame();
   // Advance TimeTicks by 1 second.
   AdvanceDIPSTime(base::TimeDelta(base::Seconds(1)));
   // Write Cookie via JS on bounce page.
@@ -632,7 +633,7 @@
   ASSERT_TRUE(content::NavigateToURL(web_contents, initial_url));
   // Wait for navigation to finish to initial page.
   EXPECT_TRUE(content::WaitForLoadStop(web_contents));
-  frame = web_contents->GetMainFrame();
+  frame = web_contents->GetPrimaryMainFrame();
   // Wait until we can click.
   content::WaitForHitTestData(frame);
   // Advance TimeTicks 10 seconds.
@@ -646,7 +647,7 @@
 
   // Wait for navigation to finish to bounce page 1.
   EXPECT_TRUE(content::WaitForLoadStop(web_contents));
-  frame = web_contents->GetMainFrame();
+  frame = web_contents->GetPrimaryMainFrame();
   // Wait until we can click.
   content::WaitForHitTestData(frame);
   // simulate mouse click
@@ -667,7 +668,7 @@
 
   // Wait for navigation to finish to bounce page 2.
   EXPECT_TRUE(content::WaitForLoadStop(web_contents));
-  frame = web_contents->GetMainFrame();
+  frame = web_contents->GetPrimaryMainFrame();
   // Advance TimeTicks by 1 second.
   AdvanceDIPSTime(base::TimeDelta(base::Seconds(1)));
   // Write Cookie via JS on bounce page 2.
@@ -682,7 +683,7 @@
 
   // Wait for navigation to finish to bounce page 3.
   EXPECT_TRUE(content::WaitForLoadStop(web_contents));
-  frame = web_contents->GetMainFrame();
+  frame = web_contents->GetPrimaryMainFrame();
   // Advance TimeTicks by 1 second.
   AdvanceDIPSTime(base::TimeDelta(base::Seconds(1)));
   // Write Cookie via JS on bounce page 3.
@@ -810,14 +811,14 @@
 
   // Set cookies on c.test without of user engagement signal.
   ASSERT_TRUE(NavigateToURLFromRendererWithoutUserGesture(
-      web_contents->GetMainFrame(),
+      web_contents->GetPrimaryMainFrame(),
       embedded_test_server()->GetURL("c.test", "/set-cookie?name=value")));
 
   // Visit initial page.
   ASSERT_TRUE(content::NavigateToURL(web_contents, initial_url));
   // Wait for navigation to finish to initial page.
   EXPECT_TRUE(content::WaitForLoadStop(web_contents));
-  frame = web_contents->GetMainFrame();
+  frame = web_contents->GetPrimaryMainFrame();
   // Wait until we can click.
   content::WaitForHitTestData(frame);
   // Advance TimeTicks 10 seconds.
@@ -832,7 +833,7 @@
 
   // Wait for navigation to finish to bounce page 1.
   EXPECT_TRUE(content::WaitForLoadStop(web_contents));
-  frame = web_contents->GetMainFrame();
+  frame = web_contents->GetPrimaryMainFrame();
   // Wait until we can click.
   content::WaitForHitTestData(frame);
   // Advance TimeTicks by 1 second
@@ -844,7 +845,7 @@
 
   // Wait for navigation to finish to bounce page 2.
   EXPECT_TRUE(content::WaitForLoadStop(web_contents));
-  frame = web_contents->GetMainFrame();
+  frame = web_contents->GetPrimaryMainFrame();
   // Advance TimeTicks by 1 second.
   AdvanceDIPSTime(base::TimeDelta(base::Seconds(1)));
   // Write Cookie via JS on bounce page 2 (c.test).
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index a917514..b4aa473 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -5317,6 +5317,14 @@
     "expiry_milestone": 96
   },
   {
+    "name": "rounded-display",
+    "owners": [
+      "zoraiznaeem",
+      "chromeos-foundations@google.com"
+    ],
+    "expiry_milestone": 110
+  },
+  {
     "name": "run-video-capture-service-in-browser",
     "owners": [ "agpalak", "herre" ],
     "expiry_milestone": 110
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 4a6e7c9..c3dbc99 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2260,6 +2260,10 @@
     "Enables Permissions Policy and Secure Context restrictions on the Gamepad "
     "API";
 
+const char kRoundedDisplay[] = "Rounded display";
+const char kRoundedDisplayDescription[] =
+    "Enables rounded corners for the display";
+
 const char kMBIModeName[] = "MBI Scheduling Mode";
 const char kMBIModeDescription[] =
     "Enables independent agent cluster scheduling, via the "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index d77b9088..f33362c 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1270,6 +1270,9 @@
 extern const char kRestrictGamepadAccessName[];
 extern const char kRestrictGamepadAccessDescription[];
 
+extern const char kRoundedDisplay[];
+extern const char kRoundedDisplayDescription[];
+
 extern const char kMBIModeName[];
 extern const char kMBIModeDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 282db210..2f9f858 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -194,6 +194,7 @@
     &kCCTResourcePrefetch,
     &kCCTToolbarCustomizations,
     &kDontAutoHideBrowserControls,
+    &kCacheDeprecatedSystemLocationSetting,
     &kChromeNewDownloadTab,
     &kChromeShareLongScreenshot,
     &kChromeSharingHub,
@@ -531,6 +532,9 @@
 const base::Feature kDontAutoHideBrowserControls{
     "DontAutoHideBrowserControls", base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kCacheDeprecatedSystemLocationSetting{
+    "CacheDeprecatedSystemLocationSetting", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kChromeNewDownloadTab{"ChromeNewDownloadTab",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index 5fe378d..53d9d25 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -51,6 +51,7 @@
 extern const base::Feature kCCTRetainingState;
 extern const base::Feature kCCTToolbarCustomizations;
 extern const base::Feature kDontAutoHideBrowserControls;
+extern const base::Feature kCacheDeprecatedSystemLocationSetting;
 extern const base::Feature kChromeNewDownloadTab;
 extern const base::Feature kChromeShareLongScreenshot;
 extern const base::Feature kChromeShareScreenshot;
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 656431a9..06001f5 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -240,6 +240,8 @@
     public static final String BACK_GESTURE_REFACTOR = "BackGestureRefactorAndroid";
     public static final String BIOMETRIC_TOUCH_TO_FILL = "BiometricTouchToFill";
     public static final String BULK_TAB_RESTORE = "BulkTabRestore";
+    public static final String CACHE_DEPRECATED_SYSTEM_LOCATION_SETTING =
+            "CacheDeprecatedSystemLocationSetting";
     public static final String CAPTIVE_PORTAL_CERTIFICATE_LIST = "CaptivePortalCertificateList";
     public static final String CCT_BACKGROUND_TAB = "CCTBackgroundTab";
     public static final String CCT_CLIENT_DATA_HEADER = "CCTClientDataHeader";
diff --git a/chrome/browser/media/webrtc/region_capture_browsertest.cc b/chrome/browser/media/webrtc/region_capture_browsertest.cc
index 5760f2b3..70b12bfc 100644
--- a/chrome/browser/media/webrtc/region_capture_browsertest.cc
+++ b/chrome/browser/media/webrtc/region_capture_browsertest.cc
@@ -114,7 +114,7 @@
   void SetUpMailman(const GURL& url) {
     std::string script_result;
     EXPECT_TRUE(content::ExecuteScriptAndExtractString(
-        web_contents->GetMainFrame(),
+        web_contents->GetPrimaryMainFrame(),
         base::StringPrintf("setUpMailman('%s');", url.spec().c_str()),
         &script_result));
     EXPECT_EQ(script_result, "mailman-ready");
@@ -198,7 +198,7 @@
   bool CloneTrack() {
     std::string script_result = "error-not-modified";
     EXPECT_TRUE(content::ExecuteScriptAndExtractString(
-        web_contents->GetMainFrame(), "clone();", &script_result));
+        web_contents->GetPrimaryMainFrame(), "clone();", &script_result));
     DCHECK(script_result == "clone-track-success" ||
            script_result == "clone-track-failure");
     return script_result == "clone-track-success";
@@ -207,7 +207,7 @@
   bool Deallocate(Track track) {
     std::string script_result = "error-not-modified";
     EXPECT_TRUE(content::ExecuteScriptAndExtractString(
-        web_contents->GetMainFrame(),
+        web_contents->GetPrimaryMainFrame(),
         base::StringPrintf("deallocate('%s');", ToString(track)),
         &script_result));
     DCHECK(script_result == "deallocate-failure" ||
diff --git a/chrome/browser/navigation_predictor/anchor_element_preloader_browsertest.cc b/chrome/browser/navigation_predictor/anchor_element_preloader_browsertest.cc
index 74a2f8b..c2000ff 100644
--- a/chrome/browser/navigation_predictor/anchor_element_preloader_browsertest.cc
+++ b/chrome/browser/navigation_predictor/anchor_element_preloader_browsertest.cc
@@ -158,7 +158,7 @@
   ukm::SourceId ukm_source_id = browser()
                                     ->tab_strip_model()
                                     ->GetActiveWebContents()
-                                    ->GetMainFrame()
+                                    ->GetPrimaryMainFrame()
                                     ->GetPageUkmSourceId();
 
   // First link with mousedown event should get preconnected.
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
index a30846e..e32919d 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -3480,7 +3480,8 @@
   ASSERT_EQ(all_frames_value, main_frame_value);
 }
 
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)  // crbug.com/1277391
+// Test is flaky. https://crbug.com/1260953
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
 #define MAYBE_PageLCPAnimatedImage DISABLED_PageLCPAnimatedImage
 #else
 #define MAYBE_PageLCPAnimatedImage PageLCPAnimatedImage
diff --git a/chrome/browser/policy/test/renderer_app_container_enabled_win_browsertest.cc b/chrome/browser/policy/test/renderer_app_container_enabled_win_browsertest.cc
index 74ce25e..75b95bc 100644
--- a/chrome/browser/policy/test/renderer_app_container_enabled_win_browsertest.cc
+++ b/chrome/browser/policy/test/renderer_app_container_enabled_win_browsertest.cc
@@ -95,7 +95,7 @@
   base::ProcessId renderer_process_id = browser()
                                             ->tab_strip_model()
                                             ->GetActiveWebContents()
-                                            ->GetMainFrame()
+                                            ->GetPrimaryMainFrame()
                                             ->GetProcess()
                                             ->GetProcess()
                                             .Pid();
diff --git a/chrome/browser/prefetch/search_prefetch/search_prefetch_service_browsertest.cc b/chrome/browser/prefetch/search_prefetch/search_prefetch_service_browsertest.cc
index d0b89aea..af129f8 100644
--- a/chrome/browser/prefetch/search_prefetch/search_prefetch_service_browsertest.cc
+++ b/chrome/browser/prefetch/search_prefetch/search_prefetch_service_browsertest.cc
@@ -928,7 +928,7 @@
     history.replaceState(null, "", url.toString());
   )";
 
-  content::RenderFrameHost* frame = GetWebContents()->GetMainFrame();
+  content::RenderFrameHost* frame = GetWebContents()->GetPrimaryMainFrame();
   EXPECT_TRUE(content::ExecuteScript(frame, script));
 
   // The prefetch should be served, and only 1 request should be issued.
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 60d1819..1d873735 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -150,6 +150,7 @@
 #include "components/sync_device_info/device_info_prefs.h"
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "components/sync_sessions/session_sync_prefs.h"
+#include "components/tracing/common/pref_names.h"
 #include "components/translate/core/browser/translate_prefs.h"
 #include "components/update_client/update_client.h"
 #include "components/variations/service/variations_service.h"
@@ -742,6 +743,9 @@
 const char kTokenServiceDiceCompatible[] = "token_service.dice_compatible";
 #endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
 
+// Deprecated 06/2022.
+const char kBackgroundTracingLastUpload[] = "background_tracing.last_upload";
+
 // Register local state used only for migration (clearing or moving to a new
 // key).
 void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) {
@@ -795,6 +799,9 @@
   registry->RegisterBooleanPref(kNativeBridge64BitSupportExperimentEnabled,
                                 false);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+  // Deprecated 06/2022.
+  registry->RegisterInt64Pref(kBackgroundTracingLastUpload, 0);
 }
 
 // Register prefs used only for migration (clearing or moving to a new key).
@@ -980,7 +987,6 @@
   chrome_labs_prefs::RegisterLocalStatePrefs(registry);
 #endif
   ChromeMetricsServiceClient::RegisterPrefs(registry);
-  ChromeTracingDelegate::RegisterPrefs(registry);
   chrome::enterprise_util::RegisterLocalStatePrefs(registry);
   component_updater::RegisterPrefs(registry);
   embedder_support::OriginTrialPrefs::RegisterPrefs(registry);
@@ -1019,6 +1025,7 @@
   SSLConfigServiceManager::RegisterPrefs(registry);
   subresource_filter::IndexedRulesetVersion::RegisterPrefs(registry);
   SystemNetworkContextManager::RegisterPrefs(registry);
+  tracing::RegisterPrefs(registry);
   update_client::RegisterPrefs(registry);
   variations::VariationsService::RegisterPrefs(registry);
 
@@ -1646,6 +1653,9 @@
   local_state->ClearPref(kNativeBridge64BitSupportExperimentEnabled);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
+  // Added 06/2022.
+  local_state->ClearPref(kBackgroundTracingLastUpload);
+
   // Please don't delete the following line. It is used by PRESUBMIT.py.
   // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS
 
diff --git a/chrome/browser/renderer_context_menu/link_to_text_menu_observer.h b/chrome/browser/renderer_context_menu/link_to_text_menu_observer.h
index 8ab2d0b..d93bbc5 100644
--- a/chrome/browser/renderer_context_menu/link_to_text_menu_observer.h
+++ b/chrome/browser/renderer_context_menu/link_to_text_menu_observer.h
@@ -109,6 +109,7 @@
   raw_ptr<RenderViewContextMenuProxy> proxy_;
   GURL url_;
   GURL raw_url_;
+  raw_ptr<content::RenderFrameHost> render_frame_host_;
 
   std::unordered_map<content::GlobalRenderFrameHostId,
                      std::vector<std::string>,
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index e5527d1..561f3bb 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -126,7 +126,6 @@
         "inline_login:closure_compile",
         "ntp4:closure_compile",
         "omnibox:closure_compile",
-        "settings:closure_compile",
       ]
     }
     if (is_chromeos_ash) {
@@ -135,6 +134,7 @@
         "nearby_internals:closure_compile",
         "nearby_share:closure_compile",
         "nearby_share/shared:closure_compile_module",
+        "settings:closure_compile",
       ]
     }
     if (is_android) {
diff --git a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.html b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.html
index ddf1e4f..8afc8c9 100644
--- a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.html
+++ b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.html
@@ -53,6 +53,7 @@
       <network-siminfo class="flex"
           network-state="[[getNetworkState_(managedProperties_)]]"
           device-state="[[deviceState_]]"
+          global-policy="[[globalPolicy_]]"
           disabled="[[disabled_]]">
       </network-siminfo>
     </div>
diff --git a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.js b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.js
index 4c508e7..52b83caa 100644
--- a/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.js
+++ b/chrome/browser/resources/chromeos/internet_detail_dialog/internet_detail_dialog.js
@@ -96,6 +96,9 @@
       value: false,
       computed: 'computeDisabled_(deviceState_.*)'
     },
+
+    /** @private {!chromeos.networkConfig.mojom.GlobalPolicy|undefined} */
+    globalPolicy_: Object,
   },
 
   /**
@@ -152,6 +155,9 @@
     this.managedProperties_ = OncMojo.getDefaultManagedProperties(
         OncMojo.getNetworkTypeFromString(type), this.guid, name);
     this.getNetworkDetails_();
+
+    // Fetch global policies.
+    this.onPoliciesApplied(/*userhash=*/ '');
   },
 
   /** @private */
@@ -176,6 +182,16 @@
 
   /**
    * CrosNetworkConfigObserver impl
+   * @param {!string} userhash
+   */
+  onPoliciesApplied(userhash) {
+    this.networkConfig_.getGlobalPolicy().then(response => {
+      this.globalPolicy_ = response.result;
+    });
+  },
+
+  /**
+   * CrosNetworkConfigObserver impl
    * @param {!Array<OncMojo.NetworkStateProperties>} networks
    */
   onActiveNetworksChanged(networks) {
diff --git a/chrome/browser/resources/feed_internals/feed_internals.html b/chrome/browser/resources/feed_internals/feed_internals.html
index 5b84305..eee1ee2 100644
--- a/chrome/browser/resources/feed_internals/feed_internals.html
+++ b/chrome/browser/resources/feed_internals/feed_internals.html
@@ -30,9 +30,9 @@
   </p>
   <p>
     <label>
-      <input type="checkbox" id="use-feed-query-requests-for-web-feeds"
-             name="use-feed-query-requests-for-web-feeds">
-      Use legacy endpoint for Web Feed content fetches
+      <input type="checkbox" id="use-feed-query-requests"
+             name="use-feed-query-requests">
+      Use legacy endpoint for content fetches
     </label>
   </p>
   <p>
diff --git a/chrome/browser/resources/feed_internals/feed_internals.js b/chrome/browser/resources/feed_internals/feed_internals.js
index cbff9da..bb51f60b 100644
--- a/chrome/browser/resources/feed_internals/feed_internals.js
+++ b/chrome/browser/resources/feed_internals/feed_internals.js
@@ -29,8 +29,7 @@
     $('enable-webfeed-follow-intro-debug').checked =
         properties.isWebFeedFollowIntroDebugEnabled;
     $('enable-webfeed-follow-intro-debug').disabled = false;
-    $('use-feed-query-requests-for-web-feeds').checked =
-        properties.useFeedQueryRequestsForWebFeeds;
+    $('use-feed-query-requests').checked = properties.useFeedQueryRequests;
 
     switch (properties.followingFeedOrder) {
       case FeedOrder.kUnspecified:
@@ -148,11 +147,9 @@
     $('enable-webfeed-follow-intro-debug').disabled = true;
   });
 
-  $('use-feed-query-requests-for-web-feeds')
-      .addEventListener('click', function() {
-        pageHandler.setUseFeedQueryRequestsForWebFeeds(
-            $('use-feed-query-requests-for-web-feeds').checked);
-      });
+  $('use-feed-query-requests').addEventListener('click', function() {
+    pageHandler.setUseFeedQueryRequests($('use-feed-query-requests').checked);
+  });
 
   const orderRadioClickListener = function(order) {
     $('following-feed-order-grouped').disabled = true;
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index e163e3e..e60915c0 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -183,79 +183,78 @@
   output_dir = "$root_gen_dir/chrome"
 }
 
-group("closure_compile") {
-  deps = [ ":closure_compile_local" ]
-
-  if (is_chromeos_ash) {
-    deps += [ "chromeos:closure_compile_module" ]
+if (is_chromeos_ash) {
+  group("closure_compile") {
+    deps = [
+      ":closure_compile_local",
+      "chromeos:closure_compile_module",
+    ]
   }
-}
 
-js_type_check("closure_compile_local") {
-  is_polymer3 = true
-  closure_flags = settings_closure_flags
-  deps = [
-    ":extension_control_browser_proxy",
-    ":i18n_setup",
-    ":lifetime_browser_proxy",
-    ":router",
-    ":setting_id_param_util",
-    ":settings",
-  ]
-}
+  js_type_check("closure_compile_local") {
+    is_polymer3 = true
+    closure_flags = settings_closure_flags
+    deps = [
+      ":extension_control_browser_proxy",
+      ":i18n_setup",
+      ":lifetime_browser_proxy",
+      ":router",
+      ":setting_id_param_util",
+      ":settings",
+    ]
+  }
 
-js_library("settings") {
-  sources =
-      [ "$root_gen_dir/chrome/browser/resources/settings/tsc/settings.js" ]
-  deps = [
-    ":i18n_setup",
-    ":lifetime_browser_proxy",
-  ]
-  extra_deps = [ ":build_ts" ]
-}
+  js_library("settings") {
+    sources =
+        [ "$root_gen_dir/chrome/browser/resources/settings/tsc/settings.js" ]
+    deps = [
+      ":i18n_setup",
+      ":lifetime_browser_proxy",
+    ]
+    extra_deps = [ ":build_ts" ]
+  }
 
-js_library("extension_control_browser_proxy") {
-  sources = [ "$root_gen_dir/chrome/browser/resources/settings/tsc/extension_control_browser_proxy.js" ]
-  deps = [ "//ui/webui/resources/js:cr.m" ]
-  externs_list = [ "$externs_path/chrome_send.js" ]
-  extra_deps = [ ":build_ts" ]
-}
+  js_library("extension_control_browser_proxy") {
+    sources = [ "$root_gen_dir/chrome/browser/resources/settings/tsc/extension_control_browser_proxy.js" ]
+    deps = [ "//ui/webui/resources/js:cr.m" ]
+    externs_list = [ "$externs_path/chrome_send.js" ]
+    extra_deps = [ ":build_ts" ]
+  }
 
-js_library("i18n_setup") {
-  sources =
-      [ "$root_gen_dir/chrome/browser/resources/settings/tsc/i18n_setup.js" ]
-  deps = [ "//ui/webui/resources/js:load_time_data.m" ]
-  extra_deps = [ ":build_ts" ]
-}
+  js_library("i18n_setup") {
+    sources =
+        [ "$root_gen_dir/chrome/browser/resources/settings/tsc/i18n_setup.js" ]
+    deps = [ "//ui/webui/resources/js:load_time_data.m" ]
+    extra_deps = [ ":build_ts" ]
+  }
 
-js_library("lifetime_browser_proxy") {
-  sources = [ "$root_gen_dir/chrome/browser/resources/settings/tsc/lifetime_browser_proxy.js" ]
-  deps = [ "//ui/webui/resources/js:cr.m" ]
-  extra_deps = [ ":build_ts" ]
-}
+  js_library("lifetime_browser_proxy") {
+    sources = [ "$root_gen_dir/chrome/browser/resources/settings/tsc/lifetime_browser_proxy.js" ]
+    deps = [ "//ui/webui/resources/js:cr.m" ]
+    extra_deps = [ ":build_ts" ]
+  }
 
-js_library("open_window_proxy") {
-  sources = [
-    "$root_gen_dir/chrome/browser/resources/settings/tsc/open_window_proxy.js",
-  ]
-  extra_deps = [ ":build_ts" ]
-}
+  js_library("open_window_proxy") {
+    sources = [ "$root_gen_dir/chrome/browser/resources/settings/tsc/open_window_proxy.js" ]
+    extra_deps = [ ":build_ts" ]
+  }
 
-js_library("router") {
-  deps = [
-    "//ui/webui/resources/js:assert.m",
-    "//ui/webui/resources/js:load_time_data.m",
-  ]
-  externs_list = [ "$externs_path/metrics_private.js" ]
-}
+  js_library("router") {
+    deps = [
+      "//ui/webui/resources/js:assert.m",
+      "//ui/webui/resources/js:load_time_data.m",
+    ]
+    externs_list = [ "$externs_path/metrics_private.js" ]
+  }
 
-js_library("setting_id_param_util") {
-  sources = [ "$root_gen_dir/chrome/browser/resources/settings/tsc/setting_id_param_util.js" ]
-  deps = [
-    ":router",
-    "//ui/webui/resources/js:load_time_data.m",
-  ]
-  extra_deps = [ ":build_ts" ]
+  js_library("setting_id_param_util") {
+    sources = [ "$root_gen_dir/chrome/browser/resources/settings/tsc/setting_id_param_util.js" ]
+    deps = [
+      ":router",
+      "//ui/webui/resources/js:load_time_data.m",
+    ]
+    extra_deps = [ ":build_ts" ]
+  }
 }
 
 html_to_js("css_wrapper_files_old") {
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.html b/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.html
index 8f97314..3863f08 100644
--- a/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.html
+++ b/chrome/browser/resources/settings/chromeos/internet_page/internet_detail_page.html
@@ -297,6 +297,7 @@
             <network-siminfo id="cellularSimInfoAdvanced"
                 network-state="[[getNetworkState_(managedProperties_)]]"
                 device-state="[[deviceState_]]"
+                global-policy="[[globalPolicy]]"
                 disabled="[[disabled_]]">
             </network-siminfo>
           </div>
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/network_summary.html b/chrome/browser/resources/settings/chromeos/internet_page/network_summary.html
index acee8c4..afed1f6 100644
--- a/chrome/browser/resources/settings/chromeos/internet_page/network_summary.html
+++ b/chrome/browser/resources/settings/chromeos/internet_page/network_summary.html
@@ -8,6 +8,7 @@
     <network-summary-item id="[[getTypeString_(item)]]"
         active-network-state="[[item]]"
         device-state="[[get(item.type, deviceStates)]]"
+        global-policy="[[globalPolicy_]]"
         network-state-list="[[get(item.type, networkStateLists_)]]"
         tether-device-state="[[getTetherDeviceState_(deviceStates)]]">
     </network-summary-item>
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/network_summary.js b/chrome/browser/resources/settings/chromeos/internet_page/network_summary.js
index 963f5ae..4173664a 100644
--- a/chrome/browser/resources/settings/chromeos/internet_page/network_summary.js
+++ b/chrome/browser/resources/settings/chromeos/internet_page/network_summary.js
@@ -90,6 +90,9 @@
           return result;
         },
       },
+
+      /** @private {!chromeos.networkConfig.mojom.GlobalPolicy|undefined} */
+      globalPolicy_: Object,
     };
   }
 
@@ -113,6 +116,18 @@
     super.connectedCallback();
 
     this.getNetworkLists_();
+
+    // Fetch global policies.
+    this.onPoliciesApplied(/*userhash=*/ '');
+  }
+  /**
+   * CrosNetworkConfigObserver impl
+   * @param {!string} userhash
+   */
+  onPoliciesApplied(userhash) {
+    this.networkConfig_.getGlobalPolicy().then(response => {
+      this.globalPolicy_ = response.result;
+    });
   }
 
   /**
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.html b/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.html
index 461dc50..9988342 100644
--- a/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.html
+++ b/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.html
@@ -56,6 +56,7 @@
       <network-siminfo
           on-click="doNothing_"
           network-state="[[activeNetworkState]]"
+          global-policy="[[globalPolicy]]""
           device-state="[[deviceState]]">
       </network-siminfo>
     </template>
diff --git a/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.js b/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.js
index 80128d7..5c95d97 100644
--- a/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.js
+++ b/chrome/browser/resources/settings/chromeos/internet_page/network_summary_item.js
@@ -99,6 +99,9 @@
               loadTimeData.getBoolean('showTechnologyBadge');
         }
       },
+
+      /** @private {!chromeos.networkConfig.mojom.GlobalPolicy|undefined} */
+      globalPolicy: Object,
     };
   }
 
diff --git a/chrome/browser/resources/settings/chromeos/settings_scheduler_slider/settings_scheduler_slider.js b/chrome/browser/resources/settings/chromeos/settings_scheduler_slider/settings_scheduler_slider.js
index ad380c9..8cbdad5 100644
--- a/chrome/browser/resources/settings/chromeos/settings_scheduler_slider/settings_scheduler_slider.js
+++ b/chrome/browser/resources/settings/chromeos/settings_scheduler_slider/settings_scheduler_slider.js
@@ -10,12 +10,34 @@
 
 import '../../settings_shared_css.js';
 
-import {I18nBehavior} from '//resources/js/i18n_behavior.m.js';
-import {IronResizableBehavior} from '//resources/polymer/v3_0/iron-resizable-behavior/iron-resizable-behavior.js';
-import {PaperRippleBehavior} from '//resources/polymer/v3_0/paper-behaviors/paper-ripple-behavior.js';
-import {html, Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js';
+import {IronResizableBehavior} from 'chrome://resources/polymer/v3_0/iron-resizable-behavior/iron-resizable-behavior.js';
+import {PaperRippleBehavior} from 'chrome://resources/polymer/v3_0/paper-behaviors/paper-ripple-behavior.js';
+import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {PrefsBehavior} from '../prefs_behavior.js';
+import {PrefsBehavior, PrefsBehaviorInterface} from '../prefs_behavior.js';
+
+/** @interface */
+class PaperRippleBehaviorInterface {
+  constructor() {
+    /**
+     * @type {?Object}
+     * @protected
+     */
+    this._ripple;
+
+    /**
+     * @type {?Element}
+     * @protected
+     */
+    this._rippleContainer;
+  }
+
+  /** @return {boolean} */
+  hasRipple() {}
+
+  ensureRipple() {}
+}
 
 const HOURS_PER_DAY = 24;
 const MIN_KNOBS_DISTANCE_MINUTES = 60;
@@ -45,95 +67,120 @@
   return ((x % y) + y) % y;
 }
 
-Polymer({
+/**
+ * @constructor
+ * @extends {PolymerElement}
+ * @implements {I18nBehaviorInterface}
+ * @implements {PrefsBehaviorInterface}
+ * @implements {PaperRippleBehaviorInterface}
+ */
+const SettingsSchedulerSliderElementBase = mixinBehaviors(
+    [I18nBehavior, PrefsBehavior, IronResizableBehavior, PaperRippleBehavior],
+    PolymerElement);
 
-  _template: html`{__html_template__}`,
+/** @polymer */
+class SettingsSchedulerSliderElement extends
+    SettingsSchedulerSliderElementBase {
+  static get is() {
+    return 'settings-scheduler-slider';
+  }
 
-  is: 'settings-scheduler-slider',
+  static get template() {
+    return html`{__html_template__}`;
+  }
 
-  behaviors: [
-    I18nBehavior,
-    PrefsBehavior,
-    IronResizableBehavior,
-    PaperRippleBehavior,
-  ],
-
-  properties: {
-
-    /**
-     * The start time pref object being tracked.
-     * @type {!chrome.settingsPrivate.PrefObject}
-     */
-    prefStartTime: {
-      type: Object,
-      notify: true,
-      value() {
-        return {
-          key: 'ash.fake_feature.custom_start_time',
-          type: chrome.settingsPrivate.PrefType.NUMBER,
-          value: DEFAULT_CUSTOM_START_TIME,
-        };
+  static get properties() {
+    return {
+      /**
+       * The start time pref object being tracked.
+       * @type {!chrome.settingsPrivate.PrefObject}
+       */
+      prefStartTime: {
+        type: Object,
+        notify: true,
+        value() {
+          return {
+            key: 'ash.fake_feature.custom_start_time',
+            type: chrome.settingsPrivate.PrefType.NUMBER,
+            value: DEFAULT_CUSTOM_START_TIME,
+          };
+        },
       },
-    },
 
-    /**
-     * The end time pref object being tracked.
-     * @type {!chrome.settingsPrivate.PrefObject}
-     */
-    prefEndTime: {
-      type: Object,
-      notify: true,
-      value() {
-        return {
-          key: 'ash.fake_feature.custom_start_time',
-          type: chrome.settingsPrivate.PrefType.NUMBER,
-          value: DEFAULT_CUSTOM_END_TIME,
-        };
+      /**
+       * The end time pref object being tracked.
+       * @type {!chrome.settingsPrivate.PrefObject}
+       */
+      prefEndTime: {
+        type: Object,
+        notify: true,
+        value() {
+          return {
+            key: 'ash.fake_feature.custom_start_time',
+            type: chrome.settingsPrivate.PrefType.NUMBER,
+            value: DEFAULT_CUSTOM_END_TIME,
+          };
+        },
       },
-    },
+
+      /**
+       * Whether the element is ready and fully rendered.
+       * @private
+       */
+      isReady_: Boolean,
+
+      /**
+       * Whether the window is in RTL locales.
+       * @private
+       */
+      isRTL_: Boolean,
+
+      /**
+       * Whether to use the 24-hour format for the time shown in the label
+       * bubbles.
+       * @private
+       */
+      shouldUse24Hours_: Boolean,
+    };
+  }
+
+  static get observers() {
+    return [
+      'updateKnobs_(prefs.*, isRTL_, isReady_)',
+      'hourFormatChanged_(prefs.settings.clock.use_24hour_clock.*)',
+      'updateMarkers_(prefs.*, isRTL_, isReady_)',
+    ];
+  }
+
+  constructor() {
+    super();
 
     /**
-     * Whether the element is ready and fully rendered.
+     * The object currently being dragged. Either the start or end knobs.
+     * @type {Element}
      * @private
      */
-    isReady_: Boolean,
+    this.dragObject_ = null;
 
     /**
-     * Whether the window is in RTL locales.
-     * @private
+     * @private {number}
      */
-    isRTL_: Boolean,
+    this.valueAtDragStart_;
+  }
 
-    /**
-     * Whether to use the 24-hour format for the time shown in the label
-     * bubbles.
-     * @private
-     */
-    shouldUse24Hours_: Boolean,
-  },
+  ready() {
+    super.ready();
 
-  listeners: {
-    'iron-resize': 'onResize_',
-    focus: 'onFocus_',
-    blur: 'onBlur_',
-    keydown: 'onKeyDown_',
-  },
-
-  observers: [
-    'updateKnobs_(prefs.*, isRTL_, isReady_)',
-    'hourFormatChanged_(prefs.settings.clock.use_24hour_clock.*)',
-    'updateMarkers_(prefs.*, isRTL_, isReady_)',
-  ],
-
-  /**
-   * The object currently being dragged. Either the start or end knobs.
-   * @type {Element}
-   * @private
-   */
-  dragObject_: null,
+    this.addEventListener('iron-resize', this.onResize_);
+    this.addEventListener('focus', this.onFocus_);
+    this.addEventListener('blur', this.onBlur_);
+    this.addEventListener('keydown', this.onKeyDown_);
+  }
 
   /** @override */
-  attached() {
+  connectedCallback() {
+    super.connectedCallback();
+
     this.isRTL_ = window.getComputedStyle(this).direction === 'rtl';
     this.$.sliderContainer.addEventListener('contextmenu', function(e) {
       // Prevent the context menu from interfering with dragging the knobs using
@@ -149,7 +196,7 @@
       // rendered.
       this.isReady_ = true;
     });
-  },
+  }
 
   /**
    * @return {boolean}
@@ -158,7 +205,7 @@
   prefsAvailable() {
     return [this.prefStartTime, this.prefEndTime].every(
         pref => pref !== undefined);
-  },
+  }
 
   /** @private */
   updateMarkers_() {
@@ -189,7 +236,7 @@
       markersContainer.appendChild(marker);
       marker.style.left = (i * 100 / HOURS_PER_DAY) + '%';
     }
-  },
+  }
 
   /**
    * Return true if the start knob is focused.
@@ -198,7 +245,7 @@
    */
   isStartKnobFocused_() {
     return (this.shadowRoot.activeElement === this.$.startKnob);
-  },
+  }
 
   /**
    * Return true if the end knob is focused.
@@ -207,7 +254,7 @@
    */
   isEndKnobFocused_() {
     return (this.shadowRoot.activeElement === this.$.endKnob);
-  },
+  }
 
   /**
    * Invoked when the element is resized and the knobs positions need to be
@@ -216,7 +263,7 @@
    */
   onResize_() {
     this.updateKnobs_();
-  },
+  }
 
   /**
    * Called when the value of the pref associated with whether to use the
@@ -226,7 +273,7 @@
   hourFormatChanged_() {
     this.shouldUse24Hours_ = /** @type {boolean} */ (
         this.getPref('settings.clock.use_24hour_clock').value);
-  },
+  }
 
   /**
    * Gets the style of legend div determining its absolute left position.
@@ -238,7 +285,7 @@
   getLegendStyle_(percent, isRTL) {
     percent = isRTL ? 100 - percent : percent;
     return 'left: ' + percent + '%';
-  },
+  }
 
   /**
    * Gets the aria label for the start time knob.
@@ -251,7 +298,7 @@
         this.getTimeString_(
             /** @type {number} */ (this.prefStartTime.value),
             this.shouldUse24Hours_));
-  },
+  }
 
   /**
    * Gets the aria label for the end time knob.
@@ -264,7 +311,7 @@
         this.getTimeString_(
             /** @type {number} */ (this.prefEndTime.value),
             this.shouldUse24Hours_));
-  },
+  }
 
 
   /**
@@ -275,7 +322,7 @@
     if (this.isEitherKnobFocused_()) {
       this.shadowRoot.activeElement.blur();
     }
-  },
+  }
 
   /**
    * Start dragging the target knob.
@@ -290,18 +337,18 @@
     if (event.target === this.$.startKnob ||
         event.target === this.$.startKnob.firstElementChild) {
       this.dragObject_ = this.$.startKnob;
-      this.valueAtDragStart_ = this.prefStartTime.value;
+      this.valueAtDragStart_ = /** @type {number} */ (this.prefStartTime.value);
     } else if (
         event.target === this.$.endKnob ||
         event.target === this.$.endKnob.firstElementChild) {
       this.dragObject_ = this.$.endKnob;
-      this.valueAtDragStart_ = this.prefEndTime.value;
+      this.valueAtDragStart_ = /** @type {number} */ (this.prefEndTime.value);
     } else {
       return;
     }
 
     this.handleKnobEvent_(event, this.dragObject_);
-  },
+  }
 
   /**
    * Continues dragging the selected knob if any.
@@ -325,7 +372,7 @@
         this.endDrag_(event);
         break;
     }
-  },
+  }
 
   /**
    * Converts horizontal pixels into number of minutes.
@@ -337,7 +384,7 @@
     return (this.isRTL_ ? -1 : 1) *
         Math.floor(
             TOTAL_MINUTES_PER_DAY * deltaX / this.$.sliderBar.offsetWidth);
-  },
+  }
 
   /**
    * Updates the knob's corresponding pref value in response to dragging, which
@@ -359,7 +406,7 @@
     // pixel movement due to rounding.
     this.updatePref_(
         this.valueAtDragStart_ + this.getDeltaMinutes_(event.detail.dx), true);
-  },
+  }
 
   /**
    * Ends the dragging.
@@ -370,7 +417,7 @@
     event.preventDefault();
     this.dragObject_ = null;
     this.removeRipple_();
-  },
+  }
 
   /**
    * Gets the given knob's offset ratio with respect to its parent element
@@ -381,7 +428,7 @@
    */
   getKnobRatio_(knob) {
     return parseFloat(knob.style.left) / this.$.sliderBar.offsetWidth;
-  },
+  }
 
   /**
    * Converts the time of day, given as |hour| and |minutes|, to its language-
@@ -402,7 +449,7 @@
     return d.toLocaleTimeString(
         navigator.language,
         {hour: 'numeric', minute: 'numeric', hour12: !shouldUse24Hours});
-  },
+  }
 
   /**
    * Converts the |offsetMinutes| value (which the number of minutes since
@@ -417,7 +464,7 @@
     const hour = Math.floor(offsetMinutes / 60);
     const minute = Math.floor(offsetMinutes % 60);
     return this.getLocaleTimeString_(hour, minute, shouldUse24Hours);
-  },
+  }
 
   /**
    * Using the current start and end times prefs, this function updates the
@@ -441,7 +488,7 @@
     this.updateKnobLeft_(this.$.endKnob, endOffsetMinutes);
 
     this.refresh_();
-  },
+  }
 
   /**
    * Updates the absolute left coordinate of the given |knob| based on the time
@@ -468,7 +515,7 @@
       ratio = this.isRTL_ ? (1.0 - ratio) : ratio;
     }
     knob.style.left = (ratio * this.$.sliderBar.offsetWidth) + 'px';
-  },
+  }
 
   /**
    * Refreshes elements of the slider other than the knobs (the label bubbles,
@@ -509,7 +556,7 @@
         'px';
 
     this.fixLabelsOverlapIfAny_();
-  },
+  }
 
   /**
    * If the label bubbles overlap, this function fixes them by moving the end
@@ -529,7 +576,7 @@
     } else {
       endLabel.classList.remove('end-label-overlap');
     }
-  },
+  }
 
   /**
    * Return the value of the pref that corresponds to the other knob than
@@ -542,7 +589,7 @@
       return /** @type {number} */ (this.prefEndTime.value);
     }
     return /** @type {number} */ (this.prefStartTime.value);
-  },
+  }
 
   /**
    * Updates the value of the pref and wraps around if necessary.
@@ -591,7 +638,7 @@
       this.set(
           'prefEndTime.value', modulo(updatedValue, TOTAL_MINUTES_PER_DAY));
     }
-  },
+  }
 
   /**
    * @param {Element} knob
@@ -606,7 +653,7 @@
     } else {
       return null;
     }
-  },
+  }
 
   /**
    * @return {boolean} Whether either of the two knobs is focused.
@@ -614,7 +661,7 @@
    */
   isEitherKnobFocused_() {
     return this.isStartKnobFocused_() || this.isEndKnobFocused_();
-  },
+  }
 
   /**
    * Overrides _createRipple() from PaperRippleBehavior to create the ripple
@@ -637,7 +684,7 @@
     ripple.setAttribute('recenters', '');
     ripple.classList.add('circle', 'toggle-ink');
     return ripple;
-  },
+  }
 
   /**
    * @param {!Event} event
@@ -645,7 +692,7 @@
    */
   onFocus_(event) {
     this.handleKnobEvent_(event);
-  },
+  }
 
   /**
    * Handles focus, drag and key events on the start and end knobs.
@@ -675,7 +722,7 @@
       this._ripple.style.display = '';
       this._ripple.holdDown = true;
     }
-  },
+  }
 
   /**
    * Handles blur events on the start and end knobs.
@@ -683,7 +730,7 @@
    */
   onBlur_() {
     this.removeRipple_();
-  },
+  }
 
   /**
    * Removes ripple if one exists.
@@ -694,7 +741,7 @@
       this._ripple.remove();
       this._ripple = null;
     }
-  },
+  }
 
   /**
    * @param {!Event} event
@@ -741,5 +788,8 @@
       const delta = deltaKeyMap[event.key];
       this.updatePref_(value + delta, false);
     }
-  },
-});
+  }
+}
+
+customElements.define(
+    SettingsSchedulerSliderElement.is, SettingsSchedulerSliderElement);
diff --git a/chrome/browser/resources/settings/people_page/sync_page.ts b/chrome/browser/resources/settings/people_page/sync_page.ts
index ae720dfd..e20ad76 100644
--- a/chrome/browser/resources/settings/people_page/sync_page.ts
+++ b/chrome/browser/resources/settings/people_page/sync_page.ts
@@ -55,6 +55,7 @@
   SYNC: Route,
   SYNC_ADVANCED: Route,
   OS_SYNC: Route,
+  OS_PEOPLE: Route,
 };
 
 function getSyncRoutes(): SyncRoutes {
@@ -372,6 +373,17 @@
     return getSyncRoutes().SYNC_ADVANCED;
   }
 
+  private getPeoplePageRoute_(): Route {
+    // <if expr="chromeos_ash">
+    if (loadTimeData.getBoolean('isOSSettings')) {
+      // In OS settings on ChromeOS a different page is used as a people page.
+      return getSyncRoutes().OS_PEOPLE;
+    }
+    // </if>
+
+    return getSyncRoutes().PEOPLE;
+  }
+
   private onFocusConfigChange_() {
     this.focusConfig.set(this.getSyncAdvancedPageRoute_().path, () => {
       const toFocus = this.shadowRoot!.querySelector('#sync-advanced-row');
@@ -637,7 +649,7 @@
         return;
       case PageStatus.DONE:
         if (router.getCurrentRoute() === getSyncRoutes().SYNC) {
-          router.navigateTo(getSyncRoutes().PEOPLE);
+          router.navigateTo(this.getPeoplePageRoute_());
         }
         return;
       case PageStatus.PASSPHRASE_FAILED:
diff --git a/chrome/browser/safe_browsing/client_side_detection_service_browsertest.cc b/chrome/browser/safe_browsing/client_side_detection_service_browsertest.cc
index 30d1ab5..30f98554 100644
--- a/chrome/browser/safe_browsing/client_side_detection_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_service_browsertest.cc
@@ -98,7 +98,7 @@
   GURL url(embedded_test_server()->GetURL("/empty.html"));
   ASSERT_TRUE(content::NavigateToURL(web_contents(), url));
 
-  content::RenderFrameHost* rfh = web_contents()->GetMainFrame();
+  content::RenderFrameHost* rfh = web_contents()->GetPrimaryMainFrame();
   content::RenderProcessHost* rph = rfh->GetProcess();
 
   // Update the model and wait for confirmation
@@ -159,7 +159,7 @@
   GURL url(embedded_test_server()->GetURL("/empty.html"));
   ASSERT_TRUE(content::NavigateToURL(web_contents(), url));
 
-  content::RenderFrameHost* rfh = web_contents()->GetMainFrame();
+  content::RenderFrameHost* rfh = web_contents()->GetPrimaryMainFrame();
   content::RenderProcessHost* rph = rfh->GetProcess();
 
   // Update the model and wait for confirmation
diff --git a/chrome/browser/share/BUILD.gn b/chrome/browser/share/BUILD.gn
index a9bd452..38d8d04 100644
--- a/chrome/browser/share/BUILD.gn
+++ b/chrome/browser/share/BUILD.gn
@@ -22,6 +22,7 @@
 
   deps = [
     "//base",
+    "//chrome/browser/favicon",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/share/proto:proto",
     "//chrome/services/qrcode_generator/public/cpp",
diff --git a/chrome/browser/share/share_attempt.cc b/chrome/browser/share/share_attempt.cc
index 5c26d81..8abd1dc3 100644
--- a/chrome/browser/share/share_attempt.cc
+++ b/chrome/browser/share/share_attempt.cc
@@ -4,16 +4,25 @@
 
 #include "chrome/browser/share/share_attempt.h"
 
+#include "chrome/browser/favicon/favicon_utils.h"
 #include "content/public/browser/web_contents.h"
+#include "ui/base/models/image_model.h"
 
 namespace share {
 
 ShareAttempt::ShareAttempt(content::WebContents* contents)
-    : ShareAttempt(contents, contents->GetTitle(), contents->GetVisibleURL()) {}
+    : ShareAttempt(contents,
+                   contents->GetTitle(),
+                   contents->GetVisibleURL(),
+                   ui::ImageModel::FromImage(favicon::GetDefaultFavicon())) {}
 ShareAttempt::ShareAttempt(content::WebContents* contents,
                            std::u16string title,
-                           GURL url)
-    : web_contents(contents->GetWeakPtr()), title(title), url(url) {}
+                           GURL url,
+                           ui::ImageModel preview_image)
+    : web_contents(contents->GetWeakPtr()),
+      title(title),
+      url(url),
+      preview_image(preview_image) {}
 
 ShareAttempt::~ShareAttempt() = default;
 
diff --git a/chrome/browser/share/share_attempt.h b/chrome/browser/share/share_attempt.h
index bf9bb1ca..6110016 100644
--- a/chrome/browser/share/share_attempt.h
+++ b/chrome/browser/share/share_attempt.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_SHARE_SHARE_ATTEMPT_H_
 
 #include "base/memory/weak_ptr.h"
+#include "ui/base/models/image_model.h"
 #include "url/gurl.h"
 
 namespace content {
@@ -18,7 +19,10 @@
 // content - a whole page, a link, an image, or perhaps (later on) other types.
 struct ShareAttempt {
   explicit ShareAttempt(content::WebContents* contents);
-  ShareAttempt(content::WebContents* contents, std::u16string title, GURL url);
+  ShareAttempt(content::WebContents* contents,
+               std::u16string title,
+               GURL url,
+               ui::ImageModel preview_image);
   ~ShareAttempt();
 
   ShareAttempt(const ShareAttempt&);
@@ -27,6 +31,11 @@
   base::WeakPtr<content::WebContents> web_contents;
   const std::u16string title;
   const GURL url;
+
+  // The initial preview image to use for the share - note that this may get
+  // replaced if a better preview image becomes available. See
+  // SharingHubBubbleController::RegisterPreviewImageChangedCallback().
+  ui::ImageModel preview_image;
 };
 
 }  // namespace share
diff --git a/chrome/browser/spellchecker/spellcheck_mac_view_interactive_uitest.mm b/chrome/browser/spellchecker/spellcheck_mac_view_interactive_uitest.mm
index 093f20e..dd37cfa 100644
--- a/chrome/browser/spellchecker/spellcheck_mac_view_interactive_uitest.mm
+++ b/chrome/browser/spellchecker/spellcheck_mac_view_interactive_uitest.mm
@@ -40,7 +40,7 @@
   test_helper.RunUntilBind();
   spellcheck::SpellCheckMockPanelHost* host =
       test_helper.GetSpellCheckMockPanelHostForProcess(
-          web_contents->GetMainFrame()->GetProcess());
+          web_contents->GetPrimaryMainFrame()->GetProcess());
   EXPECT_TRUE(host->SpellingPanelVisible());
 }
 #endif
diff --git a/chrome/browser/tracing/chrome_tracing_delegate.cc b/chrome/browser/tracing/chrome_tracing_delegate.cc
index 271d647c..4ba6f3d 100644
--- a/chrome/browser/tracing/chrome_tracing_delegate.cc
+++ b/chrome/browser/tracing/chrome_tracing_delegate.cc
@@ -28,11 +28,9 @@
 #include "chrome/browser/ui/browser_otr_state.h"
 #include "chrome/common/pref_names.h"
 #include "components/metrics/metrics_pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/tracing/common/background_tracing_state_manager.h"
 #include "components/tracing/common/background_tracing_utils.h"
-#include "components/tracing/common/pref_names.h"
 #include "components/variations/active_field_trials.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/background_tracing_config.h"
@@ -108,13 +106,6 @@
 
 }  // namespace
 
-void ChromeTracingDelegate::RegisterPrefs(PrefRegistrySimple* registry) {
-  // TODO(ssid): This is no longer used, remove the pref once the new one is
-  // stable.
-  registry->RegisterInt64Pref(prefs::kBackgroundTracingLastUpload, 0);
-  tracing::RegisterPrefs(registry);
-}
-
 ChromeTracingDelegate::ChromeTracingDelegate() {
   // Ensure that this code is called on the UI thread, except for
   // tests where a UI thread might not have been initialized at this point.
diff --git a/chrome/browser/tracing/chrome_tracing_delegate.h b/chrome/browser/tracing/chrome_tracing_delegate.h
index 2db2911..2b9730bd 100644
--- a/chrome/browser/tracing/chrome_tracing_delegate.h
+++ b/chrome/browser/tracing/chrome_tracing_delegate.h
@@ -18,8 +18,6 @@
 #include "chrome/browser/ui/browser_list_observer.h"
 #endif
 
-class PrefRegistrySimple;
-
 namespace base {
 class Value;
 }
@@ -35,8 +33,6 @@
   ChromeTracingDelegate();
   ~ChromeTracingDelegate() override;
 
-  static void RegisterPrefs(PrefRegistrySimple* registry);
-
   // Returns if the tracing session is allowed to begin. Also updates the
   // background tracing state in prefs using BackgroundTracingStateManager. So,
   // this is required to be called exactly once per background tracing session
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 0cf9e837..48e4deb 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -4764,8 +4764,6 @@
       "views/sharing_hub/sharing_hub_bubble_action_button.h",
       "views/sharing_hub/sharing_hub_bubble_util.cc",
       "views/sharing_hub/sharing_hub_bubble_util.h",
-      "views/sharing_hub/sharing_hub_bubble_view_impl.cc",
-      "views/sharing_hub/sharing_hub_bubble_view_impl.h",
       "views/sharing_hub/sharing_hub_icon_view.cc",
       "views/sharing_hub/sharing_hub_icon_view.h",
       "views/shopping_bubble/shopping_prompt_impl.cc",
@@ -5229,6 +5227,8 @@
         "views/frame/opaque_browser_frame_view_layout.h",
         "views/frame/opaque_browser_frame_view_layout_delegate.cc",
         "views/frame/opaque_browser_frame_view_layout_delegate.h",
+        "views/sharing_hub/sharing_hub_bubble_view_impl.cc",
+        "views/sharing_hub/sharing_hub_bubble_view_impl.h",
       ]
       deps += [ "//ui/views/window/vector_icons" ]
     }
diff --git a/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuTest.java b/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuTest.java
index 9699adf..13f85d0 100644
--- a/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuTest.java
+++ b/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuTest.java
@@ -6,7 +6,6 @@
 
 import static org.mockito.ArgumentMatchers.eq;
 
-import android.app.Activity;
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.view.KeyEvent;
@@ -20,18 +19,14 @@
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 
-import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.BeforeClass;
-import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 
-import org.chromium.base.test.BaseActivityTestRule;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
@@ -47,6 +42,7 @@
 import org.chromium.components.browser_ui.widget.highlight.ViewHighlighterTestUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.ui.test.util.BlankUiTestActivity;
+import org.chromium.ui.test.util.BlankUiTestActivityTestCase;
 import org.chromium.ui.test.util.UiDisableIf;
 
 import java.util.ArrayList;
@@ -60,13 +56,8 @@
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-@Batch(Batch.UNIT_TESTS)
-public class AppMenuTest {
-    @ClassRule
-    public static BaseActivityTestRule<BlankUiTestActivity> sActivityTestRule =
-            new BaseActivityTestRule<>(BlankUiTestActivity.class);
-
-    private Activity mActivity;
+@Batch(Batch.PER_CLASS)
+public class AppMenuTest extends BlankUiTestActivityTestCase {
     private AppMenuCoordinatorImpl mAppMenuCoordinator;
     private AppMenuHandlerImpl mAppMenuHandler;
     private TestAppMenuPropertiesDelegate mPropertiesDelegate;
@@ -84,38 +75,28 @@
     @BeforeClass
     public static void setUpBeforeActivityLaunched() {
         BlankUiTestActivity.setTestLayout(R.layout.test_app_menu_activity_layout);
-        sActivityTestRule.launchActivity(null);
     }
 
-    @Before
+    @Override
     public void setUpTest() throws Exception {
+        super.setUpTest();
         mCanvas = Mockito.mock(Canvas.class);
         TestThreadUtils.runOnUiThreadBlocking(this::setUpTestOnUiThread);
         mLifecycleDispatcher.observerRegisteredCallbackHelper.waitForCallback(0);
     }
 
-    @After
-    public void teardownTest() {
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mAppMenuHandler.hideAppMenu();
-            mTestMenuButtonDelegate.getMenuButtonView().setPressed(false);
-            mAppMenuCoordinator.destroy();
-        });
-    }
-
     @AfterClass
     public static void tearDownAfterActivityDestroyed() {
         AppMenuCoordinatorImpl.setHasPermanentMenuKeyForTesting(null);
     }
 
     private void setUpTestOnUiThread() {
-        mActivity = sActivityTestRule.getActivity();
         mLifecycleDispatcher = new TestActivityLifecycleDispatcher();
         mDelegate = new TestAppMenuDelegate();
         mTestMenuButtonDelegate = new TestMenuButtonDelegate();
-        mAppMenuCoordinator = new AppMenuCoordinatorImpl(mActivity, mLifecycleDispatcher,
-                mTestMenuButtonDelegate, mDelegate, mActivity.getWindow().getDecorView(),
-                mActivity.findViewById(R.id.menu_anchor_stub));
+        mAppMenuCoordinator = new AppMenuCoordinatorImpl(getActivity(), mLifecycleDispatcher,
+                mTestMenuButtonDelegate, mDelegate, getActivity().getWindow().getDecorView(),
+                getActivity().findViewById(R.id.menu_anchor_stub));
         mAppMenuHandler = mAppMenuCoordinator.getAppMenuHandlerImplForTesting();
         mMenuObserver = new TestAppMenuObserver();
         mAppMenuCoordinator.getAppMenuHandler().addObserver(mMenuObserver);
@@ -161,7 +142,7 @@
         AppMenuCoordinatorImpl.setHasPermanentMenuKeyForTesting(false);
         showMenuAndAssert();
 
-        View topAnchor = mActivity.findViewById(R.id.top_button);
+        View topAnchor = getActivity().findViewById(R.id.top_button);
         Rect viewRect = getViewLocationRect(topAnchor);
         Rect popupRect = getPopupLocationRect();
 
@@ -186,7 +167,7 @@
         AppMenuCoordinatorImpl.setHasPermanentMenuKeyForTesting(true);
         showMenuAndAssert();
 
-        View anchorStub = mActivity.findViewById(R.id.menu_anchor_stub);
+        View anchorStub = getActivity().findViewById(R.id.menu_anchor_stub);
         Rect viewRect = getViewLocationRect(anchorStub);
         Rect popupRect = getPopupLocationRect();
 
@@ -255,7 +236,7 @@
         showMenuAndAssert();
         AppMenu spiedMenu = Mockito.spy(mAppMenuHandler.getAppMenu());
 
-        View dummyView = new View(mActivity);
+        View dummyView = new View(getActivity());
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             spiedMenu.onItemLongClick(
                     mAppMenuHandler.getAppMenu().getMenuItemPropertyModel(R.id.icon_one),
@@ -272,7 +253,7 @@
         showMenuAndAssert();
         AppMenu spiedMenu = Mockito.spy(mAppMenuHandler.getAppMenu());
 
-        View dummyView = new View(mActivity);
+        View dummyView = new View(getActivity());
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             spiedMenu.onItemLongClick(
                     mAppMenuHandler.getAppMenu().getMenuItemPropertyModel(R.id.icon_two),
@@ -289,7 +270,7 @@
         showMenuAndAssert();
         AppMenu spiedMenu = Mockito.spy(mAppMenuHandler.getAppMenu());
 
-        View dummyView = new View(mActivity);
+        View dummyView = new View(getActivity());
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             spiedMenu.onItemLongClick(
                     mAppMenuHandler.getAppMenu().getMenuItemPropertyModel(R.id.icon_three),
@@ -892,7 +873,7 @@
         @Nullable
         @Override
         public View getMenuButtonView() {
-            return mActivity.findViewById(R.id.top_button);
+            return getActivity().findViewById(R.id.top_button);
         }
     }
 
diff --git a/chrome/browser/ui/android/omnibox/BUILD.gn b/chrome/browser/ui/android/omnibox/BUILD.gn
index d3254c8b..b0b5cec4 100644
--- a/chrome/browser/ui/android/omnibox/BUILD.gn
+++ b/chrome/browser/ui/android/omnibox/BUILD.gn
@@ -356,6 +356,7 @@
     "java/src/org/chromium/chrome/browser/omnibox/KeyboardHideHelperUnitTest.java",
     "java/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java",
     "java/src/org/chromium/chrome/browser/omnibox/SearchEngineLogoUtilsUnitTest.java",
+    "java/src/org/chromium/chrome/browser/omnibox/ShadowUrlBarData.java",
     "java/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModelUnitTest.java",
     "java/src/org/chromium/chrome/browser/omnibox/UrlBarDataTest.java",
     "java/src/org/chromium/chrome/browser/omnibox/UrlBarMediatorUnitTest.java",
@@ -371,6 +372,7 @@
     "java/src/org/chromium/chrome/browser/omnibox/suggestions/base/SimpleHorizontalLayoutViewTest.java",
     "java/src/org/chromium/chrome/browser/omnibox/suggestions/base/SimpleVerticalLayoutViewTest.java",
     "java/src/org/chromium/chrome/browser/omnibox/suggestions/base/SuggestionSpannableUnitTest.java",
+    "java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessorUnitTest.java",
     "java/src/org/chromium/chrome/browser/omnibox/suggestions/carousel/BaseCarouselSuggestionSelectionManagerUnitTest.java",
     "java/src/org/chromium/chrome/browser/omnibox/suggestions/carousel/BaseCarouselSuggestionViewBinderUnitTest.java",
     "java/src/org/chromium/chrome/browser/omnibox/suggestions/header/HeaderViewBinderUnitTest.java",
@@ -430,6 +432,7 @@
     "//ui/android:ui_no_recycler_view_java",
     "//ui/android:ui_recycler_view_java",
     "//url:gurl_java",
+    "//url:gurl_junit_shadows",
     "//url:gurl_junit_test_support",
   ]
   annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/ShadowUrlBarData.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/ShadowUrlBarData.java
new file mode 100644
index 0000000..0e44fe7
--- /dev/null
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/ShadowUrlBarData.java
@@ -0,0 +1,23 @@
+// Copyright 2022 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.omnibox;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+/**
+ * Shadow of the UrlBarData, that permits stubbing/mocking static methods for testing.
+ */
+@Implements(UrlBarData.class)
+public class ShadowUrlBarData {
+    public static boolean sShouldShowNextUrl = true;
+
+    @Implementation
+    public static boolean shouldShowUrl(String url, boolean isIncognito) {
+        boolean res = sShouldShowNextUrl;
+        sShouldShowNextUrl = true;
+        return res;
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessorUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessorUnitTest.java
similarity index 82%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessorUnitTest.java
rename to chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessorUnitTest.java
index a9fce94..e78ca07 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessorUnitTest.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessorUnitTest.java
@@ -10,10 +10,8 @@
 import static org.mockito.Mockito.verify;
 
 import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
 import android.graphics.drawable.BitmapDrawable;
 
-import androidx.collection.ArrayMap;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Assert;
@@ -24,39 +22,45 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.annotation.Config;
 
 import org.chromium.base.ContextUtils;
-import org.chromium.base.test.BaseJUnit4ClassRunner;
-import org.chromium.base.test.UiThreadTest;
-import org.chromium.base.test.util.Batch;
+import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.omnibox.OmniboxSuggestionType;
+import org.chromium.chrome.browser.omnibox.ShadowUrlBarData;
 import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider;
 import org.chromium.chrome.browser.omnibox.suggestions.SuggestionHost;
 import org.chromium.chrome.browser.omnibox.suggestions.base.BaseSuggestionViewProperties;
 import org.chromium.chrome.browser.omnibox.suggestions.base.SuggestionDrawableState;
 import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewProperties.SuggestionIcon;
 import org.chromium.chrome.test.util.browser.Features;
-import org.chromium.components.embedder_support.util.UrlConstants;
 import org.chromium.components.favicon.LargeIconBridge;
 import org.chromium.components.favicon.LargeIconBridge.LargeIconCallback;
 import org.chromium.components.omnibox.AutocompleteMatch;
 import org.chromium.components.omnibox.AutocompleteMatchBuilder;
-import org.chromium.content_public.browser.test.NativeLibraryTestUtils;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.url.GURL;
+import org.chromium.url.JUnitTestGURLs;
+import org.chromium.url.ShadowGURL;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Tests for {@link BasicSuggestionProcessor}.
  */
-@RunWith(BaseJUnit4ClassRunner.class)
-@Batch(Batch.UNIT_TESTS)
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, shadows = {ShadowGURL.class, ShadowUrlBarData.class})
 public class BasicSuggestionProcessorUnitTest {
-    private static final ArrayMap<Integer, String> ICON_TYPE_NAMES =
-            new ArrayMap<Integer, String>(SuggestionIcon.TOTAL_COUNT) {
+    private static final GURL EXTERNAL_URL = JUnitTestGURLs.getGURL(JUnitTestGURLs.URL_1);
+    private static final GURL INTERNAL_URL = JUnitTestGURLs.getGURL(JUnitTestGURLs.NTP_URL);
+
+    private static final Map<Integer, String> ICON_TYPE_NAMES =
+            new HashMap<Integer, String>(SuggestionIcon.TOTAL_COUNT) {
                 {
                     put(SuggestionIcon.UNSET, "UNSET");
                     put(SuggestionIcon.BOOKMARK, "BOOKMARK");
@@ -68,43 +72,39 @@
                 }
             };
 
-    private static final ArrayMap<Integer, String> SUGGESTION_TYPE_NAMES =
-            new ArrayMap<Integer, String>(OmniboxSuggestionType.NUM_TYPES) {
-                {
-                    put(OmniboxSuggestionType.URL_WHAT_YOU_TYPED, "URL_WHAT_YOU_TYPED");
-                    put(OmniboxSuggestionType.HISTORY_URL, "HISTORY_URL");
-                    put(OmniboxSuggestionType.HISTORY_TITLE, "HISTORY_TITLE");
-                    put(OmniboxSuggestionType.HISTORY_BODY, "HISTORY_BODY");
-                    put(OmniboxSuggestionType.HISTORY_KEYWORD, "HISTORY_KEYWORD");
-                    put(OmniboxSuggestionType.NAVSUGGEST, "NAVSUGGEST");
-                    put(OmniboxSuggestionType.SEARCH_WHAT_YOU_TYPED, "SEARCH_WHAT_YOU_TYPED");
-                    put(OmniboxSuggestionType.SEARCH_HISTORY, "SEARCH_HISTORY");
-                    put(OmniboxSuggestionType.SEARCH_SUGGEST, "SEARCH_SUGGEST");
-                    put(OmniboxSuggestionType.SEARCH_SUGGEST_ENTITY, "SEARCH_SUGGEST_ENTITY");
-                    put(OmniboxSuggestionType.SEARCH_SUGGEST_TAIL, "SEARCH_SUGGEST_TAIL");
-                    put(OmniboxSuggestionType.SEARCH_SUGGEST_PERSONALIZED,
-                            "SEARCH_SUGGEST_PERSONALIZED");
-                    put(OmniboxSuggestionType.SEARCH_SUGGEST_PROFILE, "SEARCH_SUGGEST_PROFILE");
-                    put(OmniboxSuggestionType.SEARCH_OTHER_ENGINE, "SEARCH_OTHER_ENGINE");
-                    put(OmniboxSuggestionType.NAVSUGGEST_PERSONALIZED, "NAVSUGGEST_PERSONALIZED");
-                    put(OmniboxSuggestionType.VOICE_SUGGEST, "VOICE_SUGGEST");
-                    put(OmniboxSuggestionType.DOCUMENT_SUGGESTION, "DOCUMENT_SUGGESTION");
-                    // Note: CALCULATOR suggestions are not handled by basic suggestion processor.
-                    // These suggestions are now processed by AnswerSuggestionProcessor instead.
-                }
-            };
+    private static final Map<Integer, String> SUGGESTION_TYPE_NAMES = new HashMap<Integer, String>(
+            OmniboxSuggestionType.NUM_TYPES) {
+        {
+            put(OmniboxSuggestionType.URL_WHAT_YOU_TYPED, "URL_WHAT_YOU_TYPED");
+            put(OmniboxSuggestionType.HISTORY_URL, "HISTORY_URL");
+            put(OmniboxSuggestionType.HISTORY_TITLE, "HISTORY_TITLE");
+            put(OmniboxSuggestionType.HISTORY_BODY, "HISTORY_BODY");
+            put(OmniboxSuggestionType.HISTORY_KEYWORD, "HISTORY_KEYWORD");
+            put(OmniboxSuggestionType.NAVSUGGEST, "NAVSUGGEST");
+            put(OmniboxSuggestionType.SEARCH_WHAT_YOU_TYPED, "SEARCH_WHAT_YOU_TYPED");
+            put(OmniboxSuggestionType.SEARCH_HISTORY, "SEARCH_HISTORY");
+            put(OmniboxSuggestionType.SEARCH_SUGGEST, "SEARCH_SUGGEST");
+            put(OmniboxSuggestionType.SEARCH_SUGGEST_ENTITY, "SEARCH_SUGGEST_ENTITY");
+            put(OmniboxSuggestionType.SEARCH_SUGGEST_TAIL, "SEARCH_SUGGEST_TAIL");
+            put(OmniboxSuggestionType.SEARCH_SUGGEST_PERSONALIZED, "SEARCH_SUGGEST_PERSONALIZED");
+            put(OmniboxSuggestionType.SEARCH_SUGGEST_PROFILE, "SEARCH_SUGGEST_PROFILE");
+            put(OmniboxSuggestionType.SEARCH_OTHER_ENGINE, "SEARCH_OTHER_ENGINE");
+            put(OmniboxSuggestionType.NAVSUGGEST_PERSONALIZED, "NAVSUGGEST_PERSONALIZED");
+            put(OmniboxSuggestionType.VOICE_SUGGEST, "VOICE_SUGGEST");
+            put(OmniboxSuggestionType.DOCUMENT_SUGGESTION, "DOCUMENT_SUGGESTION");
+            // Note: CALCULATOR suggestions are not handled by basic suggestion processor.
+            // These suggestions are now processed by AnswerSuggestionProcessor instead.
+        }
+    };
 
-    @Rule
-    public TestRule mFeaturesProcessor = new Features.JUnitProcessor();
+    public @Rule TestRule mFeaturesProcessor = new Features.JUnitProcessor();
+    public @Rule MockitoRule mMockitoRule = MockitoJUnit.rule();
 
-    @Mock
-    SuggestionHost mSuggestionHost;
-    @Mock
-    LargeIconBridge mIconBridge;
-    @Mock
-    UrlBarEditingTextStateProvider mUrlBarText;
+    private @Mock SuggestionHost mSuggestionHost;
+    private @Mock LargeIconBridge mIconBridge;
+    private @Mock UrlBarEditingTextStateProvider mUrlBarText;
+    private @Mock Bitmap mBitmap;
 
-    private Bitmap mBitmap;
     private BasicSuggestionProcessor mProcessor;
     private AutocompleteMatch mSuggestion;
     private PropertyModel mModel;
@@ -122,10 +122,7 @@
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess();
         doReturn("").when(mUrlBarText).getTextWithoutAutocomplete();
-        mBitmap = Bitmap.createBitmap(1, 1, Config.ALPHA_8);
         mProcessor = new BasicSuggestionProcessor(ContextUtils.getApplicationContext(),
                 mSuggestionHost, mUrlBarText, () -> mIconBridge, mIsBookmarked);
     }
@@ -175,7 +172,6 @@
 
     @Test
     @SmallTest
-    @UiThreadTest
     public void getSuggestionIconTypeForSearch_Default() {
         int[][] testCases = {
                 {OmniboxSuggestionType.URL_WHAT_YOU_TYPED, SuggestionIcon.MAGNIFIER},
@@ -207,7 +203,6 @@
 
     @Test
     @SmallTest
-    @UiThreadTest
     public void getSuggestionIconTypeForUrl_Default() {
         int[][] testCases = {
                 {OmniboxSuggestionType.URL_WHAT_YOU_TYPED, SuggestionIcon.GLOBE},
@@ -239,7 +234,6 @@
 
     @Test
     @SmallTest
-    @UiThreadTest
     public void getSuggestionIconTypeForBookmarks_Default() {
         int[][] testCases = {
                 {OmniboxSuggestionType.URL_WHAT_YOU_TYPED, SuggestionIcon.BOOKMARK},
@@ -273,7 +267,6 @@
 
     @Test
     @SmallTest
-    @UiThreadTest
     public void getSuggestionIconTypeForTrendingQueries() {
         int[][] testCases = {
                 {OmniboxSuggestionType.URL_WHAT_YOU_TYPED, SuggestionIcon.TRENDS},
@@ -296,7 +289,6 @@
 
     @Test
     @SmallTest
-    @UiThreadTest
     public void refineIconNotShownForWhatYouTypedSuggestions() {
         final String typed = "Typed content";
         doReturn(typed).when(mUrlBarText).getTextWithoutAutocomplete();
@@ -312,7 +304,6 @@
 
     @Test
     @SmallTest
-    @UiThreadTest
     public void refineIconShownForRefineSuggestions() {
         final String typed = "Typed conte";
         final String refined = "Typed content";
@@ -335,7 +326,6 @@
 
     @Test
     @SmallTest
-    @UiThreadTest
     public void switchTabIconShownForSwitchToTabSuggestions() {
         final String tabMatch = "tab match";
         createSwitchToTabSuggestion(OmniboxSuggestionType.URL_WHAT_YOU_TYPED, tabMatch);
@@ -352,7 +342,6 @@
 
     @Test
     @SmallTest
-    @UiThreadTest
     public void suggestionFavicons_showFaviconWhenAvailable() {
         final ArgumentCaptor<LargeIconCallback> callback =
                 ArgumentCaptor.forClass(LargeIconCallback.class);
@@ -373,7 +362,6 @@
 
     @Test
     @SmallTest
-    @UiThreadTest
     public void suggestionFavicons_doNotReplaceFallbackIconWhenNoFaviconIsAvailable() {
         final ArgumentCaptor<LargeIconCallback> callback =
                 ArgumentCaptor.forClass(LargeIconCallback.class);
@@ -393,7 +381,6 @@
 
     @Test
     @SmallTest
-    @UiThreadTest
     public void searchSuggestions_searchQueriesCanWrapAroundWithFeatureEnabled() {
         mProcessor.onNativeInitialized();
         createSearchSuggestion(OmniboxSuggestionType.SEARCH_WHAT_YOU_TYPED, "");
@@ -405,17 +392,12 @@
 
     @Test
     @SmallTest
-    @UiThreadTest
     public void internalUrlSuggestions_doNotPresentInternalScheme() {
         mProcessor.onNativeInitialized();
-        // chrome://newtab and such should have no URL in the suggestions list.
-        createUrlSuggestion(OmniboxSuggestionType.URL_WHAT_YOU_TYPED, "",
-                new GURL(UrlConstants.NTP_NON_NATIVE_URL));
-        Assert.assertNull(mModel.get(SuggestionViewProperties.TEXT_LINE_2_TEXT));
-
-        // Similarly, internal (eg. chrome-intenal://) URLs should not be shown.
+        // URLs that are rejected by UrlBarData should not be presented to the User.
+        ShadowUrlBarData.sShouldShowNextUrl = false;
         createUrlSuggestion(
-                OmniboxSuggestionType.URL_WHAT_YOU_TYPED, "", new GURL(UrlConstants.DOWNLOADS_URL));
+                OmniboxSuggestionType.URL_WHAT_YOU_TYPED, "", new GURL(JUnitTestGURLs.URL_1));
         Assert.assertNull(mModel.get(SuggestionViewProperties.TEXT_LINE_2_TEXT));
     }
 }
diff --git a/chrome/browser/ui/cocoa/applescript/tab_applescript.mm b/chrome/browser/ui/cocoa/applescript/tab_applescript.mm
index 1bc4a58..d1ddc0e 100644
--- a/chrome/browser/ui/cocoa/applescript/tab_applescript.mm
+++ b/chrome/browser/ui/cocoa/applescript/tab_applescript.mm
@@ -236,7 +236,7 @@
 - (void)handlesPrintScriptCommand:(NSScriptCommand*)command {
   AppleScript::LogAppleScriptUMA(AppleScript::AppleScriptCommand::TAB_PRINT);
   bool initiated = printing::PrintViewManager::FromWebContents(_webContents)
-                       ->PrintNow(_webContents->GetMainFrame());
+                       ->PrintNow(_webContents->GetPrimaryMainFrame());
   if (!initiated) {
     AppleScript::SetError(AppleScript::errInitiatePrinting);
   }
@@ -306,7 +306,7 @@
     return nil;
   }
 
-  content::RenderFrameHost* frame = _webContents->GetMainFrame();
+  content::RenderFrameHost* frame = _webContents->GetPrimaryMainFrame();
   if (!frame) {
     NOTREACHED();
     return nil;
diff --git a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_unittest.mm b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_unittest.mm
index 0d76c2b..c8a49ad4 100644
--- a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_unittest.mm
@@ -31,7 +31,7 @@
     content::ContextMenuParams params;
     params.selection_text = base::UTF8ToUTF16(text);
     auto menu = std::make_unique<RenderViewContextMenuMac>(
-        *contents_->GetMainFrame(), params);
+        *contents_->GetPrimaryMainFrame(), params);
     menu->InitToolkitMenu();
     return menu;
   }
diff --git a/chrome/browser/ui/content_settings/content_setting_media_image_model_unittest.mm b/chrome/browser/ui/content_settings/content_setting_media_image_model_unittest.mm
index 5f41ec0..98d90ac 100644
--- a/chrome/browser/ui/content_settings/content_setting_media_image_model_unittest.mm
+++ b/chrome/browser/ui/content_settings/content_setting_media_image_model_unittest.mm
@@ -87,8 +87,8 @@
       web_contents(),
       std::make_unique<chrome::PageSpecificContentSettingsDelegate>(
           web_contents()));
-  auto* content_settings =
-      PageSpecificContentSettings::GetForFrame(web_contents()->GetMainFrame());
+  auto* content_settings = PageSpecificContentSettings::GetForFrame(
+      web_contents()->GetPrimaryMainFrame());
   const GURL kTestOrigin("https://www.example.com");
   auto content_setting_image_model =
       ContentSettingImageModel::CreateForContentType(
diff --git a/chrome/browser/ui/sharing_hub/sharing_hub_bubble_controller.h b/chrome/browser/ui/sharing_hub/sharing_hub_bubble_controller.h
index 73f95d0..5c5b1823 100644
--- a/chrome/browser/ui/sharing_hub/sharing_hub_bubble_controller.h
+++ b/chrome/browser/ui/sharing_hub/sharing_hub_bubble_controller.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_SHARING_HUB_SHARING_HUB_BUBBLE_CONTROLLER_H_
 
 #include "chrome/browser/share/share_attempt.h"
+#include "chrome/browser/sharing_hub/sharing_hub_model.h"
 
 namespace content {
 class WebContents;
@@ -33,6 +34,39 @@
   virtual SharingHubBubbleView* sharing_hub_bubble_view() const = 0;
   // Returns true if the omnibox icon should be shown.
   virtual bool ShouldOfferOmniboxIcon() = 0;
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
+    BUILDFLAG(IS_FUCHSIA)
+  // These two methods return the sets of first- and third-party actions;
+  // first-party actions are internal to Chrome and third-party actions are
+  // other websites or apps.
+  //
+  // TODO(ellyjones): Could we feasibly pass these in when we construct
+  // ShareAttempt? Does that make sense, even?
+  virtual std::vector<SharingHubAction> GetFirstPartyActions() = 0;
+  virtual std::vector<SharingHubAction> GetThirdPartyActions() = 0;
+
+  // Returns whether the sharing hub should show a preview section or not.
+  // TODO(ellyjones): Remove this once the preview section is launched.
+  virtual bool ShouldUsePreview() = 0;
+
+  // The sharing hub can load images asynchronously under some circumstances; to
+  // allow for that, the controller allows clients to register a callback to be
+  // notified when a new image is loaded.
+  using PreviewImageChangedCallback =
+      base::RepeatingCallback<void(ui::ImageModel)>;
+  virtual base::CallbackListSubscription RegisterPreviewImageChangedCallback(
+      PreviewImageChangedCallback callback) = 0;
+
+  virtual base::WeakPtr<SharingHubBubbleController> GetWeakPtr() = 0;
+
+  // Client code should call these when the corresponding things happen in the
+  // View.
+  virtual void OnBubbleClosed() = 0;
+  virtual void OnActionSelected(int command_id,
+                                bool is_first_party,
+                                std::string feature_name_for_metrics) = 0;
+#endif
 };
 
 }  // namespace sharing_hub
diff --git a/chrome/browser/ui/sharing_hub/sharing_hub_bubble_controller_desktop_impl.cc b/chrome/browser/ui/sharing_hub/sharing_hub_bubble_controller_desktop_impl.cc
index 66bf082a..3209025 100644
--- a/chrome/browser/ui/sharing_hub/sharing_hub_bubble_controller_desktop_impl.cc
+++ b/chrome/browser/ui/sharing_hub/sharing_hub_bubble_controller_desktop_impl.cc
@@ -162,28 +162,17 @@
          share::DesktopSharePreviewVariant::kDisabled;
 }
 
-std::u16string SharingHubBubbleControllerDesktopImpl::GetPreviewTitle() {
-  // TODO(https://crbug.com/1312524): get passed this state from the omnibox
-  // instead.
-  return GetWebContents().GetTitle();
-}
-
-GURL SharingHubBubbleControllerDesktopImpl::GetPreviewUrl() {
-  // TODO(https://crbug.com/1312524): get passed this state from the omnibox
-  // instead.
-  return GetWebContents().GetVisibleURL();
-}
-
-ui::ImageModel SharingHubBubbleControllerDesktopImpl::GetPreviewImage() {
-  return ui::ImageModel::FromImage(favicon::GetDefaultFavicon());
-}
-
 base::CallbackListSubscription
 SharingHubBubbleControllerDesktopImpl::RegisterPreviewImageChangedCallback(
     PreviewImageChangedCallback callback) {
   return preview_image_changed_callbacks_.Add(callback);
 }
 
+base::WeakPtr<SharingHubBubbleController>
+SharingHubBubbleControllerDesktopImpl::GetWeakPtr() {
+  return weak_factory_.GetWeakPtr();
+}
+
 void SharingHubBubbleControllerDesktopImpl::OnActionSelected(
     int command_id,
     bool is_first_party,
@@ -261,7 +250,7 @@
       GetWebContents().GetPrimaryPage().GetMainDocument();
   main_frame.GetOpenGraphMetadata(base::BindOnce(
       &SharingHubBubbleControllerDesktopImpl::OnGetOpenGraphMetadata,
-      AsWeakPtr()));
+      internal_weak_factory_.GetWeakPtr()));
 }
 
 void SharingHubBubbleControllerDesktopImpl::OnGetOpenGraphMetadata(
@@ -288,7 +277,7 @@
   image_fetcher_->FetchImage(
       *metadata->image,
       base::BindOnce(&SharingHubBubbleControllerDesktopImpl::OnGetHQImage,
-                     AsWeakPtr()),
+                     internal_weak_factory_.GetWeakPtr()),
       image_fetcher::ImageFetcherParams(kPreviewImageNetworkAnnotationTag,
                                         kPreviewUmaClient));
 }
diff --git a/chrome/browser/ui/sharing_hub/sharing_hub_bubble_controller_desktop_impl.h b/chrome/browser/ui/sharing_hub/sharing_hub_bubble_controller_desktop_impl.h
index 9db0026..2268617 100644
--- a/chrome/browser/ui/sharing_hub/sharing_hub_bubble_controller_desktop_impl.h
+++ b/chrome/browser/ui/sharing_hub/sharing_hub_bubble_controller_desktop_impl.h
@@ -38,12 +38,8 @@
     : public SharingHubBubbleController,
       public content::WebContentsObserver,
       public content::WebContentsUserData<
-          SharingHubBubbleControllerDesktopImpl>,
-      public base::SupportsWeakPtr<SharingHubBubbleControllerDesktopImpl> {
+          SharingHubBubbleControllerDesktopImpl> {
  public:
-  using PreviewImageChangedCallback =
-      base::RepeatingCallback<void(ui::ImageModel)>;
-
   SharingHubBubbleControllerDesktopImpl(
       const SharingHubBubbleControllerDesktopImpl&) = delete;
   SharingHubBubbleControllerDesktopImpl& operator=(
@@ -62,27 +58,17 @@
   // Returns the current profile.
   Profile* GetProfile() const;
 
-  // Returns the list of Sharing Hub first party actions.
-  virtual std::vector<SharingHubAction> GetFirstPartyActions();
-  // Returns the list of Sharing Hub third party actions.
-  virtual std::vector<SharingHubAction> GetThirdPartyActions();
-
-  virtual bool ShouldUsePreview();
-  virtual std::u16string GetPreviewTitle();
-  virtual GURL GetPreviewUrl();
-  virtual ui::ImageModel GetPreviewImage();
-
+  // SharingHubBubbleController:
+  std::vector<SharingHubAction> GetFirstPartyActions() override;
+  std::vector<SharingHubAction> GetThirdPartyActions() override;
+  bool ShouldUsePreview() override;
   base::CallbackListSubscription RegisterPreviewImageChangedCallback(
-      PreviewImageChangedCallback callback);
-
-  // Handles when the user clicks on a Sharing Hub action. If this is a first
-  // party action, executes the appropriate browser command. If this is a third
-  // party action, navigates to an external webpage.
-  virtual void OnActionSelected(int command_id,
-                                bool is_first_party,
-                                std::string feature_name_for_metrics);
-  // Handler for when the bubble is closed.
-  void OnBubbleClosed();
+      PreviewImageChangedCallback callback) override;
+  base::WeakPtr<SharingHubBubbleController> GetWeakPtr() override;
+  void OnActionSelected(int command_id,
+                        bool is_first_party,
+                        std::string feature_name_for_metrics) override;
+  void OnBubbleClosed() override;
 
  protected:
   explicit SharingHubBubbleControllerDesktopImpl(
@@ -124,6 +110,17 @@
 
   std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher_;
 
+  base::WeakPtrFactory<SharingHubBubbleController> weak_factory_{this};
+
+  // This is a bit ugly: SharingHubBubbleController's interface requires it to
+  // be able to create WeakPtr<SharingHubBubbleController>, but this class
+  // internally also needs to be able to bind weak pointers to itself for use
+  // with the image fetching state machine. Those internal weak pointers need to
+  // be to an instance of *this class*, not of the parent interface, so that we
+  // can bind them to methods on this class rather than the parent interface.
+  base::WeakPtrFactory<SharingHubBubbleControllerDesktopImpl>
+      internal_weak_factory_{this};
+
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 };
 
diff --git a/chrome/browser/ui/toolbar/location_bar_model_unittest.cc b/chrome/browser/ui/toolbar/location_bar_model_unittest.cc
index 1410d00..91ae52d 100644
--- a/chrome/browser/ui/toolbar/location_bar_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/location_bar_model_unittest.cc
@@ -46,12 +46,19 @@
       {
           GURL("view-source:http://www.google.com"),
           "view-source:www.google.com",
-          "view-source:www.google.com",
       },
       {
           GURL(chrome::kChromeUINewTabURL),
           "",
       },
+      // After executing the associated JS code, the "javascript:" scheme
+      // will cause the address in the location bar to revert to whatever
+      // it was prior to execution of the JS code (i.e. the URL of the
+      // previous test case)
+      {
+          GURL("javascript:alert(1);"),
+          "",
+      },
       {
           GURL(std::string("view-source:") + chrome::kChromeUINewTabURL),
           "view-source:" +
@@ -75,10 +82,54 @@
           "google.com/search?q=tractor+supply",
       },
       {
+          GURL("https://www.google.com/search?q=tractor+supply"),
+          "https://www.google.com/search?q=tractor+supply",
+          "google.com/search?q=tractor+supply",
+      },
+      {
           GURL("https://m.google.ca/search?q=tractor+supply"),
           "https://m.google.ca/search?q=tractor+supply",
           "m.google.ca/search?q=tractor+supply",
       },
+      {
+          GURL("http://m.google.ca/search?q=tractor+supply"),
+          "m.google.ca/search?q=tractor+supply",
+      },
+      {
+          GURL("http://en.wikipedia.org"),
+          "en.wikipedia.org",
+      },
+      {
+          GURL("https://en.wikipedia.org"),
+          "https://en.wikipedia.org",
+          "en.wikipedia.org",
+      },
+      {
+          GURL("http://www3.nhk.or.jp/nhkworld"),
+          "www3.nhk.or.jp/nhkworld",
+      },
+      {
+          GURL("https://www3.nhk.or.jp/nhkworld"),
+          "https://www3.nhk.or.jp/nhkworld",
+          "www3.nhk.or.jp/nhkworld",
+      },
+#if BUILDFLAG(IS_WIN)
+      {
+          GURL("file:///c:/path/to/file"),
+          "file:///C:/path/to/file",
+          "C:/path/to/file",
+      },
+#else
+      {
+          GURL("file:///path/to/file"),
+          "file:///path/to/file",
+          "/path/to/file",
+      },
+#endif
+      {
+          GURL("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ=="),
+          "data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==",
+      },
   }};
   return *items;
 }
diff --git a/chrome/browser/ui/views/extensions/extensions_tabbed_menu_view.cc b/chrome/browser/ui/views/extensions/extensions_tabbed_menu_view.cc
index f0aef18..1d1201d 100644
--- a/chrome/browser/ui/views/extensions/extensions_tabbed_menu_view.cc
+++ b/chrome/browser/ui/views/extensions/extensions_tabbed_menu_view.cc
@@ -735,7 +735,8 @@
     requests_access_.container->SetVisible(false);
     site_settings_button_->SetVisible(false);
   } else {
-    url::Origin origin = web_contents->GetMainFrame()->GetLastCommittedOrigin();
+    url::Origin origin =
+        web_contents->GetPrimaryMainFrame()->GetLastCommittedOrigin();
     extensions::PermissionsManager::UserSiteSetting site_setting =
         extensions::PermissionsManager::Get(browser_->profile())
             ->GetUserSiteSetting(origin);
@@ -833,8 +834,8 @@
       extensions::PermissionsManager::UserSiteSetting site_setting;
       site_setting =
           extensions::PermissionsManager::Get(browser_->profile())
-              ->GetUserSiteSetting(
-                  web_contents->GetMainFrame()->GetLastCommittedOrigin());
+              ->GetUserSiteSetting(web_contents->GetPrimaryMainFrame()
+                                       ->GetLastCommittedOrigin());
       if (site_setting == UserSiteSetting::kGrantAllExtensions)
         return &has_access_;
       return &requests_access_;
@@ -871,7 +872,7 @@
 void ExtensionsTabbedMenuView::OnSiteSettingSelected(
     extensions::PermissionsManager::UserSiteSetting site_settings) {
   auto current_origin =
-      GetActiveWebContents()->GetMainFrame()->GetLastCommittedOrigin();
+      GetActiveWebContents()->GetPrimaryMainFrame()->GetLastCommittedOrigin();
   auto* permissions_manager =
       extensions::PermissionsManager::Get(browser_->profile());
   switch (site_settings) {
diff --git a/chrome/browser/ui/views/sharing_hub/preview_view.cc b/chrome/browser/ui/views/sharing_hub/preview_view.cc
index eb10a318..aea78548 100644
--- a/chrome/browser/ui/views/sharing_hub/preview_view.cc
+++ b/chrome/browser/ui/views/sharing_hub/preview_view.cc
@@ -91,7 +91,7 @@
 //     View [FlexLayout, vertical]
 //       Label (title)
 //       Label (URL)
-PreviewView::PreviewView(share::ShareAttempt attempt, ui::ImageModel image) {
+PreviewView::PreviewView(share::ShareAttempt attempt) {
   auto variant = LayoutVariant::FromFeatureConfig();
 
   auto* layout = SetLayoutManager(std::make_unique<views::FlexLayout>());
@@ -102,7 +102,8 @@
       .SetDefault(views::kMarginsKey, variant.default_margin)
       .SetCollapseMargins(true);
 
-  image_ = AddChildView(std::make_unique<views::ImageView>(image));
+  image_ =
+      AddChildView(std::make_unique<views::ImageView>(attempt.preview_image));
   image_->SetPreferredSize(variant.image_size);
 
   auto* labels_container = AddChildView(std::make_unique<views::View>());
diff --git a/chrome/browser/ui/views/sharing_hub/preview_view.h b/chrome/browser/ui/views/sharing_hub/preview_view.h
index adf318f2..06faebd 100644
--- a/chrome/browser/ui/views/sharing_hub/preview_view.h
+++ b/chrome/browser/ui/views/sharing_hub/preview_view.h
@@ -30,11 +30,7 @@
 // trial.
 class PreviewView : public views::View {
  public:
-  // Taking an initial image here, instead of requiring the caller to call
-  // OnImageChanged() after construction to set the initial image, means that
-  // this class always has a valid image to display and does not have a
-  // "half-initialized" state to worry about.
-  explicit PreviewView(share::ShareAttempt attempt, ui::ImageModel image);
+  explicit PreviewView(share::ShareAttempt attempt);
   ~PreviewView() override;
 
   // This seemingly-odd method allows for PreviewView to be uncoupled from the
diff --git a/chrome/browser/ui/views/sharing_hub/sharing_hub_bubble_view_impl.cc b/chrome/browser/ui/views/sharing_hub/sharing_hub_bubble_view_impl.cc
index 58a8cf8..8f9e433 100644
--- a/chrome/browser/ui/views/sharing_hub/sharing_hub_bubble_view_impl.cc
+++ b/chrome/browser/ui/views/sharing_hub/sharing_hub_bubble_view_impl.cc
@@ -50,7 +50,7 @@
       static_cast<SharingHubBubbleControllerDesktopImpl*>(
           SharingHubBubbleController::CreateOrGetFromWebContents(
               attempt.web_contents.get()));
-  controller_ = controller->AsWeakPtr();
+  controller_ = controller->GetWeakPtr();
 }
 
 SharingHubBubbleViewImpl::~SharingHubBubbleViewImpl() = default;
@@ -129,8 +129,7 @@
   auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>());
   layout->SetOrientation(views::BoxLayout::Orientation::kVertical);
   if (controller_->ShouldUsePreview()) {
-    auto* preview = AddChildView(std::make_unique<PreviewView>(
-        attempt_, controller_->GetPreviewImage()));
+    auto* preview = AddChildView(std::make_unique<PreviewView>(attempt_));
     preview->TakeCallbackSubscription(
         controller_->RegisterPreviewImageChangedCallback(base::BindRepeating(
             &PreviewView::OnImageChanged, base::Unretained(preview))));
diff --git a/chrome/browser/ui/views/sharing_hub/sharing_hub_bubble_view_impl.h b/chrome/browser/ui/views/sharing_hub/sharing_hub_bubble_view_impl.h
index 96757cd..7d068dc 100644
--- a/chrome/browser/ui/views/sharing_hub/sharing_hub_bubble_view_impl.h
+++ b/chrome/browser/ui/views/sharing_hub/sharing_hub_bubble_view_impl.h
@@ -18,7 +18,7 @@
 
 namespace sharing_hub {
 
-class SharingHubBubbleControllerDesktopImpl;
+class SharingHubBubbleController;
 class SharingHubBubbleActionButton;
 struct SharingHubAction;
 
@@ -77,7 +77,7 @@
   // the bubble during the window close path, since the bubble will be closed
   // asynchronously during browser window teardown but the controller will be
   // destroyed synchronously.
-  base::WeakPtr<SharingHubBubbleControllerDesktopImpl> controller_;
+  base::WeakPtr<SharingHubBubbleController> controller_;
 
   // ScrollView containing the list of share/save actions.
   raw_ptr<views::ScrollView> scroll_view_ = nullptr;
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc
index 09492721..93d6cd5 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc
@@ -65,6 +65,20 @@
   helper_.CheckPlatformShortcutAndIcon(Site::kSiteA);
 }
 
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTestMacWinLinux,
+                       CheckSiteHandlesFile) {
+  helper_.InstallCreateShortcutWindowed(Site::kSiteB);
+  helper_.CheckSiteHandlesFile(Site::kSiteB, "qux");
+  helper_.CheckSiteHandlesFile(Site::kSiteB, "quux");
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTestMacWinLinux,
+                       CheckSiteNotHandlesFile) {
+  helper_.InstallCreateShortcutWindowed(Site::kSiteA);
+  helper_.CheckSiteNotHandlesFile(Site::kSiteA, "qux");
+  helper_.CheckSiteNotHandlesFile(Site::kSiteA, "quux");
+}
+
 // Generated tests:
 
 IN_PROC_BROWSER_TEST_F(
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
index 3bcac7a..e2919a3 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
@@ -32,6 +32,7 @@
 #include "chrome/browser/banners/test_app_banner_manager_desktop.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/shell_integration.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_dialogs.h"
@@ -97,6 +98,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/manifest/display_mode.mojom-shared.h"
 #include "third_party/re2/src/re2/re2.h"
 #include "ui/accessibility/ax_action_data.h"
@@ -120,13 +122,18 @@
 #if BUILDFLAG(IS_MAC)
 #include <ImageIO/ImageIO.h>
 #include "chrome/browser/apps/app_shim/app_shim_manager_mac.h"
+#include "chrome/browser/shell_integration.h"
 #include "chrome/browser/web_applications/app_shim_registry_mac.h"
+#include "net/base/filename_util.h"
 #include "skia/ext/skia_utils_mac.h"
 #endif
 
 #if BUILDFLAG(IS_WIN)
+#include "base/test/test_reg_util_win.h"
 #include "base/win/shortcut.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/web_applications/os_integration/web_app_handler_registration_utils_win.h"
+#include "chrome/installer/util/shell_util.h"
 #endif
 
 namespace web_app::integration_tests {
@@ -293,6 +300,23 @@
 }
 
 #if BUILDFLAG(IS_WIN)
+std::vector<std::wstring> GetFileExtensionsForProgId(
+    const std::wstring& file_handler_prog_id) {
+  const std::wstring prog_id_path =
+      base::StrCat({ShellUtil::kRegClasses, L"\\", file_handler_prog_id});
+
+  // Get list of handled file extensions from value FileExtensions at
+  // HKEY_CURRENT_USER\Software\Classes\<file_handler_prog_id>.
+  base::win::RegKey file_extensions_key(HKEY_CURRENT_USER, prog_id_path.c_str(),
+                                        KEY_QUERY_VALUE);
+  std::wstring handled_file_extensions;
+  EXPECT_EQ(file_extensions_key.ReadValue(L"FileExtensions",
+                                          &handled_file_extensions),
+            ERROR_SUCCESS);
+  return base::SplitString(handled_file_extensions, std::wstring(L";"),
+                           base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+}
+
 base::FilePath GetShortcutProfile(base::FilePath shortcut_path) {
   base::FilePath shortcut_profile;
   std::wstring cmd_line_string;
@@ -544,7 +568,7 @@
 }
 
 void WebAppIntegrationTestDriver::SetUpOnMainThread() {
-  shortcut_override_ = OverrideShortcutsForTesting();
+  shortcut_override_ = OverrideShortcutsForTesting(base::GetHomeDir());
 
   // Only support manifest updates on non-sync tests, as the current
   // infrastructure here only supports listening on one profile.
@@ -1831,6 +1855,26 @@
   AfterStateCheckAction();
 }
 
+void WebAppIntegrationTestDriver::CheckSiteHandlesFile(
+    Site site,
+    std::string file_extension) {
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
+  BeforeStateCheckAction(__FUNCTION__);
+  ASSERT_TRUE(IsFileHandledBySite(site, file_extension));
+  AfterStateCheckAction();
+#endif
+}
+
+void WebAppIntegrationTestDriver::CheckSiteNotHandlesFile(
+    Site site,
+    std::string file_extension) {
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
+  BeforeStateCheckAction(__FUNCTION__);
+  ASSERT_FALSE(IsFileHandledBySite(site, file_extension));
+  AfterStateCheckAction();
+#endif
+}
+
 void WebAppIntegrationTestDriver::CheckUserCannotSetRunOnOsLogin(Site site) {
 #if !BUILDFLAG(IS_CHROMEOS)
   BeforeStateCheckAction(__FUNCTION__);
@@ -2468,6 +2512,49 @@
   return is_shortcut_and_icon_correct;
 }
 
+bool WebAppIntegrationTestDriver::IsFileHandledBySite(
+    Site site,
+    std::string file_extension) {
+  base::ScopedAllowBlockingForTesting allow_blocking;
+  bool is_file_handled = false;
+#if BUILDFLAG(IS_WIN)
+  AppId app_id = GetAppIdBySiteMode(site);
+  const std::wstring prog_id =
+      GetProgIdForApp(browser()->profile()->GetPath(), app_id);
+  const std::vector<std::wstring> file_handler_prog_ids =
+      ShellUtil::GetFileHandlerProgIdsForAppId(prog_id);
+
+  base::win::RegKey key;
+  std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
+  for (const auto& file_handler_prog_id : file_handler_prog_ids) {
+    const std::vector<std::wstring> supported_file_extensions =
+        GetFileExtensionsForProgId(file_handler_prog_id);
+    std::wstring extension = converter.from_bytes("." + file_extension);
+    if (std::find(supported_file_extensions.begin(),
+                  supported_file_extensions.end(),
+                  extension) != supported_file_extensions.end()) {
+      const std::wstring reg_key =
+          L"Software\\Classes\\" + extension + L"\\OpenWithProgids";
+      EXPECT_EQ(ERROR_SUCCESS,
+                key.Open(HKEY_CURRENT_USER, reg_key.data(), KEY_READ));
+      return key.HasValue(file_handler_prog_id.data());
+    }
+  }
+#elif BUILDFLAG(IS_MAC)
+  std::string app_name = g_site_to_app_name.find(site)->second;
+  const base::FilePath test_file_path =
+      shortcut_override_->chrome_apps_folder.GetPath().AppendASCII(
+          "test." + file_extension);
+  const base::File test_file(
+      test_file_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+  const GURL test_file_url = net::FilePathToFileURL(test_file_path);
+  is_file_handled =
+      (base::UTF8ToUTF16(app_name) ==
+       shell_integration::GetApplicationNameForProtocol(test_file_url));
+#endif
+  return is_file_handled;
+}
+
 void WebAppIntegrationTestDriver::SetRunOnOsLoginMode(
     Site site,
     apps::RunOnOsLoginMode login_mode) {
@@ -2542,6 +2629,7 @@
   enabled_features.push_back(features::kPwaUpdateDialogForName);
   enabled_features.push_back(features::kDesktopPWAsEnforceWebAppSettingsPolicy);
   enabled_features.push_back(features::kWebAppWindowControlsOverlay);
+  enabled_features.push_back(blink::features::kFileHandlingAPI);
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   disabled_features.push_back(features::kWebAppsCrosapi);
   disabled_features.push_back(chromeos::features::kLacrosPrimary);
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h
index b68a41d..30a283fc 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.h
@@ -261,6 +261,8 @@
   void CheckPlatformShortcutNotExists(Site site);
   void CheckRunOnOsLoginEnabled(Site site);
   void CheckRunOnOsLoginDisabled(Site site);
+  void CheckSiteHandlesFile(Site site, std::string file_extension);
+  void CheckSiteNotHandlesFile(Site site, std::string file_extension);
   void CheckUserCannotSetRunOnOsLogin(Site site);
   void CheckUserDisplayModeInternal(UserDisplayMode user_display_mode);
   void CheckWindowClosed();
@@ -332,6 +334,8 @@
                                 const std::string& name,
                                 const AppId& id);
 
+  bool IsFileHandledBySite(Site site, std::string file_extension);
+
   void SetRunOnOsLoginMode(Site site, apps::RunOnOsLoginMode login_mode);
 
   void LaunchAppStartupBrowserCreator(const AppId& app_id);
diff --git a/chrome/browser/ui/webui/feed_internals/feed_internals.mojom b/chrome/browser/ui/webui/feed_internals/feed_internals.mojom
index e26aed51..a842b1d 100644
--- a/chrome/browser/ui/webui/feed_internals/feed_internals.mojom
+++ b/chrome/browser/ui/webui/feed_internals/feed_internals.mojom
@@ -31,9 +31,8 @@
   // Whether debugging the WebFeed follow intro is enabled.
   bool is_web_feed_follow_intro_debug_enabled;
 
-  // Whether the legacy feed endpoint should be used for Web Feed content
-  // fetches.
-  bool use_feed_query_requests_for_web_feeds;
+  // Whether the legacy feed endpoint should be used.
+  bool use_feed_query_requests;
 
   // Last load stream status, human readable.
   string load_stream_status;
@@ -117,7 +116,7 @@
 
   // Sets whether the legacy feed endpoint should be used for Web Feed content
   // fetches.
-  SetUseFeedQueryRequestsForWebFeeds(bool use_legacy);
+  SetUseFeedQueryRequests(bool use_legacy);
 
   // Sets the Following feed order in local preferences.
   SetFollowingFeedOrder(FeedOrder order);
diff --git a/chrome/browser/ui/webui/feed_internals/feedv2_internals_page_handler.cc b/chrome/browser/ui/webui/feed_internals/feedv2_internals_page_handler.cc
index 7641e07..90edb76 100644
--- a/chrome/browser/ui/webui/feed_internals/feedv2_internals_page_handler.cc
+++ b/chrome/browser/ui/webui/feed_internals/feedv2_internals_page_handler.cc
@@ -64,8 +64,7 @@
       offline_pages::prefetch_prefs::IsEnabled(pref_service_);
   properties->is_web_feed_follow_intro_debug_enabled =
       IsWebFeedFollowIntroDebugEnabled();
-  properties->use_feed_query_requests_for_web_feeds =
-      ShouldUseFeedQueryRequestsForWebFeeds();
+  properties->use_feed_query_requests = ShouldUseFeedQueryRequests();
   if (debug_data.fetch_info)
     properties->feed_fetch_url = debug_data.fetch_info->base_request_url;
   if (debug_data.upload_info)
@@ -157,13 +156,13 @@
                             enabled);
 }
 
-bool FeedV2InternalsPageHandler::ShouldUseFeedQueryRequestsForWebFeeds() {
-  return feed::GetFeedConfig().use_feed_query_requests_for_web_feeds;
+bool FeedV2InternalsPageHandler::ShouldUseFeedQueryRequests() {
+  return feed::GetFeedConfig().use_feed_query_requests;
 }
 
-void FeedV2InternalsPageHandler::SetUseFeedQueryRequestsForWebFeeds(
+void FeedV2InternalsPageHandler::SetUseFeedQueryRequests(
     const bool use_legacy) {
-  feed::SetUseFeedQueryRequestsForWebFeeds(use_legacy);
+  feed::SetUseFeedQueryRequests(use_legacy);
 }
 
 feed_internals::mojom::FeedOrder
diff --git a/chrome/browser/ui/webui/feed_internals/feedv2_internals_page_handler.h b/chrome/browser/ui/webui/feed_internals/feedv2_internals_page_handler.h
index 35d759b9..34efba4c 100644
--- a/chrome/browser/ui/webui/feed_internals/feedv2_internals_page_handler.h
+++ b/chrome/browser/ui/webui/feed_internals/feedv2_internals_page_handler.h
@@ -46,14 +46,14 @@
   void OverrideDiscoverApiEndpoint(const GURL& endpoint_url) override;
   void OverrideFeedStreamData(const std::vector<uint8_t>& data) override;
   void SetWebFeedFollowIntroDebugEnabled(const bool enabled) override;
-  void SetUseFeedQueryRequestsForWebFeeds(const bool use_legacy) override;
+  void SetUseFeedQueryRequests(const bool use_legacy) override;
   void SetFollowingFeedOrder(
       const feed_internals::mojom::FeedOrder new_order) override;
 
  private:
   bool IsFeedAllowed();
   bool IsWebFeedFollowIntroDebugEnabled();
-  bool ShouldUseFeedQueryRequestsForWebFeeds();
+  bool ShouldUseFeedQueryRequests();
   feed_internals::mojom::FeedOrder GetFollowingFeedOrder();
 
   mojo::Receiver<feed_internals::mojom::PageHandler> receiver_;
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc
index 7db11fbc..18cab3a 100644
--- a/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc
+++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc
@@ -156,7 +156,7 @@
       PrintBackend::CreateInstance(locale));
 
   PrinterList printer_list;
-  mojom::ResultCode result = print_backend->EnumeratePrinters(&printer_list);
+  mojom::ResultCode result = print_backend->EnumeratePrinters(printer_list);
   if (result != mojom::ResultCode::kSuccess) {
     PRINTER_LOG(ERROR) << "Failure enumerating local printers, result: "
                        << result;
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
index 17c3374..af094de 100644
--- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
@@ -102,16 +102,16 @@
 }
 
 // Returns the list of |printers| formatted as a CupsPrintersList.
-base::Value BuildCupsPrintersList(const std::vector<Printer>& printers) {
-  base::Value printers_list(base::Value::Type::LIST);
+base::Value::Dict BuildCupsPrintersList(const std::vector<Printer>& printers) {
+  base::Value::List printers_list;
   for (const Printer& printer : printers) {
     // Some of these printers could be invalid but we want to allow the user
     // to edit them. crbug.com/778383
     printers_list.Append(GetCupsPrinterInfo(printer));
   }
 
-  base::Value response(base::Value::Type::DICTIONARY);
-  response.SetKey("printerList", std::move(printers_list));
+  base::Value::Dict response;
+  response.Set("printerList", std::move(printers_list));
   return response;
 }
 
@@ -383,8 +383,8 @@
   std::vector<Printer> printers =
       printers_manager_->GetPrinters(PrinterClass::kSaved);
 
-  auto response = BuildCupsPrintersList(printers);
-  ResolveJavascriptCallback(base::Value(callback_id), response);
+  ResolveJavascriptCallback(base::Value(callback_id),
+                            base::Value(BuildCupsPrintersList(printers)));
 }
 
 void CupsPrintersHandler::HandleGetCupsEnterprisePrintersList(
@@ -397,8 +397,8 @@
   std::vector<Printer> printers =
       printers_manager_->GetPrinters(PrinterClass::kEnterprise);
 
-  auto response = BuildCupsPrintersList(printers);
-  ResolveJavascriptCallback(base::Value(callback_id), response);
+  ResolveJavascriptCallback(base::Value(callback_id),
+                            base::Value(BuildCupsPrintersList(printers)));
 }
 
 void CupsPrintersHandler::HandleUpdateCupsPrinter(
@@ -551,7 +551,7 @@
   // the rest.
   PRINTER_LOG(EVENT) << "Could not query printer.  Fallback to asking the user";
   RejectJavascriptCallback(base::Value(callback_id),
-                           GetCupsPrinterInfo(printer));
+                           base::Value(GetCupsPrinterInfo(printer)));
 }
 
 void CupsPrintersHandler::OnAutoconfQueried(
@@ -812,7 +812,7 @@
                           "Fall back to manual.";
     // Could not set up printer.  Asking user for manufacturer data.
     RejectJavascriptCallback(base::Value(callback_id),
-                             GetCupsPrinterInfo(printer));
+                             base::Value(GetCupsPrinterInfo(printer)));
   }
 }
 
@@ -1029,14 +1029,14 @@
       UpdateDiscoveredPrinters();
       break;
     case PrinterClass::kSaved: {
-      auto printers_list = BuildCupsPrintersList(printers);
-      FireWebUIListener("on-saved-printers-changed", printers_list);
+      FireWebUIListener("on-saved-printers-changed",
+                        base::Value(BuildCupsPrintersList(printers)));
       break;
     }
     case PrinterClass::kEnterprise:
-      auto enterprise_printers_list = BuildCupsPrintersList(printers);
       FireWebUIListener("on-enterprise-printers-changed",
-                        enterprise_printers_list);
+                        base::Value(BuildCupsPrintersList(printers)));
+      break;
   }
 }
 
@@ -1107,7 +1107,7 @@
   // directly, so we have to fall back to manual configuration here.
   if (printer->IsUsbProtocol()) {
     RejectJavascriptCallback(base::Value(callback_id),
-                             GetCupsPrinterInfo(*printer));
+                             base::Value(GetCupsPrinterInfo(*printer)));
     return;
   }
 
@@ -1235,7 +1235,7 @@
   PRINTER_LOG(EVENT) << "Request make and model from user";
   // If it's not an IPP printer, the user must choose a PPD.
   RejectJavascriptCallback(base::Value(callback_id),
-                           GetCupsPrinterInfo(printer));
+                           base::Value(GetCupsPrinterInfo(printer)));
 }
 
 void CupsPrintersHandler::HandleQueryPrintServer(
@@ -1315,8 +1315,8 @@
   server_printers_fetcher_.reset();
 
   // Create result value and finish the callback.
-  base::Value result_dict = BuildCupsPrintersList(printers);
-  ResolveJavascriptCallback(base::Value(callback_id), result_dict);
+  ResolveJavascriptCallback(base::Value(callback_id),
+                            base::Value(BuildCupsPrintersList(printers)));
 }
 
 void CupsPrintersHandler::HandleOpenPrintManagementApp(
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 81a87a5..d080325 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1655207804-0abcd90f44ccd89ac51f969b2567acb48919e9c0.profdata
+chrome-linux-main-1655229557-36aeb1dcde852e0e6daabaedec9aed25e8446d58.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 49c6a6d3..9dab6e3 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1655207804-b62733c21a998e4abe9ff8b80ba2710e67e7784a.profdata
+chrome-mac-main-1655229557-2e41633d7cf2398cd102dfca76172e280ea23daa.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index eaeb71a..f04ed15 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1655207804-26d325bfbe5071d5ca06e216b4cf2331aaf34b13.profdata
+chrome-win32-main-1655229557-066d5add5fce3d3ed8e49b23efab1500633c1555.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 688dc9d..3a36d5a 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1655207804-ffdc848710727fd771a04d10cb14690d174a60e4.profdata
+chrome-win64-main-1655229557-734cbdd8045e65c1312bc314b73ee12f3fafdbb4.profdata
diff --git a/chrome/common/net/x509_certificate_model.cc b/chrome/common/net/x509_certificate_model.cc
index b93adb2..bc7faee 100644
--- a/chrome/common/net/x509_certificate_model.cc
+++ b/chrome/common/net/x509_certificate_model.cc
@@ -277,13 +277,42 @@
 constexpr auto kNameStringHandling =
     net::X509NameAttribute::PrintableStringHandling::kAsUTF8Hack;
 
-std::string ProcessRawBytes(net::der::Input data) {
-  return x509_certificate_model::ProcessRawBytes(data.UnsafeData(),
-                                                 data.Length());
+std::string ProcessRawBytesWithSeparators(const unsigned char* data,
+                                          size_t data_length,
+                                          char hex_separator,
+                                          char line_separator) {
+  static const char kHexChars[] = "0123456789ABCDEF";
+
+  // Each input byte creates two output hex characters + a space or newline,
+  // except for the last byte.
+  std::string ret;
+  size_t kMin = 0U;
+
+  if (!data_length)
+    return std::string();
+
+  ret.reserve(std::max(kMin, data_length * 3 - 1));
+
+  for (size_t i = 0; i < data_length; ++i) {
+    unsigned char b = data[i];
+    ret.push_back(kHexChars[(b >> 4) & 0xf]);
+    ret.push_back(kHexChars[b & 0xf]);
+    if (i + 1 < data_length) {
+      if ((i + 1) % 16 == 0)
+        ret.push_back(line_separator);
+      else
+        ret.push_back(hex_separator);
+    }
+  }
+  return ret;
 }
 
 std::string ProcessRawBytes(base::span<const uint8_t> data) {
-  return x509_certificate_model::ProcessRawBytes(data.data(), data.size());
+  return ProcessRawBytesWithSeparators(data.data(), data.size(), ' ', '\n');
+}
+
+std::string ProcessRawBytes(net::der::Input data) {
+  return ProcessRawBytes(data.AsSpan());
 }
 
 OptionalStringOrError FindAttributeOfType(
@@ -1213,13 +1242,13 @@
 std::string X509CertificateModel::HashCertSHA256WithSeparators() const {
   auto hash =
       crypto::SHA256Hash(net::x509_util::CryptoBufferAsSpan(cert_data_.get()));
-  return ProcessRawBytes(hash.data(), hash.size());
+  return ProcessRawBytes(hash);
 }
 
 std::string X509CertificateModel::HashCertSHA1WithSeparators() const {
   auto hash =
       base::SHA1HashSpan(net::x509_util::CryptoBufferAsSpan(cert_data_.get()));
-  return ProcessRawBytes(hash.data(), hash.size());
+  return ProcessRawBytes(hash);
 }
 
 std::string X509CertificateModel::GetTitle() const {
@@ -1512,50 +1541,6 @@
                                    output16);
 }
 
-// TODO(https://crbug.com/953425): move to anonymous namespace once
-// x509_certificate_model_nss is removed.
-std::string ProcessRawBytesWithSeparators(const unsigned char* data,
-                                          size_t data_length,
-                                          char hex_separator,
-                                          char line_separator) {
-  static const char kHexChars[] = "0123456789ABCDEF";
-
-  // Each input byte creates two output hex characters + a space or newline,
-  // except for the last byte.
-  std::string ret;
-  size_t kMin = 0U;
-
-  if (!data_length)
-    return std::string();
-
-  ret.reserve(std::max(kMin, data_length * 3 - 1));
-
-  for (size_t i = 0; i < data_length; ++i) {
-    unsigned char b = data[i];
-    ret.push_back(kHexChars[(b >> 4) & 0xf]);
-    ret.push_back(kHexChars[b & 0xf]);
-    if (i + 1 < data_length) {
-      if ((i + 1) % 16 == 0)
-        ret.push_back(line_separator);
-      else
-        ret.push_back(hex_separator);
-    }
-  }
-  return ret;
-}
-
-// TODO(https://crbug.com/953425): move to anonymous namespace once
-// x509_certificate_model_nss is removed.
-std::string ProcessRawBytes(const unsigned char* data, size_t data_length) {
-  return ProcessRawBytesWithSeparators(data, data_length, ' ', '\n');
-}
-
-// TODO(https://crbug.com/953425): move to anonymous namespace once
-// x509_certificate_model_nss is removed.
-std::string ProcessRawBits(const unsigned char* data, size_t data_length) {
-  return ProcessRawBytes(data, (data_length + 7) / 8);
-}
-
 std::string ProcessRawSubjectPublicKeyInfo(base::span<const uint8_t> spki_der) {
   bssl::UniquePtr<EVP_PKEY> public_key;
   if (!net::ParsePublicKey(net::der::Input(spki_der.data(), spki_der.size()),
diff --git a/chrome/common/net/x509_certificate_model.h b/chrome/common/net/x509_certificate_model.h
index 3a52e58..caf27fcb 100644
--- a/chrome/common/net/x509_certificate_model.h
+++ b/chrome/common/net/x509_certificate_model.h
@@ -142,20 +142,6 @@
 // decoded U-label form.  Otherwise, the string will be returned as is.
 std::string ProcessIDN(const std::string& input);
 
-// Format a buffer as |hex_separator| separated string, with 16 bytes on each
-// line separated using |line_separator|.
-std::string ProcessRawBytesWithSeparators(const unsigned char* data,
-                                          size_t data_length,
-                                          char hex_separator,
-                                          char line_separator);
-
-// Format a buffer as a space separated string, with 16 bytes on each line.
-std::string ProcessRawBytes(const unsigned char* data, size_t data_length);
-
-// Format a buffer as a space separated string, with 16 bytes on each line.
-// |data_length| is the length in bits.
-std::string ProcessRawBits(const unsigned char* data, size_t data_length);
-
 // Parses |public_key_spki_der| as a DER-encoded X.509 SubjectPublicKeyInfo,
 // then formats the public key as a string for displaying. Returns an empty
 // string on error.
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 5d33e8a..a90f742 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -3043,8 +3043,6 @@
     "lacros.settings.a11y.virtual_keyboard";
 #endif
 
-const char kBackgroundTracingLastUpload[] = "background_tracing.last_upload";
-
 const char kAllowDinosaurEasterEgg[] = "allow_dinosaur_easter_egg";
 
 #if BUILDFLAG(IS_ANDROID)
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index a10a186..9fb77863 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -1022,8 +1022,6 @@
 extern const char kLacrosDockedMagnifierEnabled[];
 #endif
 
-extern const char kBackgroundTracingLastUpload[];
-
 extern const char kAllowDinosaurEasterEgg[];
 
 #if BUILDFLAG(IS_ANDROID)
diff --git a/chrome/renderer/printing/chrome_print_render_frame_helper_delegate.cc b/chrome/renderer/printing/chrome_print_render_frame_helper_delegate.cc
index 214ff93..b0177ef 100644
--- a/chrome/renderer/printing/chrome_print_render_frame_helper_delegate.cc
+++ b/chrome/renderer/printing/chrome_print_render_frame_helper_delegate.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/renderer/printing/chrome_print_render_frame_helper_delegate.h"
 
+#include <utility>
 #include <vector>
 
 #include "base/check.h"
@@ -60,9 +61,9 @@
     // instructs the PDF plugin to print. This is to make window.print() on a
     // PDF plugin document correctly print the PDF. See
     // https://crbug.com/448720.
-    base::DictionaryValue message;
-    message.SetStringKey("type", "print");
-    post_message_support->PostMessageFromValue(message);
+    base::Value::Dict message;
+    message.Set("type", "print");
+    post_message_support->PostMessageFromValue(base::Value(std::move(message)));
     return true;
   }
 #endif  // BUILDFLAG(ENABLE_PDF)
diff --git a/chrome/services/printing/print_backend_service_impl.cc b/chrome/services/printing/print_backend_service_impl.cc
index 48c8592..596ff08 100644
--- a/chrome/services/printing/print_backend_service_impl.cc
+++ b/chrome/services/printing/print_backend_service_impl.cc
@@ -412,7 +412,7 @@
   }
 
   PrinterList printer_list;
-  mojom::ResultCode result = print_backend_->EnumeratePrinters(&printer_list);
+  mojom::ResultCode result = print_backend_->EnumeratePrinters(printer_list);
   if (result != mojom::ResultCode::kSuccess) {
     std::move(callback).Run(mojom::PrinterListResult::NewResultCode(result));
     return;
diff --git a/chrome/test/data/web_apps/site_b/basic.json b/chrome/test/data/web_apps/site_b/basic.json
index 36a63d10..8cefecfe 100644
--- a/chrome/test/data/web_apps/site_b/basic.json
+++ b/chrome/test/data/web_apps/site_b/basic.json
@@ -20,7 +20,8 @@
       "action": "/web_apps/site_b/text_handler.html",
       "name": "Plain Text",
       "accept": {
-        "text/plain": [".txt", ".md", ".csv", ".text"]
+        "text/plain": [".txt", ".md", ".csv", ".text"],
+        "application/octet-stream": [".qux", ".quux"]
       }
     },
     {
diff --git a/chrome/test/data/webrtc/region_capture_embedded.html b/chrome/test/data/webrtc/region_capture_embedded.html
index 3f1cdce1..03591155 100644
--- a/chrome/test/data/webrtc/region_capture_embedded.html
+++ b/chrome/test/data/webrtc/region_capture_embedded.html
@@ -19,11 +19,17 @@
       }
     </script>
   </head>
-  <body onload="reportEmbeddingSuccess();">
+  <body onload="onLoad();">
     <div id="div">
       <!-- This DIV is just a convenient target for cropTargetFromElement. -->
-      <h1>Region Capture Test - Page 1 (Embedded)</h1>
+      <p id="p_id">0</p>
     </div>
-    <iframe id="mailman_frame"></iframe>
+    <iframe id="mailman_frame" hidden></iframe>
+    <script>
+      function onLoad() {
+        animate(document.getElementById('p_id'));
+        reportEmbeddingSuccess();
+      }
+    </script>
   </body>
 </html>
diff --git a/chrome/test/data/webrtc/region_capture_helpers.js b/chrome/test/data/webrtc/region_capture_helpers.js
index 4e888f69..2ccdcd1 100644
--- a/chrome/test/data/webrtc/region_capture_helpers.js
+++ b/chrome/test/data/webrtc/region_capture_helpers.js
@@ -65,6 +65,12 @@
   }
 }
 
+function animate(element) {
+  const animationCallback = function() {
+    element.innerHTML = parseInt(element.innerHTML) + 1;
+  };
+  setInterval(animationCallback, 20);
+}
 
 /////////////////////////////////////////
 // Main actions from C++ test fixture. //
diff --git a/chrome/test/data/webrtc/region_capture_main.html b/chrome/test/data/webrtc/region_capture_main.html
index e521ac3..50b7b6bc3 100644
--- a/chrome/test/data/webrtc/region_capture_main.html
+++ b/chrome/test/data/webrtc/region_capture_main.html
@@ -54,13 +54,18 @@
       }
     </script>
   </head>
-  <body>
+  <body onload="onLoad();">
     <div id="div">
       <!-- This DIV is just a convenient target for cropTargetFromElement. -->
-      <h1>Region Capture Test - Page 1 (Main)</h1>
-      <br/>
+      <p id="p_id">0</p>
     </div>
+    <br />
     <iframe id="embedded_frame" allow="display-capture *"></iframe>
-    <iframe id="mailman_frame"></iframe>
+    <iframe id="mailman_frame" hidden></iframe>
+    <script>
+      function onLoad() {
+        animate(document.getElementById('p_id'));
+      }
+    </script>
   </body>
 </html>
diff --git a/chrome/test/data/webrtc/region_capture_other_embedded.html b/chrome/test/data/webrtc/region_capture_other_embedded.html
index 3c1e6f4..ae0f488 100644
--- a/chrome/test/data/webrtc/region_capture_other_embedded.html
+++ b/chrome/test/data/webrtc/region_capture_other_embedded.html
@@ -14,11 +14,17 @@
       }
     </script>
   </head>
-  <body onload="reportEmbeddingSuccess();">
+  <body onload="onLoad();">
     <div id="div">
       <!-- This DIV is just a convenient target for cropTargetFromElement. -->
-      <h1>Region Capture Test - Page 2 (Embedded)</h1>
+      <p id="p_id">0</p>
     </div>
-    <iframe id="mailman_frame"></iframe>
+    <iframe id="mailman_frame" hidden></iframe>
+    <script>
+      function onLoad() {
+        animate(document.getElementById('p_id'));
+        reportEmbeddingSuccess();
+      }
+    </script>
   </body>
 </html>
diff --git a/chrome/test/data/webrtc/region_capture_other_main.html b/chrome/test/data/webrtc/region_capture_other_main.html
index 8ad30d5e..0b69455 100644
--- a/chrome/test/data/webrtc/region_capture_other_main.html
+++ b/chrome/test/data/webrtc/region_capture_other_main.html
@@ -10,13 +10,18 @@
       setRole("top-level");
     </script>
   </head>
-  <body>
+  <body onload="onLoad();">
     <div id="div">
       <!-- This DIV is just a convenient target for cropTargetFromElement. -->
-      <h1>Region Capture Test - Page 2 (Main)</h1>
-      <br/>
+      <p id="p_id">0</p>
+      <br />
       <iframe id="embedded_frame" allow="display-capture *"></iframe>
     </div>
-    <iframe id="mailman_frame"></iframe>
+    <iframe id="mailman_frame" hidden></iframe>
+    <script>
+      function onLoad() {
+        animate(document.getElementById('p_id'));
+      }
+    </script>
   </body>
 </html>
diff --git a/chrome/test/data/webui/chromeos/scanning/scanning_app_browsertest.js b/chrome/test/data/webui/chromeos/scanning/scanning_app_browsertest.js
index 8f21bff..1c518ec 100644
--- a/chrome/test/data/webui/chromeos/scanning/scanning_app_browsertest.js
+++ b/chrome/test/data/webui/chromeos/scanning/scanning_app_browsertest.js
@@ -45,7 +45,7 @@
 ];
 
 // Flaky. See crbug.com/1334465
-TEST_F('ScanningAppBrowserTest', 'DISABLED_All', function() {
+TEST_F('ScanningAppBrowserTest', 'All', function() {
   assertDeepEquals(
       debug_suites_list, test_suites_list,
       'List of registered tests suites and debug suites do not match.\n' +
diff --git a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js
index 88a7fd3..4213078 100644
--- a/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js
+++ b/chrome/test/data/webui/cr_components/chromeos/cr_components_chromeos_v3_browsertest.js
@@ -109,6 +109,7 @@
         enabled: [
           'chromeos::features::kCellularUseAttachApn',
           'chromeos::features::kESimPolicy',
+          'chromeos::features::kSimLockPolicy',
           'ash::features::kBluetoothRevamp',
         ],
       };
diff --git a/chrome/test/data/webui/cr_components/chromeos/network/network_siminfo_test.js b/chrome/test/data/webui/cr_components/chromeos/network/network_siminfo_test.js
index ee002506..c508041 100644
--- a/chrome/test/data/webui/cr_components/chromeos/network/network_siminfo_test.js
+++ b/chrome/test/data/webui/cr_components/chromeos/network/network_siminfo_test.js
@@ -142,6 +142,55 @@
     verifyExistsAndClickOpensDialog('changePinButton');
   });
 
+  test('Policy controlled SIM lock setting', async () => {
+    const getChangePinButton = () => simInfo.$$('#changePinButton');
+    const getSimLockButton = () => simInfo.$$('#simLockButton');
+    const getSimLockButtonTooltip = () => simInfo.$$('#inActiveSimLockTooltip');
+
+    simInfo.globalPolicy = {
+      allowCellularSimLock: false,
+    };
+    await flushAsync();
+
+    // Unlocked primary SIM with lock setting enabled. Change button should not
+    // be visible, and toggle should be visible, on, and enabled to allow users
+    // to turn off the SIM Lock setting.
+    updateDeviceState(
+        /*isPrimary=*/ true, /*lockEnabled=*/ true, /*isLocked=*/ false);
+    assertTrue(getChangePinButton().hidden);
+    assertFalse(getSimLockButton().disabled);
+    assertTrue(getSimLockButton().checked);
+    assertFalse(!!getSimLockButtonTooltip());
+
+    // Unlocked primary SIM with lock setting disabled. Change button should not
+    // be visible, and toggle should be visible, off, and disabled to prevent
+    // users to turn on the SIM Lock setting.
+    updateDeviceState(
+        /*isPrimary=*/ true, /*lockEnabled=*/ false, /*isLocked=*/ false);
+    assertTrue(getChangePinButton().hidden);
+    assertTrue(getSimLockButton().disabled);
+    assertFalse(getSimLockButton().checked);
+    assertFalse(!!getSimLockButtonTooltip());
+
+    // Non-primary unlocked SIM with lock setting enabled. Change button should
+    // be hidden, and toggle should be visible, off, and disabled.
+    updateDeviceState(
+        /*isPrimary=*/ false, /*lockEnabled=*/ true, /*isLocked=*/ false);
+    assertTrue(getChangePinButton().hidden);
+    assertTrue(getSimLockButton().disabled);
+    assertFalse(getSimLockButton().checked);
+    assertTrue(!!getSimLockButtonTooltip());
+
+    // Non-primary unlocked SIM with lock setting disabled. Change button should
+    // be hidden, and toggle should be visible, off, and disabled.
+    updateDeviceState(
+        /*isPrimary=*/ false, /*lockEnabled=*/ false, /*isLocked=*/ false);
+    assertTrue(getChangePinButton().hidden);
+    assertTrue(getSimLockButton().disabled);
+    assertFalse(getSimLockButton().checked);
+    assertTrue(!!getSimLockButtonTooltip());
+  });
+
   test('Primary vs. non-primary SIM', function() {
     const getChangePinButton = () => simInfo.$$('#changePinButton');
     const getSimLockButton = () => simInfo.$$('#simLockButton');
diff --git a/chrome/test/data/webui/settings/chromeos/settings_scheduler_slider_test.js b/chrome/test/data/webui/settings/chromeos/settings_scheduler_slider_test.js
index 5d65dc1..51f7569 100644
--- a/chrome/test/data/webui/settings/chromeos/settings_scheduler_slider_test.js
+++ b/chrome/test/data/webui/settings/chromeos/settings_scheduler_slider_test.js
@@ -61,15 +61,15 @@
   test.skip('pref value update time string', function() {
     // Test that the slider time string is updated after the pref is
     // saved.
-    assertTrue(!!slider.$$('#startLabel'));
-    assertTrue(!!slider.$$('#endLabel'));
+    assertTrue(!!slider.shadowRoot.querySelector('#startLabel'));
+    assertTrue(!!slider.shadowRoot.querySelector('#endLabel'));
 
     const getStartTimeString = () => {
-      return slider.$$('#startLabel').innerHTML.trim();
+      return slider.shadowRoot.querySelector('#startLabel').innerHTML.trim();
     };
 
     const getEndTimeString = () => {
-      return slider.$$('#endLabel').innerHTML.trim();
+      return slider.shadowRoot.querySelector('#endLabel').innerHTML.trim();
     };
 
     assertEquals('1:00 AM', getStartTimeString());
@@ -109,15 +109,15 @@
   // daylight savings is active.
   test.skip('pref value update aria label', function() {
     // Test that the aria label is updated after the pref is saved.
-    assertTrue(!!slider.$$('#startKnob'));
-    assertTrue(!!slider.$$('#endKnob'));
+    assertTrue(!!slider.shadowRoot.querySelector('#startKnob'));
+    assertTrue(!!slider.shadowRoot.querySelector('#endKnob'));
 
     const getStartTimeAriaLabel = () => {
-      return slider.$$('#startKnob').ariaLabel.trim();
+      return slider.shadowRoot.querySelector('#startKnob').ariaLabel.trim();
     };
 
     const getEndTimeAriaLabel = () => {
-      return slider.$$('#endKnob').ariaLabel.trim();
+      return slider.shadowRoot.querySelector('#endKnob').ariaLabel.trim();
     };
 
     assertEquals(slider.i18n('startTime', '1:00 AM'), getStartTimeAriaLabel());
diff --git a/chrome/test/data/webui/settings/safety_check_page_test.ts b/chrome/test/data/webui/settings/safety_check_page_test.ts
index add7586..0fbeb7b 100644
--- a/chrome/test/data/webui/settings/safety_check_page_test.ts
+++ b/chrome/test/data/webui/settings/safety_check_page_test.ts
@@ -4,6 +4,7 @@
 
 // clang-format off
 import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {HatsBrowserProxyImpl, LifetimeBrowserProxyImpl, MetricsBrowserProxyImpl, OpenWindowProxyImpl, PasswordCheckReferrer, PasswordManagerImpl, Router, routes, SafetyCheckBrowserProxy, SafetyCheckBrowserProxyImpl, SafetyCheckCallbackConstants, SafetyCheckChromeCleanerStatus, SafetyCheckExtensionsStatus, SafetyCheckIconStatus, SafetyCheckInteractions, SafetyCheckParentStatus, SafetyCheckPasswordsStatus, SafetyCheckSafeBrowsingStatus, SafetyCheckUpdatesStatus, SettingsSafetyCheckChildElement, SettingsSafetyCheckExtensionsChildElement, SettingsSafetyCheckPageElement, SettingsSafetyCheckPasswordsChildElement, SettingsSafetyCheckSafeBrowsingChildElement, SettingsSafetyCheckUpdatesChildElement, TrustSafetyInteraction} from 'chrome://settings/settings.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
@@ -18,6 +19,10 @@
 // clang-format on
 
 const testDisplayString = 'Test display string';
+const passwordsString =
+    loadTimeData.getBoolean('unifiedPasswordManagerEnabled') ?
+    'Password Manager' :
+    'Passwords';
 
 /**
  * Fire a safety check parent event.
@@ -539,7 +544,7 @@
     assertSafetyCheckChild({
       page: page,
       iconStatus: SafetyCheckIconStatus.RUNNING,
-      label: 'Passwords',
+      label: passwordsString,
     });
   });
 
@@ -549,7 +554,7 @@
     assertSafetyCheckChild({
       page: page,
       iconStatus: SafetyCheckIconStatus.SAFE,
-      label: 'Passwords',
+      label: passwordsString,
       rowClickable: true,
     });
 
@@ -576,7 +581,7 @@
     assertSafetyCheckChild({
       page: page,
       iconStatus: SafetyCheckIconStatus.WARNING,
-      label: 'Passwords',
+      label: passwordsString,
       buttonLabel: 'Review',
       buttonAriaLabel: 'Review passwords',
       buttonClass: 'action-button',
@@ -614,7 +619,7 @@
     assertSafetyCheckChild({
       page: page,
       iconStatus: SafetyCheckIconStatus.INFO,
-      label: 'Passwords',
+      label: passwordsString,
       rowClickable: true,
     });
 
@@ -651,7 +656,7 @@
           assertSafetyCheckChild({
             page: page,
             iconStatus: SafetyCheckIconStatus.INFO,
-            label: 'Passwords',
+            label: passwordsString,
           });
           break;
         case SafetyCheckPasswordsStatus.QUOTA_LIMIT:
@@ -659,7 +664,7 @@
           assertSafetyCheckChild({
             page: page,
             iconStatus: SafetyCheckIconStatus.INFO,
-            label: 'Passwords',
+            label: passwordsString,
             rowClickable: true,
           });
           break;
diff --git a/chrome/updater/win/win_util.cc b/chrome/updater/win/win_util.cc
index 9ede349..b0f7a0e9 100644
--- a/chrome/updater/win/win_util.cc
+++ b/chrome/updater/win/win_util.cc
@@ -168,6 +168,28 @@
   return foreground_parent.Detach();
 }
 
+// Compares the OS, service pack, and build numbers using `::VerifyVersionInfo`,
+// in accordance with `type_mask` and `oper`.
+bool CompareOSVersionsInternal(const OSVERSIONINFOEX& os,
+                               DWORD type_mask,
+                               BYTE oper) {
+  DCHECK(type_mask);
+  DCHECK(oper);
+
+  ULONGLONG cond_mask = 0;
+  cond_mask = ::VerSetConditionMask(cond_mask, VER_MAJORVERSION, oper);
+  cond_mask = ::VerSetConditionMask(cond_mask, VER_MINORVERSION, oper);
+  cond_mask = ::VerSetConditionMask(cond_mask, VER_SERVICEPACKMAJOR, oper);
+  cond_mask = ::VerSetConditionMask(cond_mask, VER_SERVICEPACKMINOR, oper);
+  cond_mask = ::VerSetConditionMask(cond_mask, VER_BUILDNUMBER, oper);
+
+  // `::VerifyVersionInfo` could return `FALSE` due to an error other than
+  // `ERROR_OLD_WIN_VERSION`. We do not handle that case here.
+  // https://msdn.microsoft.com/ms725492.
+  OSVERSIONINFOEX os_in = os;
+  return !!::VerifyVersionInfo(&os_in, type_mask, cond_mask);
+}
+
 }  // namespace
 
 NamedObjectAttributes::NamedObjectAttributes() = default;
@@ -772,4 +794,18 @@
   return os_out;
 }
 
+bool CompareOSVersions(const OSVERSIONINFOEX& os_version, BYTE oper) {
+  DCHECK(oper);
+
+  const DWORD os_sp_type_mask = VER_MAJORVERSION | VER_MINORVERSION |
+                                VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR;
+  const DWORD build_number_type_mask = VER_BUILDNUMBER;
+
+  // If the OS and the service pack match, return the build number comparison.
+  return CompareOSVersionsInternal(os_version, os_sp_type_mask, VER_EQUAL)
+             ? CompareOSVersionsInternal(os_version, build_number_type_mask,
+                                         oper)
+             : CompareOSVersionsInternal(os_version, os_sp_type_mask, oper);
+}
+
 }  // namespace updater
diff --git a/chrome/updater/win/win_util.h b/chrome/updater/win/win_util.h
index 70a9d1c..85fa5c5 100644
--- a/chrome/updater/win/win_util.h
+++ b/chrome/updater/win/win_util.h
@@ -259,6 +259,12 @@
 // Returns an OSVERSIONINFOEX for the current OS version.
 absl::optional<OSVERSIONINFOEX> GetOSVersion();
 
+// Compares the current OS to the supplied version.  The value of `oper` should
+// be one of the predicate values from `::VerSetConditionMask()`, for example,
+// `VER_GREATER` or `VER_GREATER_EQUAL`. `os_version` is usually from a prior
+// call to `::GetVersionEx` or `::RtlGetVersion`.
+bool CompareOSVersions(const OSVERSIONINFOEX& os, BYTE oper);
+
 }  // namespace updater
 
 #endif  // CHROME_UPDATER_WIN_WIN_UTIL_H_
diff --git a/chrome/updater/win/win_util_unittest.cc b/chrome/updater/win/win_util_unittest.cc
index 9bcb6f66..00610051 100644
--- a/chrome/updater/win/win_util_unittest.cc
+++ b/chrome/updater/win/win_util_unittest.cc
@@ -159,4 +159,100 @@
   EXPECT_EQ(rtl_os_version->wReserved, os.wReserved);
 }
 
+TEST(WinUtil, CompareOSVersions_SameAsCurrent) {
+  absl::optional<OSVERSIONINFOEX> this_os = GetOSVersion();
+  ASSERT_NE(this_os, absl::nullopt);
+
+  EXPECT_TRUE(CompareOSVersions(this_os.value(), VER_EQUAL));
+  EXPECT_TRUE(CompareOSVersions(this_os.value(), VER_GREATER_EQUAL));
+  EXPECT_FALSE(CompareOSVersions(this_os.value(), VER_GREATER));
+  EXPECT_FALSE(CompareOSVersions(this_os.value(), VER_LESS));
+  EXPECT_TRUE(CompareOSVersions(this_os.value(), VER_LESS_EQUAL));
+}
+
+TEST(WinUtil, CompareOSVersions_NewBuildNumber) {
+  absl::optional<OSVERSIONINFOEX> prior_os = GetOSVersion();
+  ASSERT_NE(prior_os, absl::nullopt);
+  ASSERT_GT(prior_os->dwBuildNumber, 0UL);
+  --prior_os->dwBuildNumber;
+
+  EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_EQUAL));
+  EXPECT_TRUE(CompareOSVersions(prior_os.value(), VER_GREATER_EQUAL));
+  EXPECT_TRUE(CompareOSVersions(prior_os.value(), VER_GREATER));
+  EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_LESS));
+  EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_LESS_EQUAL));
+}
+
+TEST(WinUtil, CompareOSVersions_NewMajor) {
+  absl::optional<OSVERSIONINFOEX> prior_os = GetOSVersion();
+  ASSERT_NE(prior_os, absl::nullopt);
+  ASSERT_GT(prior_os->dwMajorVersion, 0UL);
+  --prior_os->dwMajorVersion;
+
+  EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_EQUAL));
+  EXPECT_TRUE(CompareOSVersions(prior_os.value(), VER_GREATER_EQUAL));
+  EXPECT_TRUE(CompareOSVersions(prior_os.value(), VER_GREATER));
+  EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_LESS));
+  EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_LESS_EQUAL));
+}
+
+TEST(WinUtil, CompareOSVersions_NewMinor) {
+  absl::optional<OSVERSIONINFOEX> prior_os = GetOSVersion();
+  ASSERT_NE(prior_os, absl::nullopt);
+
+  // This test only runs if the current OS has a minor version.
+  if (prior_os->dwMinorVersion >= 1) {
+    --prior_os->dwMinorVersion;
+
+    EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_EQUAL));
+    EXPECT_TRUE(CompareOSVersions(prior_os.value(), VER_GREATER_EQUAL));
+    EXPECT_TRUE(CompareOSVersions(prior_os.value(), VER_GREATER));
+    EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_LESS));
+    EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_LESS_EQUAL));
+  }
+}
+
+TEST(WinUtil, CompareOSVersions_NewMajorWithLowerMinor) {
+  absl::optional<OSVERSIONINFOEX> prior_os = GetOSVersion();
+  ASSERT_NE(prior_os, absl::nullopt);
+  ASSERT_GT(prior_os->dwMajorVersion, 0UL);
+  --prior_os->dwMajorVersion;
+  ++prior_os->dwMinorVersion;
+
+  EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_EQUAL));
+  EXPECT_TRUE(CompareOSVersions(prior_os.value(), VER_GREATER_EQUAL));
+  EXPECT_TRUE(CompareOSVersions(prior_os.value(), VER_GREATER));
+  EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_LESS));
+  EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_LESS_EQUAL));
+}
+
+TEST(WinUtil, CompareOSVersions_OldMajor) {
+  absl::optional<OSVERSIONINFOEX> prior_os = GetOSVersion();
+  ASSERT_NE(prior_os, absl::nullopt);
+  ++prior_os->dwMajorVersion;
+
+  EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_EQUAL));
+  EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_GREATER_EQUAL));
+  EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_GREATER));
+  EXPECT_TRUE(CompareOSVersions(prior_os.value(), VER_LESS));
+  EXPECT_TRUE(CompareOSVersions(prior_os.value(), VER_LESS_EQUAL));
+}
+
+TEST(WinUtil, CompareOSVersions_OldMajorWithHigherMinor) {
+  absl::optional<OSVERSIONINFOEX> prior_os = GetOSVersion();
+  ASSERT_NE(prior_os, absl::nullopt);
+
+  // This test only runs if the current OS has a minor version.
+  if (prior_os->dwMinorVersion >= 1) {
+    ++prior_os->dwMajorVersion;
+    --prior_os->dwMinorVersion;
+
+    EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_EQUAL));
+    EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_GREATER_EQUAL));
+    EXPECT_FALSE(CompareOSVersions(prior_os.value(), VER_GREATER));
+    EXPECT_TRUE(CompareOSVersions(prior_os.value(), VER_LESS));
+    EXPECT_TRUE(CompareOSVersions(prior_os.value(), VER_LESS_EQUAL));
+  }
+}
+
 }  // namespace updater
diff --git a/chromecast/browser/accessibility/accessibility_service_impl.cc b/chromecast/browser/accessibility/accessibility_service_impl.cc
index 767d263..4423b53 100644
--- a/chromecast/browser/accessibility/accessibility_service_impl.cc
+++ b/chromecast/browser/accessibility/accessibility_service_impl.cc
@@ -103,7 +103,7 @@
   for (chromecast::CastWebContents* webview : webviews) {
     mojo::Remote<mojom::CastAccessibilityClient> accessibility_client;
     content::RenderFrameHost* render_frame_host =
-        webview->web_contents()->GetMainFrame();
+        webview->web_contents()->GetPrimaryMainFrame();
 
     if (!render_frame_host)
       continue;
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc
index 03136bb..43c890d 100644
--- a/chromecast/browser/cast_content_browser_client.cc
+++ b/chromecast/browser/cast_content_browser_client.cc
@@ -630,8 +630,8 @@
       base::BindOnce(
           &CastContentBrowserClient::SelectClientCertificateOnIOThread,
           base::Unretained(this), requesting_url, session_id,
-          web_contents->GetMainFrame()->GetProcess()->GetID(),
-          web_contents->GetMainFrame()->GetRoutingID(),
+          web_contents->GetPrimaryMainFrame()->GetProcess()->GetID(),
+          web_contents->GetPrimaryMainFrame()->GetRoutingID(),
           base::SequencedTaskRunnerHandle::Get(),
           base::BindOnce(
               &content::ClientCertificateDelegate::ContinueWithCertificate,
diff --git a/chromecast/browser/cast_web_contents_browsertest.cc b/chromecast/browser/cast_web_contents_browsertest.cc
index 73f04b6..b41e09d 100644
--- a/chromecast/browser/cast_web_contents_browsertest.cc
+++ b/chromecast/browser/cast_web_contents_browsertest.cc
@@ -473,11 +473,11 @@
   ASSERT_TRUE(ExecJs(web_contents_.get(), script));
 
   ASSERT_EQ(2, (int)render_frames_.size());
-  auto it =
-      std::find_if(render_frames_.begin(), render_frames_.end(),
-                   [this](content::RenderFrameHost* frame) {
-                     return frame->GetParent() == web_contents_->GetMainFrame();
-                   });
+  auto it = std::find_if(render_frames_.begin(), render_frames_.end(),
+                         [this](content::RenderFrameHost* frame) {
+                           return frame->GetParent() ==
+                                  web_contents_->GetPrimaryMainFrame();
+                         });
   ASSERT_NE(render_frames_.end(), it);
   content::RenderFrameHost* sub_frame = *it;
   ASSERT_NE(nullptr, sub_frame);
@@ -490,8 +490,9 @@
   EXPECT_CALL(mock_cast_wc_observer_, PageStateChanged(_)).Times(0);
   EXPECT_CALL(mock_cast_wc_observer_, PageStopped(_, _)).Times(0);
   cast_web_contents_->DidFailLoad(
-      web_contents_->GetMainFrame(),
-      web_contents_->GetMainFrame()->GetLastCommittedURL(), net::ERR_ABORTED);
+      web_contents_->GetPrimaryMainFrame(),
+      web_contents_->GetPrimaryMainFrame()->GetLastCommittedURL(),
+      net::ERR_ABORTED);
 
   // ===========================================================================
   // Test: If main frame fails to load, page should enter ERROR state.
@@ -501,8 +502,9 @@
               PageStopped(PageState::ERROR, net::ERR_FAILED))
       .WillOnce(InvokeWithoutArgs([&]() { QuitRunLoop(); }));
   cast_web_contents_->DidFailLoad(
-      web_contents_->GetMainFrame(),
-      web_contents_->GetMainFrame()->GetLastCommittedURL(), net::ERR_FAILED);
+      web_contents_->GetPrimaryMainFrame(),
+      web_contents_->GetPrimaryMainFrame()->GetLastCommittedURL(),
+      net::ERR_FAILED);
   run_loop_->Run();
 }
 
diff --git a/chromecast/browser/cast_web_contents_impl.cc b/chromecast/browser/cast_web_contents_impl.cc
index 9710040..98968cf 100644
--- a/chromecast/browser/cast_web_contents_impl.cc
+++ b/chromecast/browser/cast_web_contents_impl.cc
@@ -162,9 +162,9 @@
   DCHECK(web_contents_);
   DCHECK(web_contents_->GetController().IsInitialNavigation());
   DCHECK(!web_contents_->IsLoading());
-  DCHECK(web_contents_->GetMainFrame());
+  DCHECK(web_contents_->GetPrimaryMainFrame());
 
-  main_process_host_ = web_contents_->GetMainFrame()->GetProcess();
+  main_process_host_ = web_contents_->GetPrimaryMainFrame()->GetProcess();
   DCHECK(main_process_host_);
   main_process_host_->AddObserver(this);
 
@@ -201,7 +201,7 @@
       switches::kCastAppBackgroundColor, SK_ColorBLACK));
 
   if (params_->enable_webui_bindings_permission) {
-    web_contents_->GetMainFrame()->AllowBindings(
+    web_contents_->GetPrimaryMainFrame()->AllowBindings(
         content::BINDINGS_POLICY_WEB_UI | content::BINDINGS_POLICY_MOJO_WEB_UI);
   }
 }
@@ -407,11 +407,11 @@
     base::OnceCallback<void(base::Value)> callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!web_contents_ || closing_ || !main_frame_loaded_ ||
-      !web_contents_->GetMainFrame())
+      !web_contents_->GetPrimaryMainFrame())
     return;
 
-  web_contents_->GetMainFrame()->ExecuteJavaScript(javascript,
-                                                   std::move(callback));
+  web_contents_->GetPrimaryMainFrame()->ExecuteJavaScript(javascript,
+                                                          std::move(callback));
 }
 
 void CastWebContentsImpl::ConnectToBindingsService(
@@ -450,12 +450,12 @@
 }
 
 void CastWebContentsImpl::GetMainFramePid(GetMainFramePidCallback cb) {
-  if (!web_contents_ || !web_contents_->GetMainFrame()) {
+  if (!web_contents_ || !web_contents_->GetPrimaryMainFrame()) {
     std::move(cb).Run(base::kNullProcessHandle);
     return;
   }
 
-  auto* rph = web_contents_->GetMainFrame()->GetProcess();
+  auto* rph = web_contents_->GetPrimaryMainFrame()->GetProcess();
   if (!rph || rph->GetProcess().Handle() == base::kNullProcessHandle) {
     std::move(cb).Run(base::kNullProcessHandle);
     return;
@@ -747,7 +747,7 @@
     const GURL& validated_url) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (page_state_ != PageState::LOADING || !web_contents_ ||
-      render_frame_host != web_contents_->GetMainFrame()) {
+      render_frame_host != web_contents_->GetPrimaryMainFrame()) {
     return;
   }
 
@@ -884,7 +884,8 @@
     content::RenderFrameHost* render_frame_host,
     const content::GlobalRequestID& request_id,
     const blink::mojom::ResourceLoadInfo& resource_load_info) {
-  if (!web_contents_ || render_frame_host != web_contents_->GetMainFrame())
+  if (!web_contents_ ||
+      render_frame_host != web_contents_->GetPrimaryMainFrame())
     return;
   int net_error = resource_load_info.net_error;
   if (net_error == net::OK)
diff --git a/chromecast/browser/webview/cast_app_controller.cc b/chromecast/browser/webview/cast_app_controller.cc
index 0d785a93..52581b4 100644
--- a/chromecast/browser/webview/cast_app_controller.cc
+++ b/chromecast/browser/webview/cast_app_controller.cc
@@ -23,7 +23,7 @@
   std::unique_ptr<webview::WebviewResponse> response =
       std::make_unique<webview::WebviewResponse>();
 
-  auto ax_id = contents->GetMainFrame()->GetAXTreeID().ToString();
+  auto ax_id = contents->GetPrimaryMainFrame()->GetAXTreeID().ToString();
   response->mutable_create_response()
       ->mutable_accessibility_info()
       ->set_ax_tree_id(ax_id);
diff --git a/chromecast/browser/webview/web_content_controller.cc b/chromecast/browser/webview/web_content_controller.cc
index be6334ab..53f8459f 100644
--- a/chromecast/browser/webview/web_content_controller.cc
+++ b/chromecast/browser/webview/web_content_controller.cc
@@ -448,7 +448,7 @@
 void WebContentController::HandleEvaluateJavascript(
     int64_t id,
     const webview::EvaluateJavascriptRequest& request) {
-  GetWebContents()->GetMainFrame()->ExecuteJavaScript(
+  GetWebContents()->GetPrimaryMainFrame()->ExecuteJavaScript(
       base::UTF8ToUTF16(request.javascript_blob()),
       base::BindOnce(&WebContentController::JavascriptCallback,
                      weak_ptr_factory_.GetWeakPtr(), id));
diff --git a/chromeos/dbus/dbus_clients_browser.cc b/chromeos/dbus/dbus_clients_browser.cc
index a8fc24e..cb65bfc9 100644
--- a/chromeos/dbus/dbus_clients_browser.cc
+++ b/chromeos/dbus/dbus_clients_browser.cc
@@ -35,8 +35,6 @@
 #include "chromeos/dbus/image_burner/image_burner_client.h"
 #include "chromeos/dbus/image_loader/fake_image_loader_client.h"
 #include "chromeos/dbus/image_loader/image_loader_client.h"
-#include "chromeos/dbus/lorgnette_manager/fake_lorgnette_manager_client.h"
-#include "chromeos/dbus/lorgnette_manager/lorgnette_manager_client.h"
 #include "chromeos/dbus/oobe_config/fake_oobe_configuration_client.h"
 #include "chromeos/dbus/oobe_config/oobe_configuration_client.h"
 #include "chromeos/dbus/runtime_probe/fake_runtime_probe_client.h"
@@ -90,8 +88,6 @@
       CREATE_DBUS_CLIENT(ImageBurnerClient, use_real_clients);
   image_loader_client_ =
       CREATE_DBUS_CLIENT(ImageLoaderClient, use_real_clients);
-  lorgnette_manager_client_ =
-      CREATE_DBUS_CLIENT(LorgnetteManagerClient, use_real_clients);
   oobe_configuration_client_ =
       CREATE_DBUS_CLIENT(OobeConfigurationClient, use_real_clients);
   runtime_probe_client_ =
@@ -128,7 +124,6 @@
   gnubby_client_->Init(system_bus);
   image_burner_client_->Init(system_bus);
   image_loader_client_->Init(system_bus);
-  lorgnette_manager_client_->Init(system_bus);
   oobe_configuration_client_->Init(system_bus);
   runtime_probe_client_->Init(system_bus);
   smb_provider_client_->Init(system_bus);
diff --git a/chromeos/dbus/dbus_clients_browser.h b/chromeos/dbus/dbus_clients_browser.h
index 82e589f..0e1bb471 100644
--- a/chromeos/dbus/dbus_clients_browser.h
+++ b/chromeos/dbus/dbus_clients_browser.h
@@ -28,7 +28,6 @@
 class GnubbyClient;
 class ImageBurnerClient;
 class ImageLoaderClient;
-class LorgnetteManagerClient;
 class OobeConfigurationClient;
 class RuntimeProbeClient;
 class SmbProviderClient;
@@ -70,7 +69,6 @@
   std::unique_ptr<GnubbyClient> gnubby_client_;
   std::unique_ptr<ImageBurnerClient> image_burner_client_;
   std::unique_ptr<ImageLoaderClient> image_loader_client_;
-  std::unique_ptr<LorgnetteManagerClient> lorgnette_manager_client_;
   std::unique_ptr<OobeConfigurationClient> oobe_configuration_client_;
   std::unique_ptr<RuntimeProbeClient> runtime_probe_client_;
   std::unique_ptr<SmbProviderClient> smb_provider_client_;
diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc
index edcace9..8d699bc 100644
--- a/chromeos/dbus/dbus_thread_manager.cc
+++ b/chromeos/dbus/dbus_thread_manager.cc
@@ -24,7 +24,6 @@
 #include "chromeos/dbus/gnubby/gnubby_client.h"
 #include "chromeos/dbus/image_burner/image_burner_client.h"
 #include "chromeos/dbus/image_loader/image_loader_client.h"
-#include "chromeos/dbus/lorgnette_manager/lorgnette_manager_client.h"
 #include "chromeos/dbus/oobe_config/oobe_configuration_client.h"
 #include "chromeos/dbus/runtime_probe/runtime_probe_client.h"
 #include "chromeos/dbus/shill/shill_clients.h"
@@ -104,11 +103,6 @@
   RETURN_DBUS_CLIENT(image_loader_client_);
 }
 
-LorgnetteManagerClient* DBusThreadManager::GetLorgnetteManagerClient() {
-  return clients_browser_ ? clients_browser_->lorgnette_manager_client_.get()
-                          : nullptr;
-}
-
 OobeConfigurationClient* DBusThreadManager::GetOobeConfigurationClient() {
   return clients_browser_->oobe_configuration_client_.get();
 }
diff --git a/chromeos/dbus/dbus_thread_manager.h b/chromeos/dbus/dbus_thread_manager.h
index e50e35d..8e7f3cf 100644
--- a/chromeos/dbus/dbus_thread_manager.h
+++ b/chromeos/dbus/dbus_thread_manager.h
@@ -29,7 +29,6 @@
 class GnubbyClient;
 class ImageBurnerClient;
 class ImageLoaderClient;
-class LorgnetteManagerClient;
 class OobeConfigurationClient;
 class RuntimeProbeClient;
 class SmbProviderClient;
@@ -84,7 +83,6 @@
   GnubbyClient* GetGnubbyClient();
   ImageBurnerClient* GetImageBurnerClient();
   ImageLoaderClient* GetImageLoaderClient();
-  LorgnetteManagerClient* GetLorgnetteManagerClient();
   OobeConfigurationClient* GetOobeConfigurationClient();
   RuntimeProbeClient* GetRuntimeProbeClient();
   SmbProviderClient* GetSmbProviderClient();
diff --git a/chromeos/dbus/dbus_thread_manager_unittest.cc b/chromeos/dbus/dbus_thread_manager_unittest.cc
index 85bf784..a518edd 100644
--- a/chromeos/dbus/dbus_thread_manager_unittest.cc
+++ b/chromeos/dbus/dbus_thread_manager_unittest.cc
@@ -26,7 +26,6 @@
   EXPECT_TRUE(manager->GetDebugDaemonClient());
   EXPECT_TRUE(manager->GetEasyUnlockClient());
   EXPECT_TRUE(manager->GetImageBurnerClient());
-  EXPECT_TRUE(manager->GetLorgnetteManagerClient());
   EXPECT_TRUE(manager->GetUpdateEngineClient());
 
   DBusThreadManager::Shutdown();
diff --git a/chromeos/dbus/lorgnette_manager/lorgnette_manager_client.cc b/chromeos/dbus/lorgnette_manager/lorgnette_manager_client.cc
index a0d58f5e..dc6b046 100644
--- a/chromeos/dbus/lorgnette_manager/lorgnette_manager_client.cc
+++ b/chromeos/dbus/lorgnette_manager/lorgnette_manager_client.cc
@@ -21,6 +21,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chromeos/dbus/common/pipe_reader.h"
 #include "chromeos/dbus/lorgnette/lorgnette_service.pb.h"
+#include "chromeos/dbus/lorgnette_manager/fake_lorgnette_manager_client.h"
 #include "dbus/bus.h"
 #include "dbus/message.h"
 #include "dbus/object_path.h"
@@ -29,6 +30,9 @@
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
 namespace chromeos {
+namespace {
+
+LorgnetteManagerClient* g_instance = nullptr;
 
 // The LorgnetteManagerClient implementation used in production.
 class LorgnetteManagerClientImpl : public LorgnetteManagerClient {
@@ -105,7 +109,6 @@
                                   std::move(cancel_callback)));
   }
 
- protected:
   void Init(dbus::Bus* bus) override {
     lorgnette_daemon_proxy_ =
         bus->GetObjectProxy(lorgnette::kManagerServiceName,
@@ -524,13 +527,38 @@
   base::WeakPtrFactory<LorgnetteManagerClientImpl> weak_ptr_factory_{this};
 };
 
-LorgnetteManagerClient::LorgnetteManagerClient() = default;
-
-LorgnetteManagerClient::~LorgnetteManagerClient() = default;
+}  // namespace
 
 // static
-std::unique_ptr<LorgnetteManagerClient> LorgnetteManagerClient::Create() {
-  return std::make_unique<LorgnetteManagerClientImpl>();
+void LorgnetteManagerClient::Initialize(dbus::Bus* bus) {
+  CHECK(bus);
+  (new LorgnetteManagerClientImpl())->Init(bus);
+}
+
+// static
+void LorgnetteManagerClient::InitializeFake() {
+  new FakeLorgnetteManagerClient();
+}
+
+// static
+void LorgnetteManagerClient::Shutdown() {
+  CHECK(g_instance);
+  delete g_instance;
+}
+
+// static
+LorgnetteManagerClient* LorgnetteManagerClient::Get() {
+  return g_instance;
+}
+
+LorgnetteManagerClient::LorgnetteManagerClient() {
+  CHECK(!g_instance);
+  g_instance = this;
+}
+
+LorgnetteManagerClient::~LorgnetteManagerClient() {
+  CHECK_EQ(g_instance, this);
+  g_instance = nullptr;
 }
 
 }  // namespace chromeos
diff --git a/chromeos/dbus/lorgnette_manager/lorgnette_manager_client.h b/chromeos/dbus/lorgnette_manager/lorgnette_manager_client.h
index 274d80a..cfea4f8 100644
--- a/chromeos/dbus/lorgnette_manager/lorgnette_manager_client.h
+++ b/chromeos/dbus/lorgnette_manager/lorgnette_manager_client.h
@@ -29,9 +29,20 @@
     int resolution_dpi = 0;
   };
 
+  // Creates and initializes the global instance. |bus| must not be null.
+  static void Initialize(dbus::Bus* bus);
+
+  // Creates and initializes a fake global instance.
+  static void InitializeFake();
+
+  // Destroys the global instance if it has been initialized.
+  static void Shutdown();
+
+  // Returns the global instance if initialized. May return null.
+  static LorgnetteManagerClient* Get();
+
   LorgnetteManagerClient(const LorgnetteManagerClient&) = delete;
   LorgnetteManagerClient& operator=(const LorgnetteManagerClient&) = delete;
-  ~LorgnetteManagerClient() override;
 
   // Gets a list of scanners from the lorgnette manager.
   virtual void ListScanners(
@@ -70,15 +81,12 @@
   // scan running at a time.
   virtual void CancelScan(VoidDBusMethodCallback cancel_callback) = 0;
 
-  // Factory function, creates a new instance and returns ownership.
-  // For normal usage, access the singleton via DBusThreadManager::Get().
-  static std::unique_ptr<LorgnetteManagerClient> Create();
-
  protected:
   friend class LorgnetteManagerClientTest;
 
-  // Create() should be used instead.
+  // Initialize() should be used instead.
   LorgnetteManagerClient();
+  ~LorgnetteManagerClient() override;
 };
 
 }  // namespace chromeos
diff --git a/chromeos/dbus/lorgnette_manager/lorgnette_manager_client_unittest.cc b/chromeos/dbus/lorgnette_manager/lorgnette_manager_client_unittest.cc
index f1cafeb..788a5e2 100644
--- a/chromeos/dbus/lorgnette_manager/lorgnette_manager_client_unittest.cc
+++ b/chromeos/dbus/lorgnette_manager/lorgnette_manager_client_unittest.cc
@@ -224,7 +224,7 @@
         mock_bus_.get(), lorgnette::kManagerServiceName,
         dbus::ObjectPath(lorgnette::kManagerServicePath));
 
-    // |client_|'s Init() method should request a proxy for communicating with
+    // The client's Init() method should request a proxy for communicating with
     // the lorgnette daemon.
     EXPECT_CALL(
         *mock_bus_.get(),
@@ -232,7 +232,7 @@
                        dbus::ObjectPath(lorgnette::kManagerServicePath)))
         .WillOnce(Return(mock_proxy_.get()));
 
-    // Save |client_|'s scan status changed signal callback.
+    // Save the client's scan status changed signal callback.
     EXPECT_CALL(*mock_proxy_.get(),
                 DoConnectToSignal(lorgnette::kManagerServiceInterface,
                                   lorgnette::kScanStatusChangedSignal, _, _))
@@ -252,16 +252,21 @@
     EXPECT_CALL(*mock_bus_.get(), ShutdownAndBlock()).WillOnce(Return());
 
     // Create and initialize a client with the mock bus.
-    client_ = LorgnetteManagerClient::Create();
-    client_->Init(mock_bus_.get());
+    LorgnetteManagerClient::Initialize(mock_bus_.get());
 
     // Execute callbacks posted by Init().
     base::RunLoop().RunUntilIdle();
   }
 
-  void TearDown() override { mock_bus_->ShutdownAndBlock(); }
+  void TearDown() override {
+    LorgnetteManagerClient::Shutdown();
+    mock_bus_->ShutdownAndBlock();
+  }
 
-  LorgnetteManagerClient* client() { return client_.get(); }
+  // A shorter name to return the LorgnetteManagerClient under test.
+  static LorgnetteManagerClient* GetClient() {
+    return LorgnetteManagerClient::Get();
+  }
 
   // Adds an expectation to |mock_proxy_| that kListScannersMethod will be
   // called. When called, |mock_proxy_| will respond with |response|.
@@ -442,12 +447,10 @@
 
   // A message loop to emulate asynchronous behavior.
   base::test::TaskEnvironment task_environment_;
-  // Mock D-Bus objects for |client_| to interact with.
+  // Mock D-Bus objects for the client to interact with.
   scoped_refptr<dbus::MockBus> mock_bus_;
   scoped_refptr<dbus::MockObjectProxy> mock_proxy_;
-  // The client to be tested.
-  std::unique_ptr<LorgnetteManagerClient> client_;
-  // Holds |client_|'s kScanStatusChangedSignal callback.
+  // Holds the client's kScanStatusChangedSignal callback.
   dbus::ObjectProxy::SignalCallback scan_status_changed_signal_callback_;
   // Used to respond to kListScannersMethod D-Bus calls.
   dbus::Response* list_scanners_response_ = nullptr;
@@ -477,7 +480,7 @@
   SetListScannersExpectation(response.get());
 
   base::RunLoop run_loop;
-  client()->ListScanners(base::BindLambdaForTesting(
+  GetClient()->ListScanners(base::BindLambdaForTesting(
       [&](absl::optional<lorgnette::ListScannersResponse> result) {
         ASSERT_TRUE(result.has_value());
         EXPECT_THAT(result.value(), ProtobufEquals(kExpectedResponse));
@@ -493,7 +496,7 @@
   SetListScannersExpectation(nullptr);
 
   base::RunLoop run_loop;
-  client()->ListScanners(base::BindLambdaForTesting(
+  GetClient()->ListScanners(base::BindLambdaForTesting(
       [&](absl::optional<lorgnette::ListScannersResponse> result) {
         EXPECT_EQ(result, absl::nullopt);
         run_loop.Quit();
@@ -509,7 +512,7 @@
   SetListScannersExpectation(response.get());
 
   base::RunLoop run_loop;
-  client()->ListScanners(base::BindLambdaForTesting(
+  GetClient()->ListScanners(base::BindLambdaForTesting(
       [&](absl::optional<lorgnette::ListScannersResponse> result) {
         EXPECT_EQ(result, absl::nullopt);
         run_loop.Quit();
@@ -528,7 +531,7 @@
   SetGetScannerCapabilitiesExpectation(response.get());
 
   base::RunLoop run_loop;
-  client()->GetScannerCapabilities(
+  GetClient()->GetScannerCapabilities(
       kScannerDeviceName,
       base::BindLambdaForTesting(
           [&](absl::optional<lorgnette::ScannerCapabilities> result) {
@@ -546,7 +549,7 @@
   SetGetScannerCapabilitiesExpectation(nullptr);
 
   base::RunLoop run_loop;
-  client()->GetScannerCapabilities(
+  GetClient()->GetScannerCapabilities(
       kScannerDeviceName,
       base::BindLambdaForTesting(
           [&](absl::optional<lorgnette::ScannerCapabilities> result) {
@@ -564,7 +567,7 @@
   SetGetScannerCapabilitiesExpectation(response.get());
 
   base::RunLoop run_loop;
-  client()->GetScannerCapabilities(
+  GetClient()->GetScannerCapabilities(
       kScannerDeviceName,
       base::BindLambdaForTesting(
           [&](absl::optional<lorgnette::ScannerCapabilities> result) {
@@ -585,7 +588,7 @@
 
   base::RunLoop run_loop;
   lorgnette::StartScanRequest request = CreateStartScanRequest();
-  client()->StartScan(
+  GetClient()->StartScan(
       request.device_name(), request.settings(), base::NullCallback(),
       base::NullCallback(),
       base::BindLambdaForTesting([&](uint32_t progress, uint32_t page_num) {
@@ -616,7 +619,7 @@
   base::RunLoop page_run_loop;
   uint8_t num_pages_scanned = 0;
   lorgnette::StartScanRequest request = CreateStartScanRequest();
-  client()->StartScan(
+  GetClient()->StartScan(
       request.device_name(), request.settings(),
       base::BindLambdaForTesting([&](lorgnette::ScanFailureMode failure_mode) {
         EXPECT_EQ(failure_mode, lorgnette::SCAN_FAILURE_MODE_NO_FAILURE);
@@ -661,7 +664,7 @@
   base::RunLoop page_run_loop;
   uint8_t num_pages_scanned = 0;
   lorgnette::StartScanRequest request = CreateStartScanRequest();
-  client()->StartScan(
+  GetClient()->StartScan(
       request.device_name(), request.settings(),
       base::BindLambdaForTesting([&](lorgnette::ScanFailureMode failure_mode) {
         EXPECT_EQ(failure_mode, lorgnette::SCAN_FAILURE_MODE_NO_FAILURE);
@@ -708,7 +711,7 @@
   base::RunLoop second_page_run_loop;
   uint8_t num_pages_scanned = 0;
   lorgnette::StartScanRequest request = CreateStartScanRequest();
-  client()->StartScan(
+  GetClient()->StartScan(
       request.device_name(), request.settings(),
       base::BindLambdaForTesting([&](lorgnette::ScanFailureMode failure_mode) {
         EXPECT_EQ(failure_mode, lorgnette::SCAN_FAILURE_MODE_NO_FAILURE);
@@ -763,7 +766,7 @@
 
   base::RunLoop run_loop;
   lorgnette::StartScanRequest request = CreateStartScanRequest();
-  client()->StartScan(
+  GetClient()->StartScan(
       request.device_name(), request.settings(),
       base::BindLambdaForTesting([&](lorgnette::ScanFailureMode failure_mode) {
         EXPECT_EQ(failure_mode, lorgnette::SCAN_FAILURE_MODE_DEVICE_BUSY);
@@ -788,7 +791,7 @@
 
   base::RunLoop run_loop;
   lorgnette::StartScanRequest request = CreateStartScanRequest();
-  client()->StartScan(
+  GetClient()->StartScan(
       request.device_name(), request.settings(),
       base::BindLambdaForTesting([&](lorgnette::ScanFailureMode failure_mode) {
         EXPECT_EQ(failure_mode, lorgnette::SCAN_FAILURE_MODE_UNKNOWN);
@@ -807,7 +810,7 @@
 
   base::RunLoop run_loop;
   lorgnette::StartScanRequest request = CreateStartScanRequest();
-  client()->StartScan(
+  GetClient()->StartScan(
       request.device_name(), request.settings(),
       base::BindLambdaForTesting([&](lorgnette::ScanFailureMode failure_mode) {
         EXPECT_EQ(failure_mode, lorgnette::SCAN_FAILURE_MODE_UNKNOWN);
@@ -828,7 +831,7 @@
 
   base::RunLoop run_loop;
   lorgnette::StartScanRequest request = CreateStartScanRequest();
-  client()->StartScan(
+  GetClient()->StartScan(
       request.device_name(), request.settings(),
       base::BindLambdaForTesting([&](lorgnette::ScanFailureMode failure_mode) {
         EXPECT_EQ(failure_mode, lorgnette::SCAN_FAILURE_MODE_ADF_JAMMED);
@@ -849,7 +852,7 @@
 
   base::RunLoop run_loop;
   lorgnette::StartScanRequest request = CreateStartScanRequest();
-  client()->StartScan(
+  GetClient()->StartScan(
       request.device_name(), request.settings(),
       base::BindLambdaForTesting([&](lorgnette::ScanFailureMode failure_mode) {
         EXPECT_EQ(failure_mode, lorgnette::SCAN_FAILURE_MODE_UNKNOWN);
@@ -872,7 +875,7 @@
 
   base::RunLoop run_loop;
   lorgnette::StartScanRequest request = CreateStartScanRequest();
-  client()->StartScan(
+  GetClient()->StartScan(
       request.device_name(), request.settings(),
       base::BindLambdaForTesting([&](lorgnette::ScanFailureMode failure_mode) {
         EXPECT_EQ(failure_mode, lorgnette::SCAN_FAILURE_MODE_UNKNOWN);
@@ -895,7 +898,7 @@
 
   base::RunLoop run_loop;
   lorgnette::StartScanRequest request = CreateStartScanRequest();
-  client()->StartScan(
+  GetClient()->StartScan(
       request.device_name(), request.settings(),
       base::BindLambdaForTesting([&](lorgnette::ScanFailureMode failure_mode) {
         EXPECT_EQ(failure_mode, lorgnette::SCAN_FAILURE_MODE_IO_ERROR);
@@ -931,14 +934,14 @@
   SetCancelScanExpectation(cancel_scan_response.get());
 
   lorgnette::StartScanRequest request = CreateStartScanRequest();
-  client()->StartScan(request.device_name(), request.settings(),
-                      base::NullCallback(), base::NullCallback(),
-                      base::NullCallback());
+  GetClient()->StartScan(request.device_name(), request.settings(),
+                         base::NullCallback(), base::NullCallback(),
+                         base::NullCallback());
 
   base::RunLoop().RunUntilIdle();
 
   base::RunLoop run_loop;
-  client()->CancelScan(base::BindLambdaForTesting([&](bool success) {
+  GetClient()->CancelScan(base::BindLambdaForTesting([&](bool success) {
     EXPECT_TRUE(success);
     run_loop.Quit();
   }));
@@ -955,7 +958,7 @@
 // Test that the client handles a cancel call with no existing scan jobs.
 TEST_F(LorgnetteManagerClientTest, CancelScanJobNoExistingJobs) {
   base::RunLoop run_loop;
-  client()->CancelScan(base::BindLambdaForTesting([&](bool success) {
+  GetClient()->CancelScan(base::BindLambdaForTesting([&](bool success) {
     EXPECT_FALSE(success);
     run_loop.Quit();
   }));
@@ -972,9 +975,9 @@
   SetGetNextImageExpectation(get_next_image_response.get());
 
   lorgnette::StartScanRequest request = CreateStartScanRequest();
-  client()->StartScan(request.device_name(), request.settings(),
-                      base::NullCallback(), base::NullCallback(),
-                      base::NullCallback());
+  GetClient()->StartScan(request.device_name(), request.settings(),
+                         base::NullCallback(), base::NullCallback(),
+                         base::NullCallback());
 
   base::RunLoop().RunUntilIdle();
 
@@ -982,14 +985,14 @@
       lorgnette::ScanState::SCAN_STATE_IN_PROGRESS, kSecondScanUuid);
   SetStartScanExpectation(start_scan_response.get());
   SetGetNextImageExpectation(get_next_image_response.get(), kSecondScanUuid);
-  client()->StartScan(request.device_name(), request.settings(),
-                      base::NullCallback(), base::NullCallback(),
-                      base::NullCallback());
+  GetClient()->StartScan(request.device_name(), request.settings(),
+                         base::NullCallback(), base::NullCallback(),
+                         base::NullCallback());
 
   base::RunLoop().RunUntilIdle();
 
   base::RunLoop run_loop;
-  client()->CancelScan(base::BindLambdaForTesting([&](bool success) {
+  GetClient()->CancelScan(base::BindLambdaForTesting([&](bool success) {
     EXPECT_FALSE(success);
     run_loop.Quit();
   }));
@@ -1008,14 +1011,14 @@
   SetCancelScanExpectation(nullptr);
 
   lorgnette::StartScanRequest request = CreateStartScanRequest();
-  client()->StartScan(request.device_name(), request.settings(),
-                      base::NullCallback(), base::NullCallback(),
-                      base::NullCallback());
+  GetClient()->StartScan(request.device_name(), request.settings(),
+                         base::NullCallback(), base::NullCallback(),
+                         base::NullCallback());
 
   base::RunLoop().RunUntilIdle();
 
   base::RunLoop run_loop;
-  client()->CancelScan(base::BindLambdaForTesting([&](bool success) {
+  GetClient()->CancelScan(base::BindLambdaForTesting([&](bool success) {
     EXPECT_FALSE(success);
     run_loop.Quit();
   }));
@@ -1035,14 +1038,14 @@
   SetCancelScanExpectation(cancel_scan_response.get());
 
   lorgnette::StartScanRequest request = CreateStartScanRequest();
-  client()->StartScan(request.device_name(), request.settings(),
-                      base::NullCallback(), base::NullCallback(),
-                      base::NullCallback());
+  GetClient()->StartScan(request.device_name(), request.settings(),
+                         base::NullCallback(), base::NullCallback(),
+                         base::NullCallback());
 
   base::RunLoop().RunUntilIdle();
 
   base::RunLoop run_loop;
-  client()->CancelScan(base::BindLambdaForTesting([&](bool success) {
+  GetClient()->CancelScan(base::BindLambdaForTesting([&](bool success) {
     EXPECT_FALSE(success);
     run_loop.Quit();
   }));
@@ -1061,14 +1064,14 @@
   SetCancelScanExpectation(cancel_scan_response.get());
 
   lorgnette::StartScanRequest request = CreateStartScanRequest();
-  client()->StartScan(request.device_name(), request.settings(),
-                      base::NullCallback(), base::NullCallback(),
-                      base::NullCallback());
+  GetClient()->StartScan(request.device_name(), request.settings(),
+                         base::NullCallback(), base::NullCallback(),
+                         base::NullCallback());
 
   base::RunLoop().RunUntilIdle();
 
   base::RunLoop run_loop;
-  client()->CancelScan(base::BindLambdaForTesting([&](bool success) {
+  GetClient()->CancelScan(base::BindLambdaForTesting([&](bool success) {
     EXPECT_FALSE(success);
     run_loop.Quit();
   }));
diff --git a/chromeos/printing/printer_translator.cc b/chromeos/printing/printer_translator.cc
index 49ab79b..56e232d 100644
--- a/chromeos/printing/printer_translator.cc
+++ b/chromeos/printing/printer_translator.cc
@@ -39,35 +39,34 @@
 
 // Populates the |printer| object with corresponding fields from |value|.
 // Returns false if |value| is missing a required field.
-bool DictionaryToPrinter(const base::Value& value, Printer* printer) {
+bool DictionaryToPrinter(const base::Value::Dict& value, Printer* printer) {
   // Mandatory fields
-  const std::string* display_name = value.FindStringKey(kDisplayName);
-  if (display_name) {
-    printer->set_display_name(*display_name);
-  } else {
+  const std::string* display_name = value.FindString(kDisplayName);
+  if (!display_name) {
     LOG(WARNING) << "Display name required";
     return false;
   }
+  printer->set_display_name(*display_name);
 
-  const std::string* uri = value.FindStringKey(kUri);
-  if (uri) {
-    std::string message;
-    if (!printer->SetUri(*uri, &message)) {
-      LOG(WARNING) << message;
-      return false;
-    }
-  } else {
+  const std::string* uri = value.FindString(kUri);
+  if (!uri) {
     LOG(WARNING) << "Uri required";
     return false;
   }
 
+  std::string message;
+  if (!printer->SetUri(*uri, &message)) {
+    LOG(WARNING) << message;
+    return false;
+  }
+
   // Optional fields
-  const std::string* description = value.FindStringKey(kDescription);
+  const std::string* description = value.FindString(kDescription);
   if (description)
     printer->set_description(*description);
 
-  const std::string* manufacturer = value.FindStringKey(kManufacturer);
-  const std::string* model = value.FindStringKey(kModel);
+  const std::string* manufacturer = value.FindString(kManufacturer);
+  const std::string* model = value.FindString(kModel);
 
   std::string make_and_model = manufacturer ? *manufacturer : std::string();
   if (!make_and_model.empty() && model && !model->empty())
@@ -76,7 +75,7 @@
     make_and_model.append(*model);
   printer->set_make_and_model(make_and_model);
 
-  const std::string* uuid = value.FindStringKey(kUUID);
+  const std::string* uuid = value.FindString(kUUID);
   if (uuid)
     printer->set_uuid(*uuid);
 
@@ -86,21 +85,21 @@
 // Create an empty CupsPrinterInfo dictionary value. It should be consistent
 // with the fields in js side. See cups_printers_browser_proxy.js for the
 // definition of CupsPrintersInfo.
-base::Value CreateEmptyPrinterInfo() {
-  base::Value printer_info(base::Value::Type::DICTIONARY);
-  printer_info.SetBoolKey("isManaged", false);
-  printer_info.SetStringKey("ppdManufacturer", "");
-  printer_info.SetStringKey("ppdModel", "");
-  printer_info.SetStringKey("printerAddress", "");
-  printer_info.SetBoolPath("printerPpdReference.autoconf", false);
-  printer_info.SetStringKey("printerDescription", "");
-  printer_info.SetStringKey("printerId", "");
-  printer_info.SetStringKey("printerMakeAndModel", "");
-  printer_info.SetStringKey("printerName", "");
-  printer_info.SetStringKey("printerPPDPath", "");
-  printer_info.SetStringKey("printerProtocol", "ipp");
-  printer_info.SetStringKey("printerQueue", "");
-  printer_info.SetStringKey("printerStatus", "");
+base::Value::Dict CreateEmptyPrinterInfo() {
+  base::Value::Dict printer_info;
+  printer_info.Set("isManaged", false);
+  printer_info.Set("ppdManufacturer", "");
+  printer_info.Set("ppdModel", "");
+  printer_info.Set("printerAddress", "");
+  printer_info.SetByDottedPath("printerPpdReference.autoconf", false);
+  printer_info.Set("printerDescription", "");
+  printer_info.Set("printerId", "");
+  printer_info.Set("printerMakeAndModel", "");
+  printer_info.Set("printerName", "");
+  printer_info.Set("printerPPDPath", "");
+  printer_info.Set("printerProtocol", "ipp");
+  printer_info.Set("printerQueue", "");
+  printer_info.Set("printerStatus", "");
   return printer_info;
 }
 
@@ -118,11 +117,12 @@
 
 const char kPrinterId[] = "id";
 
-std::unique_ptr<Printer> RecommendedPrinterToPrinter(const base::Value& pref) {
+std::unique_ptr<Printer> RecommendedPrinterToPrinter(
+    const base::Value::Dict& pref) {
   std::string id;
   // Printer id comes from the id or guid field depending on the source.
-  const std::string* printer_id = pref.FindStringKey(kPrinterId);
-  const std::string* printer_guid = pref.FindStringKey(kGuid);
+  const std::string* printer_id = pref.FindString(kPrinterId);
+  const std::string* printer_guid = pref.FindString(kGuid);
   if (printer_id) {
     id = *printer_id;
   } else if (printer_guid) {
@@ -140,13 +140,13 @@
 
   printer->set_source(Printer::SRC_POLICY);
 
-  const base::Value* ppd = pref.FindDictKey(kPpdResource);
+  const base::Value::Dict* ppd = pref.FindDict(kPpdResource);
   if (ppd) {
     Printer::PpdReference* ppd_reference = printer->mutable_ppd_reference();
-    const std::string* make_and_model = ppd->FindStringKey(kEffectiveModel);
+    const std::string* make_and_model = ppd->FindString(kEffectiveModel);
     if (make_and_model)
       ppd_reference->effective_make_and_model = *make_and_model;
-    absl::optional<bool> autoconf = ppd->FindBoolKey(kAutoconf);
+    absl::optional<bool> autoconf = ppd->FindBool(kAutoconf);
     if (autoconf.has_value())
       ppd_reference->autoconf = *autoconf;
   }
@@ -168,70 +168,65 @@
   return printer;
 }
 
-base::Value GetCupsPrinterInfo(const Printer& printer) {
-  base::Value printer_info = CreateEmptyPrinterInfo();
+base::Value::Dict GetCupsPrinterInfo(const Printer& printer) {
+  base::Value::Dict printer_info = CreateEmptyPrinterInfo();
 
-  printer_info.SetBoolKey("isManaged",
-                          printer.source() == Printer::Source::SRC_POLICY);
-  printer_info.SetStringKey("printerId", printer.id());
-  printer_info.SetStringKey("printerName", printer.display_name());
-  printer_info.SetStringKey("printerDescription", printer.description());
-  printer_info.SetStringKey("printerMakeAndModel", printer.make_and_model());
+  printer_info.Set("isManaged",
+                   printer.source() == Printer::Source::SRC_POLICY);
+  printer_info.Set("printerId", printer.id());
+  printer_info.Set("printerName", printer.display_name());
+  printer_info.Set("printerDescription", printer.description());
+  printer_info.Set("printerMakeAndModel", printer.make_and_model());
   // NOTE: This assumes the the function IsIppEverywhere() simply returns
   // |printer.ppd_reference_.autoconf|. If the implementation of
   // IsIppEverywhere() changes this will need to be changed as well.
-  printer_info.SetBoolPath("printerPpdReference.autoconf",
-                           printer.IsIppEverywhere());
-  printer_info.SetStringKey("printerPPDPath",
-                            printer.ppd_reference().user_supplied_ppd_url);
-  printer_info.SetStringKey("printServerUri", printer.print_server_uri());
+  printer_info.SetByDottedPath("printerPpdReference.autoconf",
+                               printer.IsIppEverywhere());
+  printer_info.Set("printerPPDPath",
+                   printer.ppd_reference().user_supplied_ppd_url);
+  printer_info.Set("printServerUri", printer.print_server_uri());
 
   if (!printer.HasUri()) {
     // Uri is invalid so we set default values.
     LOG(WARNING) << "Could not parse uri.  Defaulting values";
-    printer_info.SetStringKey("printerAddress", "");
-    printer_info.SetStringKey("printerQueue", "");
-    printer_info.SetStringKey("printerProtocol",
-                              "ipp");  // IPP is our default protocol.
+    printer_info.Set("printerAddress", "");
+    printer_info.Set("printerQueue", "");
+    printer_info.Set("printerProtocol", "ipp");  // IPP is our default protocol.
     return printer_info;
   }
 
   if (printer.IsUsbProtocol())
-    printer_info.SetStringKey("ppdManufacturer",
-                              printer.usb_printer_manufacturer());
-  printer_info.SetStringKey("printerProtocol", printer.uri().GetScheme());
-  printer_info.SetStringKey("printerAddress", PrinterAddress(printer.uri()));
+    printer_info.Set("ppdManufacturer", printer.usb_printer_manufacturer());
+  printer_info.Set("printerProtocol", printer.uri().GetScheme());
+  printer_info.Set("printerAddress", PrinterAddress(printer.uri()));
   std::string printer_queue = printer.uri().GetPathEncodedAsString();
   if (!printer_queue.empty())
     printer_queue = printer_queue.substr(1);  // removes the leading '/'
   if (!printer.uri().GetQueryEncodedAsString().empty())
     printer_queue += "?" + printer.uri().GetQueryEncodedAsString();
-  printer_info.SetStringKey("printerQueue", printer_queue);
+  printer_info.Set("printerQueue", printer_queue);
 
   return printer_info;
 }
 
-base::Value CreateCupsPrinterStatusDictionary(
+base::Value::Dict CreateCupsPrinterStatusDictionary(
     const CupsPrinterStatus& cups_printer_status) {
-  base::Value printer_status(base::Value::Type::DICTIONARY);
+  base::Value::Dict printer_status;
 
-  printer_status.SetKey("printerId",
-                        base::Value(cups_printer_status.GetPrinterId()));
-  printer_status.SetKey(
-      "timestamp",
-      base::Value(cups_printer_status.GetTimestamp().ToJsTimeIgnoringNull()));
+  printer_status.Set("printerId", cups_printer_status.GetPrinterId());
+  printer_status.Set("timestamp",
+                     cups_printer_status.GetTimestamp().ToJsTimeIgnoringNull());
 
-  base::Value status_reasons(base::Value::Type::LIST);
-  for (auto reason : cups_printer_status.GetStatusReasons()) {
-    base::Value status_reason(base::Value::Type::DICTIONARY);
-    status_reason.SetKey("reason",
-                         base::Value(static_cast<int>(reason.GetReason())));
-    status_reason.SetKey("severity",
-                         base::Value(static_cast<int>(reason.GetSeverity())));
+  base::Value::List status_reasons;
+  for (const auto& reason : cups_printer_status.GetStatusReasons()) {
+    base::Value::Dict status_reason;
+    status_reason.Set("reason", static_cast<int>(reason.GetReason()));
+    status_reason.Set("severity", static_cast<int>(reason.GetSeverity()));
     status_reasons.Append(std::move(status_reason));
   }
-  printer_status.SetKey("statusReasons", std::move(status_reasons));
+  printer_status.Set("statusReasons", std::move(status_reasons));
 
   return printer_status;
 }
+
 }  // namespace chromeos
diff --git a/chromeos/printing/printer_translator.h b/chromeos/printing/printer_translator.h
index 25f46f65..993cb62a 100644
--- a/chromeos/printing/printer_translator.h
+++ b/chromeos/printing/printer_translator.h
@@ -8,12 +8,9 @@
 #include <memory>
 
 #include "base/component_export.h"
+#include "base/values.h"
 #include "chromeos/printing/printer_configuration.h"
 
-namespace base {
-class Value;
-}
-
 namespace chromeos {
 
 class CupsPrinterStatus;
@@ -23,18 +20,20 @@
 // Returns a new printer populated with the fields from |pref|.  Processes
 // dictionaries from policy.
 COMPONENT_EXPORT(CHROMEOS_PRINTING)
-std::unique_ptr<Printer> RecommendedPrinterToPrinter(const base::Value& pref);
+std::unique_ptr<Printer> RecommendedPrinterToPrinter(
+    const base::Value::Dict& pref);
 
 // Returns a JSON representation of |printer| as a CupsPrinterInfo. If the
 // printer uri cannot be parsed, the relevant fields are populated with default
 // values. CupsPrinterInfo is defined in cups_printers_browser_proxy.js.
 COMPONENT_EXPORT(CHROMEOS_PRINTING)
-base::Value GetCupsPrinterInfo(const Printer& printer);
+base::Value::Dict GetCupsPrinterInfo(const Printer& printer);
 
 // Returns a JSON representation of a CupsPrinterStatus
 COMPONENT_EXPORT(CHROMEOS_PRINTING)
-base::Value CreateCupsPrinterStatusDictionary(
+base::Value::Dict CreateCupsPrinterStatusDictionary(
     const CupsPrinterStatus& cups_printer_status);
+
 }  // namespace chromeos
 
 #endif  // CHROMEOS_PRINTING_PRINTER_TRANSLATOR_H_
diff --git a/chromeos/printing/printer_translator_unittest.cc b/chromeos/printing/printer_translator_unittest.cc
index c3795763..8d1c30f 100644
--- a/chromeos/printing/printer_translator_unittest.cc
+++ b/chromeos/printing/printer_translator_unittest.cc
@@ -55,7 +55,7 @@
 
 // Check the values populated in |printer_info| match the values of |printer|.
 void CheckGenericPrinterInfo(const Printer& printer,
-                             const base::Value& printer_info) {
+                             const base::Value::Dict& printer_info) {
   ExpectDictStringValue(printer.id(), printer_info, "printerId");
   ExpectDictStringValue(printer.display_name(), printer_info, "printerName");
   ExpectDictStringValue(printer.description(), printer_info,
@@ -66,7 +66,7 @@
 
 // Check that the corresponding values in |printer_info| match the given URI
 // components of |address|, |queue|, and |protocol|.
-void CheckPrinterInfoUri(const base::Value& printer_info,
+void CheckPrinterInfoUri(const base::Value::Dict& printer_info,
                          const std::string& protocol,
                          const std::string& address,
                          const std::string& queue) {
@@ -78,41 +78,41 @@
 }  // anonymous namespace
 
 TEST(PrinterTranslatorTest, RecommendedPrinterToPrinterMissingId) {
-  base::Value value(base::Value::Type::DICTIONARY);
+  base::Value::Dict value;
   std::unique_ptr<Printer> printer = RecommendedPrinterToPrinter(value);
 
   EXPECT_FALSE(printer);
 }
 
 TEST(PrinterTranslatorTest, MissingDisplayNameFails) {
-  base::Value preference(base::Value::Type::DICTIONARY);
-  preference.SetStringKey("id", kHash);
+  base::Value::Dict preference;
+  preference.Set("id", kHash);
   // display name omitted
-  preference.SetStringKey("uri", kUri);
-  preference.SetStringPath("ppd_resource.effective_model",
-                           kEffectiveMakeAndModel);
+  preference.Set("uri", kUri);
+  preference.SetByDottedPath("ppd_resource.effective_model",
+                             kEffectiveMakeAndModel);
 
   std::unique_ptr<Printer> printer = RecommendedPrinterToPrinter(preference);
   EXPECT_FALSE(printer);
 }
 
 TEST(PrinterTranslatorTest, MissingUriFails) {
-  base::Value preference(base::Value::Type::DICTIONARY);
-  preference.SetStringKey("id", kHash);
-  preference.SetStringKey("display_name", kName);
+  base::Value::Dict preference;
+  preference.Set("id", kHash);
+  preference.Set("display_name", kName);
   // uri omitted
-  preference.SetStringPath("ppd_resource.effective_model",
-                           kEffectiveMakeAndModel);
+  preference.SetByDottedPath("ppd_resource.effective_model",
+                             kEffectiveMakeAndModel);
 
   std::unique_ptr<Printer> printer = RecommendedPrinterToPrinter(preference);
   EXPECT_FALSE(printer);
 }
 
 TEST(PrinterTranslatorTest, MissingPpdResourceFails) {
-  base::Value preference(base::Value::Type::DICTIONARY);
-  preference.SetStringKey("id", kHash);
-  preference.SetStringKey("display_name", kName);
-  preference.SetStringKey("uri", kUri);
+  base::Value::Dict preference;
+  preference.Set("id", kHash);
+  preference.Set("display_name", kName);
+  preference.Set("uri", kUri);
   // ppd resource omitted
 
   std::unique_ptr<Printer> printer = RecommendedPrinterToPrinter(preference);
@@ -120,11 +120,11 @@
 }
 
 TEST(PrinterTranslatorTest, MissingEffectiveMakeModelFails) {
-  base::Value preference(base::Value::Type::DICTIONARY);
-  preference.SetStringKey("id", kHash);
-  preference.SetStringKey("display_name", kName);
-  preference.SetStringKey("uri", kUri);
-  preference.SetStringPath("ppd_resource.foobarwrongfield", "gibberish");
+  base::Value::Dict preference;
+  preference.Set("id", kHash);
+  preference.Set("display_name", kName);
+  preference.Set("uri", kUri);
+  preference.SetByDottedPath("ppd_resource.foobarwrongfield", "gibberish");
 
   std::unique_ptr<Printer> printer = RecommendedPrinterToPrinter(preference);
   EXPECT_FALSE(printer);
@@ -133,39 +133,39 @@
 // The test verifies that setting both true autoconf flag and non-empty
 // effective_model properties is not considered as the valid policy.
 TEST(PrinterTranslatorTest, AutoconfAndMakeModelSet) {
-  base::Value preference(base::Value::Type::DICTIONARY);
-  preference.SetStringKey("id", kHash);
-  preference.SetStringKey("display_name", kName);
-  preference.SetStringKey("uri", kUri);
-  preference.SetStringPath("ppd_resource.effective_model",
-                           kEffectiveMakeAndModel);
-  preference.SetBoolPath("ppd_resource.autoconf", true);
+  base::Value::Dict preference;
+  preference.Set("id", kHash);
+  preference.Set("display_name", kName);
+  preference.Set("uri", kUri);
+  preference.SetByDottedPath("ppd_resource.effective_model",
+                             kEffectiveMakeAndModel);
+  preference.SetByDottedPath("ppd_resource.autoconf", true);
 
   std::unique_ptr<Printer> printer = RecommendedPrinterToPrinter(preference);
   EXPECT_FALSE(printer);
 }
 
 TEST(PrinterTranslatorTest, InvalidUriFails) {
-  base::Value preference(base::Value::Type::DICTIONARY);
-  preference.SetStringKey("id", kHash);
-  preference.SetStringKey("display_name", kName);
-  preference.SetStringPath("ppd_resource.effective_model",
-                           kEffectiveMakeAndModel);
+  base::Value::Dict preference;
+  preference.Set("id", kHash);
+  preference.Set("display_name", kName);
+  preference.SetByDottedPath("ppd_resource.effective_model",
+                             kEffectiveMakeAndModel);
 
   // uri with incorrect port
-  preference.SetStringKey("uri", "ipp://hostname.tld:-1");
+  preference.Set("uri", "ipp://hostname.tld:-1");
 
   std::unique_ptr<Printer> printer = RecommendedPrinterToPrinter(preference);
   EXPECT_FALSE(printer);
 }
 
 TEST(PrinterTranslatorTest, RecommendedPrinterMinimalSetup) {
-  base::Value preference(base::Value::Type::DICTIONARY);
-  preference.SetStringKey("id", kHash);
-  preference.SetStringKey("display_name", kName);
-  preference.SetStringKey("uri", kUri);
-  preference.SetStringPath("ppd_resource.effective_model",
-                           kEffectiveMakeAndModel);
+  base::Value::Dict preference;
+  preference.Set("id", kHash);
+  preference.Set("display_name", kName);
+  preference.Set("uri", kUri);
+  preference.SetByDottedPath("ppd_resource.effective_model",
+                             kEffectiveMakeAndModel);
 
   std::unique_ptr<Printer> printer = RecommendedPrinterToPrinter(preference);
   ASSERT_TRUE(printer);
@@ -176,18 +176,18 @@
 }
 
 TEST(PrinterTranslatorTest, RecommendedPrinterToPrinter) {
-  base::Value preference(base::Value::Type::DICTIONARY);
-  preference.SetStringKey("id", kHash);
-  preference.SetStringKey("display_name", kName);
-  preference.SetStringKey("description", kDescription);
-  preference.SetStringKey("manufacturer", kMake);
-  preference.SetStringKey("model", kModel);
-  preference.SetStringKey("uri", kUri);
-  preference.SetStringKey("uuid", kUUID);
+  base::Value::Dict preference;
+  preference.Set("id", kHash);
+  preference.Set("display_name", kName);
+  preference.Set("description", kDescription);
+  preference.Set("manufacturer", kMake);
+  preference.Set("model", kModel);
+  preference.Set("uri", kUri);
+  preference.Set("uuid", kUUID);
 
-  preference.SetBoolPath("ppd_resource.autoconf", false);
-  preference.SetStringPath("ppd_resource.effective_model",
-                           kEffectiveMakeAndModel);
+  preference.SetByDottedPath("ppd_resource.autoconf", false);
+  preference.SetByDottedPath("ppd_resource.effective_model",
+                             kEffectiveMakeAndModel);
 
   std::unique_ptr<Printer> printer = RecommendedPrinterToPrinter(preference);
   EXPECT_TRUE(printer);
@@ -205,12 +205,12 @@
 }
 
 TEST(PrinterTranslatorTest, RecommendedPrinterToPrinterAutoconf) {
-  base::Value preference(base::Value::Type::DICTIONARY);
-  preference.SetStringKey("id", kHash);
-  preference.SetStringKey("display_name", kName);
-  preference.SetStringKey("uri", kUri);
+  base::Value::Dict preference;
+  preference.Set("id", kHash);
+  preference.Set("display_name", kName);
+  preference.Set("uri", kUri);
 
-  preference.SetBoolPath("ppd_resource.autoconf", true);
+  preference.SetByDottedPath("ppd_resource.autoconf", true);
 
   std::unique_ptr<Printer> printer = RecommendedPrinterToPrinter(preference);
   EXPECT_TRUE(printer);
@@ -223,13 +223,13 @@
 }
 
 TEST(PrinterTranslatorTest, RecommendedPrinterToPrinterBlankManufacturer) {
-  base::Value preference(base::Value::Type::DICTIONARY);
-  preference.SetStringKey("id", kHash);
-  preference.SetStringKey("display_name", kName);
-  preference.SetStringKey("model", kModel);
-  preference.SetStringKey("uri", kUri);
-  preference.SetStringPath("ppd_resource.effective_model",
-                           kEffectiveMakeAndModel);
+  base::Value::Dict preference;
+  preference.Set("id", kHash);
+  preference.Set("display_name", kName);
+  preference.Set("model", kModel);
+  preference.Set("uri", kUri);
+  preference.SetByDottedPath("ppd_resource.effective_model",
+                             kEffectiveMakeAndModel);
 
   std::unique_ptr<Printer> printer = RecommendedPrinterToPrinter(preference);
   EXPECT_TRUE(printer);
@@ -238,13 +238,13 @@
 }
 
 TEST(PrinterTranslatorTest, RecommendedPrinterToPrinterBlankModel) {
-  base::Value preference(base::Value::Type::DICTIONARY);
-  preference.SetStringKey("id", kHash);
-  preference.SetStringKey("display_name", kName);
-  preference.SetStringKey("manufacturer", kMake);
-  preference.SetStringKey("uri", kUri);
-  preference.SetStringPath("ppd_resource.effective_model",
-                           kEffectiveMakeAndModel);
+  base::Value::Dict preference;
+  preference.Set("id", kHash);
+  preference.Set("display_name", kName);
+  preference.Set("manufacturer", kMake);
+  preference.Set("uri", kUri);
+  preference.SetByDottedPath("ppd_resource.effective_model",
+                             kEffectiveMakeAndModel);
 
   std::unique_ptr<Printer> printer = RecommendedPrinterToPrinter(preference);
   EXPECT_TRUE(printer);
@@ -253,12 +253,12 @@
 }
 
 TEST(PrinterTranslatorTest, BulkPrinterJson) {
-  base::Value preference(base::Value::Type::DICTIONARY);
-  preference.SetStringKey("guid", kGUID);
-  preference.SetStringKey("display_name", kName);
-  preference.SetStringKey("uri", kUri);
-  preference.SetStringPath("ppd_resource.effective_model",
-                           kEffectiveMakeAndModel);
+  base::Value::Dict preference;
+  preference.Set("guid", kGUID);
+  preference.Set("display_name", kName);
+  preference.Set("uri", kUri);
+  preference.SetByDottedPath("ppd_resource.effective_model",
+                             kEffectiveMakeAndModel);
 
   std::unique_ptr<Printer> printer = RecommendedPrinterToPrinter(preference);
   EXPECT_TRUE(printer);
@@ -268,7 +268,7 @@
 
 TEST(PrinterTranslatorTest, GetCupsPrinterInfoGenericPrinter) {
   Printer printer = CreateGenericPrinter();
-  base::Value printer_info = GetCupsPrinterInfo(printer);
+  base::Value::Dict printer_info = GetCupsPrinterInfo(printer);
   CheckGenericPrinterInfo(CreateGenericPrinter(), printer_info);
 
   // We expect the default values to be set for the URI components since the
@@ -282,7 +282,7 @@
   Printer printer = CreateGenericPrinter();
   ASSERT_TRUE(printer.SetUri(kUri));
 
-  base::Value printer_info = GetCupsPrinterInfo(printer);
+  base::Value::Dict printer_info = GetCupsPrinterInfo(printer);
   CheckGenericPrinterInfo(CreateGenericPrinter(), printer_info);
 
   CheckPrinterInfoUri(printer_info, "ipp", "printy.domain.co:555", "ipp/print");
@@ -294,7 +294,7 @@
   Printer printer = CreateGenericPrinter();
   ASSERT_TRUE(printer.SetUri(kUsbUri));
 
-  base::Value printer_info = GetCupsPrinterInfo(printer);
+  base::Value::Dict printer_info = GetCupsPrinterInfo(printer);
   CheckGenericPrinterInfo(CreateGenericPrinter(), printer_info);
 
   CheckPrinterInfoUri(printer_info, "usb", "1234", "af9d?serial=ink1");
@@ -304,7 +304,7 @@
 
 TEST(PrinterTranslatorTest, GetCupsPrinterInfoAutoconfPrinter) {
   Printer printer = CreateAutoconfPrinter();
-  base::Value printer_info = GetCupsPrinterInfo(printer);
+  base::Value::Dict printer_info = GetCupsPrinterInfo(printer);
   CheckGenericPrinterInfo(CreateGenericPrinter(), printer_info);
 
   // We expect the default values to be set for the URI components since the
@@ -322,22 +322,24 @@
       CupsPrinterStatusReason::Reason::kDoorOpen,
       CupsPrinterStatusReason::Severity::kError);
 
-  base::Value printer_status_dict =
+  base::Value::Dict printer_status_dict =
       CreateCupsPrinterStatusDictionary(cups_printer_status);
 
-  EXPECT_EQ("id", *printer_status_dict.FindStringPath("printerId"));
+  EXPECT_EQ("id", *printer_status_dict.FindString("printerId"));
   EXPECT_EQ(cups_printer_status.GetTimestamp().ToJsTimeIgnoringNull(),
-            *printer_status_dict.FindDoublePath("timestamp"));
+            *printer_status_dict.FindDouble("timestamp"));
 
-  const base::Value* status_reasons =
-      printer_status_dict.FindListPath("statusReasons");
-  EXPECT_EQ(1u, status_reasons->GetList().size());
+  const base::Value::List* status_reasons =
+      printer_status_dict.FindList("statusReasons");
+  ASSERT_TRUE(status_reasons);
+  EXPECT_EQ(1u, status_reasons->size());
 
-  for (const base::Value& status_reason : status_reasons->GetList()) {
+  for (const base::Value& status_reason : *status_reasons) {
+    ASSERT_TRUE(status_reason.is_dict());
     EXPECT_EQ(static_cast<int>(CupsPrinterStatusReason::Reason::kDoorOpen),
-              *status_reason.FindIntPath("reason"));
+              status_reason.GetDict().FindInt("reason"));
     EXPECT_EQ(static_cast<int>(CupsPrinterStatusReason::Severity::kError),
-              *status_reason.FindIntPath("severity"));
+              status_reason.GetDict().FindInt("severity"));
   }
 }
 
@@ -350,33 +352,34 @@
       CupsPrinterStatusReason::Reason::kPaperJam,
       CupsPrinterStatusReason::Severity::kError);
 
-  base::Value printer_status_dict =
+  base::Value::Dict printer_status_dict =
       CreateCupsPrinterStatusDictionary(cups_printer_status);
 
-  EXPECT_EQ("id", *printer_status_dict.FindStringPath("printerId"));
+  EXPECT_EQ("id", *printer_status_dict.FindString("printerId"));
   EXPECT_EQ(cups_printer_status.GetTimestamp().ToJsTimeIgnoringNull(),
-            *printer_status_dict.FindDoublePath("timestamp"));
+            *printer_status_dict.FindDouble("timestamp"));
 
-  const base::Value* status_reasons =
-      printer_status_dict.FindListPath("statusReasons");
+  const base::Value::List* status_reasons =
+      printer_status_dict.FindList("statusReasons");
+  ASSERT_TRUE(status_reasons);
 
-  const auto& status_reasons_list = status_reasons->GetList();
+  const auto& status_reasons_list = *status_reasons;
   ASSERT_EQ(2u, status_reasons_list.size());
   EXPECT_EQ(static_cast<int>(CupsPrinterStatusReason::Reason::kLowOnPaper),
-            status_reasons_list[0].FindIntPath("reason"));
+            status_reasons_list[0].GetDict().FindInt("reason"));
   EXPECT_EQ(static_cast<int>(CupsPrinterStatusReason::Severity::kWarning),
-            status_reasons_list[0].FindIntPath("severity"));
+            status_reasons_list[0].GetDict().FindInt("severity"));
 
   EXPECT_EQ(static_cast<int>(CupsPrinterStatusReason::Reason::kPaperJam),
-            status_reasons_list[1].FindIntPath("reason"));
+            status_reasons_list[1].GetDict().FindInt("reason"));
   EXPECT_EQ(static_cast<int>(CupsPrinterStatusReason::Severity::kError),
-            status_reasons_list[1].FindIntPath("severity"));
+            status_reasons_list[1].GetDict().FindInt("severity"));
 }
 
 TEST(PrinterTranslatorTest, GetCupsPrinterInfoManagedPrinter) {
   Printer printer = CreateGenericPrinter();
   printer.set_source(Printer::Source::SRC_USER_PREFS);
-  base::Value printer_info = GetCupsPrinterInfo(printer);
+  base::Value::Dict printer_info = GetCupsPrinterInfo(printer);
   ExpectDictBooleanValue(false, printer_info, "isManaged");
 
   printer.set_source(Printer::Source::SRC_POLICY);
diff --git a/components/exo/wayland/clients/client_base.cc b/components/exo/wayland/clients/client_base.cc
index 50f1a59f..430f0b8 100644
--- a/components/exo/wayland/clients/client_base.cc
+++ b/components/exo/wayland/clients/client_base.cc
@@ -556,8 +556,9 @@
     ui::OzonePlatform::InitParams ozone_params;
     ozone_params.single_process = true;
     ui::OzonePlatform::InitializeForGPU(ozone_params);
-    bool gl_initialized = gl::init::InitializeGLOneOff(/*system_device_id=*/0);
-    DCHECK(gl_initialized);
+    gl::GLDisplayEGL* display = static_cast<gl::GLDisplayEGL*>(
+        gl::init::InitializeGLOneOff(/*system_device_id=*/0));
+    DCHECK(display);
     gl_surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size());
     gl_context_ =
         gl::init::CreateGLContext(nullptr,  // share_group
@@ -566,14 +567,11 @@
     make_current_ = std::make_unique<ui::ScopedMakeCurrent>(gl_context_.get(),
                                                             gl_surface_.get());
 
-    if (gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension(
-            "EGL_EXT_image_flush_external") ||
-        gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension(
-            "EGL_ARM_implicit_external_sync")) {
+    if (display->ext->b_EGL_EXT_image_flush_external ||
+        display->ext->b_EGL_ARM_implicit_external_sync) {
       egl_sync_type_ = EGL_SYNC_FENCE_KHR;
     }
-    if (gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension(
-            "EGL_ANDROID_native_fence_sync")) {
+    if (display->ext->b_EGL_ANDROID_native_fence_sync) {
       egl_sync_type_ = EGL_SYNC_NATIVE_FENCE_ANDROID;
     }
 
diff --git a/components/feed/core/v2/api_test/feed_api_stream_unittest.cc b/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
index bc108e6..06d79de 100644
--- a/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
+++ b/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
@@ -322,6 +322,22 @@
                        ModelStateFor(GetStreamType(), store_.get()));
 }
 
+TEST_P(FeedStreamTestForAllStreamTypes, UseFeedQueryOverride) {
+  Config config = GetFeedConfig();
+  config.use_feed_query_requests = true;
+  SetFeedConfigForTesting(config);
+
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_TRUE(network_.query_request_sent);
+  // There should be no API refresh requests when using use_feed_query_requests.
+  auto api_request_counts = network_.GetApiRequestCounts();
+  api_request_counts.erase(NetworkRequestType::kListWebFeeds);  // ignore
+  EXPECT_EQ((std::map<NetworkRequestType, int>()), api_request_counts);
+  EXPECT_EQ("loading -> [user@foo] 2 slices", surface.DescribeUpdates());
+}
+
 TEST_F(FeedApiTest, OnboardingFetchAfterStartup) {
   // Enable WebFeed and WebFeedOnboarding flags.
   base::test::ScopedFeatureList features;
@@ -439,7 +455,7 @@
 }
 
 TEST_P(FeedNetworkEndpointTest, TestAllNetworkEndpointConfigs) {
-  SetUseFeedQueryRequestsForWebFeeds(GetWebFeedUsesFeedQueryRequests());
+  SetUseFeedQueryRequests(GetUseFeedQueryRequests());
 
   // Enable WebFeed and subscribe to a page, so that we can check if the WebFeed
   // is refreshed by ForceRefreshForDebugging.
@@ -470,10 +486,10 @@
   // Total 2 queries (Web + For You).
   EXPECT_EQ(2, network_.send_query_call_count);
   // API request to DiscoFeed (For You) - if enabled by feature
-  EXPECT_EQ(GetDiscoFeedEnabled() ? 1 : 0,
+  EXPECT_EQ((!GetUseFeedQueryRequests() && GetDiscoFeedEnabled()) ? 1 : 0,
             network_.GetApiRequestCount<QueryInteractiveFeedDiscoverApi>());
   // API request to WebFeedList if FeedQuery not enabled by config.
-  EXPECT_EQ(GetWebFeedUsesFeedQueryRequests() ? 0 : 1,
+  EXPECT_EQ(GetUseFeedQueryRequests() ? 0 : 1,
             network_.GetApiRequestCount<WebFeedListContentsDiscoverApi>());
 }
 
diff --git a/components/feed/core/v2/api_test/feed_api_test.cc b/components/feed/core/v2/api_test/feed_api_test.cc
index 5a2261f9..34b5e846 100644
--- a/components/feed/core/v2/api_test/feed_api_test.cc
+++ b/components/feed/core/v2/api_test/feed_api_test.cc
@@ -840,9 +840,9 @@
   // Disable fetching of recommended web feeds at startup to
   // avoid a delayed task in tests that don't need it.
   config.fetch_web_feed_info_delay = base::TimeDelta();
-  // `use_feed_query_requests_for_web_feeds` is a temporary option for
+  // `use_feed_query_requests` is a temporary option for
   // debugging, setting it to false tests the preferred endpoint.
-  config.use_feed_query_requests_for_web_feeds = false;
+  config.use_feed_query_requests = false;
   SetFeedConfigForTesting(config);
 
   feed::prefs::RegisterFeedSharedProfilePrefs(profile_prefs_.registry());
diff --git a/components/feed/core/v2/api_test/feed_api_test.h b/components/feed/core/v2/api_test/feed_api_test.h
index 0ef006e..59406c5 100644
--- a/components/feed/core/v2/api_test/feed_api_test.h
+++ b/components/feed/core/v2/api_test/feed_api_test.h
@@ -304,6 +304,10 @@
     auto iter = api_request_count_.find(request_type);
     return iter == api_request_count_.end() ? 0 : iter->second;
   }
+  std::map<NetworkRequestType, int> GetApiRequestCounts() const {
+    return api_request_count_;
+  }
+
   int GetActionRequestCount() const;
   int GetFollowRequestCount() const {
     return GetApiRequestCount<FollowWebFeedDiscoverApi>();
@@ -553,7 +557,8 @@
       public ::testing::WithParamInterface<::testing::tuple<bool, bool>> {
  public:
   static bool GetDiscoFeedEnabled() { return ::testing::get<0>(GetParam()); }
-  static bool GetWebFeedUsesFeedQueryRequests() {
+  // Whether Feed-Query is used instead, as request in snippets-internals.
+  static bool GetUseFeedQueryRequests() {
     return ::testing::get<1>(GetParam());
   }
 };
diff --git a/components/feed/core/v2/config.cc b/components/feed/core/v2/config.cc
index 462813c..876b50b9 100644
--- a/components/feed/core/v2/config.cc
+++ b/components/feed/core/v2/config.cc
@@ -171,9 +171,8 @@
 }
 
 void OverrideWithSwitches(Config& config) {
-  config.use_feed_query_requests_for_web_feeds =
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          "webfeed-legacy-feedquery");
+  config.use_feed_query_requests =
+      base::CommandLine::ForCurrentProcess()->HasSwitch("use-legacy-feedquery");
 }
 
 }  // namespace
@@ -189,10 +188,9 @@
 }
 
 // This is a dev setting that updates Config, which is supposed to be constant.
-// TODO(crbug/1152592): remove when not needed anymore.
-void SetUseFeedQueryRequestsForWebFeeds(const bool use_legacy) {
+void SetUseFeedQueryRequests(const bool use_legacy) {
   Config& config = const_cast<Config&>(GetFeedConfig());
-  config.use_feed_query_requests_for_web_feeds = use_legacy;
+  config.use_feed_query_requests = use_legacy;
 }
 
 void SetFeedConfigForTesting(const Config& config) {
diff --git a/components/feed/core/v2/config.h b/components/feed/core/v2/config.h
index 456b081..f295219 100644
--- a/components/feed/core/v2/config.h
+++ b/components/feed/core/v2/config.h
@@ -102,7 +102,7 @@
   // Until we get the new list contents API working, keep using FeedQuery.
   // TODO(crbug/1152592): remove this when new endpoint is tested enough.
   // Set using snippets-internals, or the --webfeed-legacy-feedquery switch.
-  bool use_feed_query_requests_for_web_feeds = false;
+  bool use_feed_query_requests = false;
 
   // Set of optional capabilities included in requests. See
   // CreateFeedQueryRequest() for required capabilities.
@@ -124,7 +124,7 @@
 
 // Sets whether the legacy feed endpoint should be used for Web Feed content
 // fetches.
-void SetUseFeedQueryRequestsForWebFeeds(const bool use_legacy);
+void SetUseFeedQueryRequests(const bool use_legacy);
 
 void SetFeedConfigForTesting(const Config& config);
 void OverrideConfigWithFinchForTesting();
diff --git a/components/feed/core/v2/tasks/load_more_task.cc b/components/feed/core/v2/tasks/load_more_task.cc
index 07f73cb..dc89ec2 100644
--- a/components/feed/core/v2/tasks/load_more_task.cc
+++ b/components/feed/core/v2/tasks/load_more_task.cc
@@ -15,6 +15,7 @@
 #include "components/feed/core/proto/v2/wire/client_info.pb.h"
 #include "components/feed/core/proto/v2/wire/feed_request.pb.h"
 #include "components/feed/core/proto/v2/wire/request.pb.h"
+#include "components/feed/core/v2/config.h"
 #include "components/feed/core/v2/enums.h"
 #include "components/feed/core/v2/feed_network.h"
 #include "components/feed/core/v2/feed_stream.h"
@@ -94,9 +95,8 @@
       request_metadata, stream_.GetMetadata().consistency_token(),
       stream_.GetModel(stream_type_)->GetNextPageToken());
 
-  // TODO(crbug/1152592): Send a different network request type for
-  // WebFeeds.
-  if (base::FeatureList::IsEnabled(kDiscoFeedEndpoint)) {
+  if (base::FeatureList::IsEnabled(kDiscoFeedEndpoint) &&
+      !GetFeedConfig().use_feed_query_requests) {
     stream_.GetNetwork().SendApiRequest<QueryNextPageDiscoverApi>(
         request, account_info, std::move(request_metadata),
         base::BindOnce(&LoadMoreTask::QueryApiRequestComplete, GetWeakPtr()));
diff --git a/components/feed/core/v2/tasks/load_stream_task.cc b/components/feed/core/v2/tasks/load_stream_task.cc
index 9ab3ccb70..04a75fb 100644
--- a/components/feed/core/v2/tasks/load_stream_task.cc
+++ b/components/feed/core/v2/tasks/load_stream_task.cc
@@ -304,16 +304,16 @@
       options_.stream_type, request_metadata.content_order);
 
   FeedNetwork& network = stream_.GetNetwork();
-
-  if (options_.stream_type.IsWebFeed() &&
-      !GetFeedConfig().use_feed_query_requests_for_web_feeds) {
+  const bool force_feed_query = GetFeedConfig().use_feed_query_requests;
+  if (options_.stream_type.IsWebFeed() && !force_feed_query) {
     // Special case: web feed that is not using Feed Query requests go to
     // WebFeedListContentsDiscoverApi.
     network.SendApiRequest<WebFeedListContentsDiscoverApi>(
         std::move(request), account_info, std::move(request_metadata),
         base::BindOnce(&LoadStreamTask::QueryApiRequestComplete, GetWeakPtr()));
   } else if (options_.stream_type.IsForYou() &&
-             base::FeatureList::IsEnabled(kDiscoFeedEndpoint)) {
+             base::FeatureList::IsEnabled(kDiscoFeedEndpoint) &&
+             !force_feed_query) {
     // Special case: For You feed using the DiscoFeedEndpoint call
     // Query*FeedDiscoverApi.
     switch (options_.load_type) {
diff --git a/components/omnibox/OWNERS b/components/omnibox/OWNERS
index c01d941..d59becaf 100644
--- a/components/omnibox/OWNERS
+++ b/components/omnibox/OWNERS
@@ -1,7 +1,8 @@
+ender@google.com
 jdonnelly@chromium.org
 mahmadi@chromium.org
 manukh@chromium.org
 mpearson@chromium.org
 orinj@chromium.org
 tommycli@chromium.org
-yoangela@chromium.org
+yoangela@chromium.org
\ No newline at end of file
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn
index 7f1e2bb..90221ff 100644
--- a/components/omnibox/browser/BUILD.gn
+++ b/components/omnibox/browser/BUILD.gn
@@ -466,6 +466,7 @@
       "//components/query_tiles:query_tile_java",
       "//third_party/androidx:androidx_collection_collection_java",
       "//url:gurl_java",
+      "//url:gurl_junit_test_support",
     ]
   }
 
diff --git a/components/omnibox/browser/android/javatests/src/org/chromium/components/omnibox/AutocompleteMatchBuilder.java b/components/omnibox/browser/android/javatests/src/org/chromium/components/omnibox/AutocompleteMatchBuilder.java
index e31e064..456bfaa 100644
--- a/components/omnibox/browser/android/javatests/src/org/chromium/components/omnibox/AutocompleteMatchBuilder.java
+++ b/components/omnibox/browser/android/javatests/src/org/chromium/components/omnibox/AutocompleteMatchBuilder.java
@@ -11,6 +11,7 @@
 import org.chromium.components.omnibox.action.OmniboxPedal;
 import org.chromium.components.query_tiles.QueryTile;
 import org.chromium.url.GURL;
+import org.chromium.url.JUnitTestGURLs;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -56,7 +57,8 @@
                 .setIsSearch(true)
                 .setDisplayText("Dummy Suggestion")
                 .setDescription("Dummy Description")
-                .setUrl(new GURL("http://dummy-website.com/test"));
+                // Use either JUnitTest or actual GURL (depends on whether ShadowGURL is applied).
+                .setUrl(new GURL(JUnitTestGURLs.SEARCH_URL));
     }
 
     public AutocompleteMatchBuilder(@OmniboxSuggestionType int type) {
diff --git a/components/safe_browsing/core/common/features.cc b/components/safe_browsing/core/common/features.cc
index e4e8f99..1309a829 100644
--- a/components/safe_browsing/core/common/features.cc
+++ b/components/safe_browsing/core/common/features.cc
@@ -116,6 +116,9 @@
 const base::Feature kSimplifiedUrlDisplay{"SimplifiedUrlDisplay",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kTailoredSecurityDesktopNotice{
+    "TailoredSecurityDesktopNotice", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kTailoredSecurityIntegration{
     "TailoredSecurityIntegration", base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/components/safe_browsing/core/common/features.h b/components/safe_browsing/core/common/features.h
index a6eea513..63b5960 100644
--- a/components/safe_browsing/core/common/features.h
+++ b/components/safe_browsing/core/common/features.h
@@ -141,6 +141,12 @@
 // default and control groups of the experiment.
 extern const base::Feature kSimplifiedUrlDisplay;
 
+// Controls whether to automatically enable Enhanced Protection for desktop
+// tailored security users. If not enabled, users of tailored security are
+// notified that they can enable Enhanced Protection through an operating system
+// notification.
+extern const base::Feature kTailoredSecurityDesktopNotice;
+
 // Controls whether the integration of tailored security settings is enabled.
 extern const base::Feature kTailoredSecurityIntegration;
 
diff --git a/components/sync/engine/cycle/sync_cycle_snapshot_unittest.cc b/components/sync/engine/cycle/sync_cycle_snapshot_unittest.cc
index d33ffe2..1c740ae 100644
--- a/components/sync/engine/cycle/sync_cycle_snapshot_unittest.cc
+++ b/components/sync/engine/cycle/sync_cycle_snapshot_unittest.cc
@@ -51,24 +51,25 @@
       /*has_remaining_local_changes=*/false);
   std::unique_ptr<base::DictionaryValue> value(snapshot.ToValue());
   EXPECT_EQ(14u, value->DictSize());
-  ExpectDictStringValue(kBirthday, *value, "birthday");
+  const base::Value::Dict& dict = value->GetDict();
+  ExpectDictStringValue(kBirthday, dict, "birthday");
   // Base64-encoded version of |kBagOfChips|.
-  ExpectDictStringValue("YmFnb2ZjaGlwcwE=", *value, "bagOfChips");
-  ExpectDictIntegerValue(model_neutral.num_successful_commits, *value,
+  ExpectDictStringValue("YmFnb2ZjaGlwcwE=", dict, "bagOfChips");
+  ExpectDictIntegerValue(model_neutral.num_successful_commits, dict,
                          "numSuccessfulCommits");
-  ExpectDictIntegerValue(model_neutral.num_successful_bookmark_commits, *value,
+  ExpectDictIntegerValue(model_neutral.num_successful_bookmark_commits, dict,
                          "numSuccessfulBookmarkCommits");
-  ExpectDictIntegerValue(model_neutral.num_updates_downloaded_total, *value,
+  ExpectDictIntegerValue(model_neutral.num_updates_downloaded_total, dict,
                          "numUpdatesDownloadedTotal");
   ExpectDictIntegerValue(model_neutral.num_tombstone_updates_downloaded_total,
-                         *value, "numTombstoneUpdatesDownloadedTotal");
-  ExpectDictValue(*expected_download_progress_markers_value, *value,
+                         dict, "numTombstoneUpdatesDownloadedTotal");
+  ExpectDictValue(*expected_download_progress_markers_value, dict,
                   "downloadProgressMarkers");
-  ExpectDictBooleanValue(kIsSilenced, *value, "isSilenced");
-  ExpectDictIntegerValue(kNumServerConflicts, *value, "numServerConflicts");
-  ExpectDictBooleanValue(false, *value, "notificationsEnabled");
-  ExpectDictBooleanValue(false, *value, "hasRemainingLocalChanges");
-  ExpectDictStringValue("0h 30m", *value, "poll_interval");
+  ExpectDictBooleanValue(kIsSilenced, dict, "isSilenced");
+  ExpectDictIntegerValue(kNumServerConflicts, dict, "numServerConflicts");
+  ExpectDictBooleanValue(false, dict, "notificationsEnabled");
+  ExpectDictBooleanValue(false, dict, "hasRemainingLocalChanges");
+  ExpectDictStringValue("0h 30m", dict, "poll_interval");
   // poll_finish_time includes the local time zone, so simply verify its
   // existence.
   EXPECT_TRUE(
diff --git a/components/ui_devtools/OWNERS b/components/ui_devtools/OWNERS
index 3b961a1d..b8580f13 100644
--- a/components/ui_devtools/OWNERS
+++ b/components/ui_devtools/OWNERS
@@ -1,2 +1,2 @@
-sadrul@chromium.org
+kerenzhu@chromium.org
 lgrey@chromium.org
diff --git a/components/ui_devtools/views/OWNERS b/components/ui_devtools/views/OWNERS
index 3b961a1d..b8580f13 100644
--- a/components/ui_devtools/views/OWNERS
+++ b/components/ui_devtools/views/OWNERS
@@ -1,2 +1,2 @@
-sadrul@chromium.org
+kerenzhu@chromium.org
 lgrey@chromium.org
diff --git a/components/viz/service/display_embedder/compositor_gpu_thread.cc b/components/viz/service/display_embedder/compositor_gpu_thread.cc
index 06e2cb2..e3a72cb 100644
--- a/components/viz/service/display_embedder/compositor_gpu_thread.cc
+++ b/components/viz/service/display_embedder/compositor_gpu_thread.cc
@@ -20,6 +20,7 @@
 #include "gpu/ipc/common/gpu_client_ids.h"
 #include "gpu/ipc/service/gpu_channel_manager.h"
 #include "gpu/vulkan/buildflags.h"
+#include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_surface_egl.h"
 #include "ui/gl/init/gl_factory.h"
@@ -48,7 +49,7 @@
   // that instead of enabling/disabling DrDc based on the extension.
   if (gl::GetGLImplementation() == gl::kGLImplementationEGLANGLE)
     DCHECK(gl::GLSurfaceEGL::GetGLDisplayEGL()
-               ->IsANGLEContextVirtualizationSupported());
+               ->ext->b_EGL_ANGLE_context_virtualization);
 #endif
 
   scoped_refptr<VulkanContextProvider> vulkan_context_provider;
diff --git a/components/viz/service/display_embedder/skia_output_surface_dependency.h b/components/viz/service/display_embedder/skia_output_surface_dependency.h
index 43dadb7..0683b7e 100644
--- a/components/viz/service/display_embedder/skia_output_surface_dependency.h
+++ b/components/viz/service/display_embedder/skia_output_surface_dependency.h
@@ -89,9 +89,13 @@
       gl::GLSurfaceFormat format) = 0;
   // Hold a ref of the given surface until the returned closure is fired.
   virtual base::ScopedClosureRunner CacheGLSurface(gl::GLSurface* surface) = 0;
-  virtual void PostTaskToClientThread(base::OnceClosure closure) = 0;
   virtual void ScheduleGrContextCleanup() = 0;
 
+  void PostTaskToClientThread(base::OnceClosure closure) {
+    GetClientTaskRunner()->PostTask(FROM_HERE, std::move(closure));
+  }
+  virtual scoped_refptr<base::TaskRunner> GetClientTaskRunner() = 0;
+
   // This function schedules delayed task to be run on GPUThread. It can be
   // called only from GPU Thread.
   virtual void ScheduleDelayedGPUTaskFromGPUThread(base::OnceClosure task) = 0;
diff --git a/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc b/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc
index 342f27f9..8a7a0354 100644
--- a/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc
@@ -127,9 +127,9 @@
   return base::ScopedClosureRunner(std::move(release_callback));
 }
 
-void SkiaOutputSurfaceDependencyImpl::PostTaskToClientThread(
-    base::OnceClosure closure) {
-  client_thread_task_runner_->PostTask(FROM_HERE, std::move(closure));
+scoped_refptr<base::TaskRunner>
+SkiaOutputSurfaceDependencyImpl::GetClientTaskRunner() {
+  return client_thread_task_runner_;
 }
 
 void SkiaOutputSurfaceDependencyImpl::ScheduleGrContextCleanup() {
diff --git a/components/viz/service/display_embedder/skia_output_surface_dependency_impl.h b/components/viz/service/display_embedder/skia_output_surface_dependency_impl.h
index d8d90af..1d65c148 100644
--- a/components/viz/service/display_embedder/skia_output_surface_dependency_impl.h
+++ b/components/viz/service/display_embedder/skia_output_surface_dependency_impl.h
@@ -52,7 +52,7 @@
       base::WeakPtr<gpu::ImageTransportSurfaceDelegate> stub,
       gl::GLSurfaceFormat format) override;
   base::ScopedClosureRunner CacheGLSurface(gl::GLSurface* surface) override;
-  void PostTaskToClientThread(base::OnceClosure closure) override;
+  scoped_refptr<base::TaskRunner> GetClientTaskRunner() override;
   void ScheduleGrContextCleanup() override;
   void ScheduleDelayedGPUTaskFromGPUThread(base::OnceClosure task) override;
 
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.cc b/components/viz/service/display_embedder/skia_output_surface_impl.cc
index 74fd2601..2ca903a 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/callback_forward.h"
 #include "base/callback_helpers.h"
 #include "base/no_destructor.h"
 #include "base/observer_list.h"
@@ -32,6 +33,7 @@
 #include "components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h"
 #include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
 #include "gpu/command_buffer/common/swap_buffers_complete_params.h"
+#include "gpu/command_buffer/common/sync_token.h"
 #include "gpu/command_buffer/service/scheduler.h"
 #include "gpu/command_buffer/service/shared_image_factory.h"
 #include "gpu/command_buffer/service/shared_image_representation.h"
@@ -852,13 +854,15 @@
       base::BindRepeating(&SkiaOutputSurfaceImpl::BufferPresented, weak_ptr_);
   auto context_lost_callback =
       base::BindOnce(&SkiaOutputSurfaceImpl::ContextLost, weak_ptr_);
+  auto schedule_gpu_task = base::BindRepeating(
+      &SkiaOutputSurfaceImpl::ScheduleOrRetainGpuTask, weak_ptr_);
 
   impl_on_gpu_ = SkiaOutputSurfaceImplOnGpu::Create(
       dependency_, renderer_settings_, gpu_task_scheduler_->GetSequenceId(),
       display_compositor_controller_->controller_on_gpu(),
       std::move(did_swap_buffer_complete_callback),
       std::move(buffer_presented_callback), std::move(context_lost_callback),
-      std::move(vsync_callback_runner));
+      std::move(schedule_gpu_task), std::move(vsync_callback_runner));
   if (!impl_on_gpu_) {
     *result = false;
   } else {
@@ -1252,6 +1256,13 @@
     observer.OnContextLost();
 }
 
+void SkiaOutputSurfaceImpl::ScheduleOrRetainGpuTask(
+    base::OnceClosure callback,
+    std::vector<gpu::SyncToken> tokens) {
+  gpu_task_scheduler_->ScheduleOrRetainGpuTask(std::move(callback),
+                                               std::move(tokens));
+}
+
 gfx::Rect SkiaOutputSurfaceImpl::GetCurrentFramebufferDamage() const {
   if (use_damage_area_from_skia_output_device_) {
     DCHECK(damage_of_current_buffer_);
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.h b/components/viz/service/display_embedder/skia_output_surface_impl.h
index 685a700..2bf5bd4 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.h
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/callback_forward.h"
 #include "base/callback_helpers.h"
 #include "base/containers/circular_deque.h"
 #include "base/memory/raw_ptr.h"
@@ -195,6 +196,8 @@
                       std::vector<gpu::SyncToken> sync_tokens,
                       bool make_current,
                       bool need_framebuffer);
+  void ScheduleOrRetainGpuTask(base::OnceClosure callback,
+                               std::vector<gpu::SyncToken> tokens);
 
   enum class SyncMode {
     kNoWait = 0,
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index dcca5fa9..702b77f 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -9,12 +9,14 @@
 
 #include "base/atomic_sequence_num.h"
 #include "base/bind.h"
+#include "base/callback_forward.h"
 #include "base/callback_helpers.h"
 #include "base/debug/crash_logging.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/notreached.h"
 #include "base/task/bind_post_task.h"
+#include "base/threading/thread_checker.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/trace_event.h"
@@ -24,6 +26,7 @@
 #include "components/viz/common/frame_sinks/copy_output_request.h"
 #include "components/viz/common/frame_sinks/copy_output_util.h"
 #include "components/viz/common/gpu/vulkan_context_provider.h"
+#include "components/viz/common/resources/release_callback.h"
 #include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/common/skia_helper.h"
 #include "components/viz/common/viz_utils.h"
@@ -39,6 +42,7 @@
 #include "components/viz/service/display_embedder/skia_output_device_webview.h"
 #include "components/viz/service/display_embedder/skia_output_surface_dependency.h"
 #include "components/viz/service/display_embedder/skia_render_copy_results.h"
+#include "gpu/command_buffer/common/mailbox.h"
 #include "gpu/command_buffer/common/mailbox_holder.h"
 #include "gpu/command_buffer/common/swap_buffers_complete_params.h"
 #include "gpu/command_buffer/common/sync_token.h"
@@ -264,6 +268,7 @@
     DidSwapBufferCompleteCallback did_swap_buffer_complete_callback,
     BufferPresentedCallback buffer_presented_callback,
     ContextLostCallback context_lost_callback,
+    ScheduleGpuTaskCallback schedule_gpu_task,
     GpuVSyncCallback gpu_vsync_callback) {
   TRACE_EVENT0("viz", "SkiaOutputSurfaceImplOnGpu::Create");
 
@@ -286,7 +291,7 @@
       context_state->feature_info(), renderer_settings, sequence_id,
       shared_gpu_deps, std::move(did_swap_buffer_complete_callback),
       std::move(buffer_presented_callback), std::move(context_lost_callback),
-      std::move(gpu_vsync_callback));
+      std::move(schedule_gpu_task), std::move(gpu_vsync_callback));
   if (!impl_on_gpu->Initialize())
     return nullptr;
 
@@ -303,6 +308,7 @@
     DidSwapBufferCompleteCallback did_swap_buffer_complete_callback,
     BufferPresentedCallback buffer_presented_callback,
     ContextLostCallback context_lost_callback,
+    ScheduleGpuTaskCallback schedule_gpu_task,
     GpuVSyncCallback gpu_vsync_callback)
     : dependency_(std::move(deps)),
       shared_gpu_deps_(shared_gpu_deps),
@@ -324,6 +330,7 @@
       did_swap_buffer_complete_callback_(
           std::move(did_swap_buffer_complete_callback)),
       context_lost_callback_(std::move(context_lost_callback)),
+      schedule_gpu_task_(std::move(schedule_gpu_task)),
       gpu_vsync_callback_(std::move(gpu_vsync_callback)),
       gpu_preferences_(dependency_->GetGpuPreferences()),
       display_context_(std::make_unique<DisplayContext>(deps, this)),
@@ -355,8 +362,9 @@
     }
   }
 
-  for (auto& callback : release_on_gpu_callbacks_)
-    std::move(*callback).Run(gpu::SyncToken(), /*is_lost=*/true);
+  DCHECK(copy_output_images_.empty() || context_state_)
+      << "We must have a valid context if copy requests were serviced";
+  copy_output_images_.clear();
 
   // |output_device_| may still need |shared_image_factory_|, so release it
   // first.
@@ -1310,18 +1318,45 @@
 ReleaseCallback
 SkiaOutputSurfaceImplOnGpu::CreateDestroyCopyOutputResourcesOnGpuThreadCallback(
     std::unique_ptr<gpu::SharedImageRepresentationSkia> representation) {
-  auto gpu_callback = std::make_unique<ReleaseCallback>(base::BindOnce(
+  copy_output_images_.push_back(std::move(representation));
+
+  auto closure_on_gpu_thread = base::BindOnce(
       &SkiaOutputSurfaceImplOnGpu::DestroyCopyOutputResourcesOnGpuThread,
-      weak_ptr_factory_.GetWeakPtr(), std::move(representation),
-      context_state_));
-  release_on_gpu_callbacks_.push_back(std::move(gpu_callback));
+      weak_ptr_, copy_output_images_.back()->mailbox());
 
-  auto run_gpu_callback = base::BindOnce(
-      &SkiaOutputSurfaceImplOnGpu::RunDestroyCopyOutputResourcesOnGpuThread,
-      weak_ptr_factory_.GetWeakPtr(), release_on_gpu_callbacks_.back().get());
+  // The destruction sequence for the textures cached by |copy_output_images_|
+  // is as follows:
+  // 1) The ReleaseCallback returned here can be invoked on any thread. When
+  //    invoked, we post a task to the client thread with sync token
+  //    dependencies that must be met before the texture can be released.
+  // 2) When this task runs on the Viz thread, it will retain the closure above
+  //    until the next draw (for WebView). At the next draw, the Viz thread
+  //    synchronously waits to satisfy the sync token dependencies.
+  // 3) Once the step above finishes, the closure is dispatched on the GPU
+  //    thread (or render thread on WebView).
+  ReleaseCallback release_callback = base::BindOnce(
+      [](ScheduleGpuTaskCallback schedule_gpu_task, base::OnceClosure callback,
+         const gpu::SyncToken& sync_token,
+         bool) { schedule_gpu_task.Run(std::move(callback), {sync_token}); },
+      schedule_gpu_task_, std::move(closure_on_gpu_thread));
 
-  return base::BindPostTask(base::ThreadTaskRunnerHandle::Get(),
-                            std::move(run_gpu_callback));
+  return base::BindPostTask(dependency_->GetClientTaskRunner(),
+                            std::move(release_callback));
+}
+
+void SkiaOutputSurfaceImplOnGpu::DestroyCopyOutputResourcesOnGpuThread(
+    const gpu::Mailbox& mailbox) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  for (size_t i = 0; i < copy_output_images_.size(); ++i) {
+    if (copy_output_images_[i]->mailbox() == mailbox) {
+      context_state_->MakeCurrent(nullptr);
+      copy_output_images_.erase(copy_output_images_.begin() + i);
+      return;
+    }
+  }
+  NOTREACHED() << "The Callback returned by GetDeleteCallback() was called "
+               << "more than once.";
 }
 
 void SkiaOutputSurfaceImplOnGpu::CopyOutput(
@@ -1479,30 +1514,6 @@
   ScheduleCheckReadbackCompletion();
 }
 
-void SkiaOutputSurfaceImplOnGpu::RunDestroyCopyOutputResourcesOnGpuThread(
-    ReleaseCallback* callback,
-    const gpu::SyncToken& sync_token,
-    bool is_lost) {
-  for (size_t i = 0; i < release_on_gpu_callbacks_.size(); ++i) {
-    if (release_on_gpu_callbacks_[i].get() == callback) {
-      std::move(*release_on_gpu_callbacks_[i]).Run(sync_token, is_lost);
-      release_on_gpu_callbacks_.erase(release_on_gpu_callbacks_.begin() + i);
-      return;
-    }
-  }
-  NOTREACHED() << "The Callback returned by GetDeleteCallback() was called "
-               << "more than once.";
-}
-
-void SkiaOutputSurfaceImplOnGpu::DestroyCopyOutputResourcesOnGpuThread(
-    std::unique_ptr<gpu::SharedImageRepresentationSkia> representation,
-    scoped_refptr<gpu::SharedContextState> context_state,
-    const gpu::SyncToken& sync_token,
-    bool is_lost) {
-  context_state_->MakeCurrent(nullptr);
-  representation.reset();
-}
-
 void SkiaOutputSurfaceImplOnGpu::BeginAccessImages(
     const std::vector<ImageContextImpl*>& image_contexts,
     std::vector<GrBackendSemaphore>* begin_semaphores,
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
index 204eebd..9b27550 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -11,6 +11,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/callback_forward.h"
 #include "base/containers/span.h"
 #include "base/memory/raw_ptr.h"
 #include "base/threading/thread_checker.h"
@@ -94,6 +95,10 @@
       base::RepeatingCallback<void(const gfx::PresentationFeedback& feedback)>;
   using ContextLostCallback = base::OnceClosure;
 
+  using ScheduleGpuTaskCallback =
+      base::RepeatingCallback<void(base::OnceClosure,
+                                   std::vector<gpu::SyncToken>)>;
+
   // |gpu_vsync_callback| must be safe to call on any thread. The other
   // callbacks will only be called via |deps->PostTaskToClientThread|.
   static std::unique_ptr<SkiaOutputSurfaceImplOnGpu> Create(
@@ -104,6 +109,7 @@
       DidSwapBufferCompleteCallback did_swap_buffer_complete_callback,
       BufferPresentedCallback buffer_presented_callback,
       ContextLostCallback context_lost_callback,
+      ScheduleGpuTaskCallback schedule_gpu_task,
       GpuVSyncCallback gpu_vsync_callback);
 
   SkiaOutputSurfaceImplOnGpu(
@@ -116,6 +122,7 @@
       DidSwapBufferCompleteCallback did_swap_buffer_complete_callback,
       BufferPresentedCallback buffer_presented_callback,
       ContextLostCallback context_lost_callback,
+      ScheduleGpuTaskCallback schedule_gpu_task,
       GpuVSyncCallback gpu_vsync_callback);
 
   SkiaOutputSurfaceImplOnGpu(const SkiaOutputSurfaceImplOnGpu&) = delete;
@@ -278,16 +285,7 @@
 
   void MarkContextLost(ContextLostReason reason);
 
-  void RunDestroyCopyOutputResourcesOnGpuThread(
-      ReleaseCallback* callback,
-      const gpu::SyncToken& sync_token,
-      bool is_lost);
-
-  void DestroyCopyOutputResourcesOnGpuThread(
-      std::unique_ptr<gpu::SharedImageRepresentationSkia> representation,
-      scoped_refptr<gpu::SharedContextState> context_state,
-      const gpu::SyncToken& sync_token,
-      bool is_lost);
+  void DestroyCopyOutputResourcesOnGpuThread(const gpu::Mailbox& mailbox);
 
   void SwapBuffersInternal(absl::optional<OutputSurfaceFrame> frame);
   void PostSubmit(absl::optional<OutputSurfaceFrame> frame);
@@ -431,15 +429,17 @@
   DidSwapBufferCompleteCallback did_swap_buffer_complete_callback_;
   BufferPresentedCallback buffer_presented_callback_;
   ContextLostCallback context_lost_callback_;
+  ScheduleGpuTaskCallback schedule_gpu_task_;
   GpuVSyncCallback gpu_vsync_callback_;
 
   // ImplOnGpu::CopyOutput can create SharedImages via ImplOnGpu's
   // SharedImageFactory. Clients can use these images via CopyOutputResult and
   // when done, release the resources by invoking the provided callback. If
   // ImplOnGpu is already destroyed, however, there is no way of running the
-  // release callback from the client, so this vector holds all pending release
-  // callbacks so resources can still be cleaned up in the dtor.
-  std::vector<std::unique_ptr<ReleaseCallback>> release_on_gpu_callbacks_;
+  // release callback from the client, so this vector holds all pending images
+  // so resources can still be cleaned up in the dtor.
+  std::vector<std::unique_ptr<gpu::SharedImageRepresentationSkia>>
+      copy_output_images_;
 
   // Helper, creates a release callback for the passed in |representation|.
   ReleaseCallback CreateDestroyCopyOutputResourcesOnGpuThreadCallback(
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
index 411603d..d4924b12 100644
--- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
+++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
@@ -971,7 +971,17 @@
     return;
   }
 
-  if (absl::holds_alternative<RegionCaptureCropId>(target_->sub_target)) {
+  // If the target is in a different renderer than the root renderer (indicated
+  // by having a different frame sink ID), we currently cannot provide
+  // reasonable metadata about the region capture rect. For more context, see
+  // https://crbug.com/1327560.
+  //
+  // TODO(https://crbug.com/1335175): Provide accurate bounds for elements
+  // embedded in different renderers.
+  const bool is_same_frame_sink_as_requested =
+      resolved_target_->GetFrameSinkId() == target_->frame_sink_id;
+  if (absl::holds_alternative<RegionCaptureCropId>(target_->sub_target) &&
+      is_same_frame_sink_as_requested) {
     const float scale_factor = frame_metadata.device_scale_factor;
     metadata.region_capture_rect =
         scale_factor ? ScaleToEnclosingRect(capture_region, 1.0f / scale_factor)
diff --git a/components/webrtc/BUILD.gn b/components/webrtc/BUILD.gn
index b9e6f308..0f641b599 100644
--- a/components/webrtc/BUILD.gn
+++ b/components/webrtc/BUILD.gn
@@ -99,16 +99,3 @@
     "//third_party/webrtc_overrides:metronome_like_task_queue_test",
   ]
 }
-
-if (is_android) {
-  java_cpp_features("java_features_srcjar") {
-    # External code should depend on ":components_webrtc_java" instead.
-    visibility = [ ":*" ]
-    sources = [ "//components/webrtc/thread_wrapper.cc" ]
-    template =
-        "//components/webrtc/java_templates/ComponentsWebRtcFeatures.java.tmpl"
-  }
-  android_library("components_webrtc_java") {
-    srcjar_deps = [ ":java_features_srcjar" ]
-  }
-}
diff --git a/components/webrtc/java_templates/ComponentsWebRtcFeatures.java.tmpl b/components/webrtc/java_templates/ComponentsWebRtcFeatures.java.tmpl
deleted file mode 100644
index 0586785..0000000
--- a/components/webrtc/java_templates/ComponentsWebRtcFeatures.java.tmpl
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.webrtc;
-
-/**
- * Contains features that are specific to components/webrtc/.
- */
-public final class ComponentsWebRtcFeatures {{
-
-{NATIVE_FEATURES}
-
-    // Prevents instantiation.
-    private ComponentsWebRtcFeatures() {{}}
-}}
diff --git a/components/webrtc/thread_wrapper.cc b/components/webrtc/thread_wrapper.cc
index 34714c5..f35c3d41 100644
--- a/components/webrtc/thread_wrapper.cc
+++ b/components/webrtc/thread_wrapper.cc
@@ -29,9 +29,6 @@
 constexpr base::TimeDelta kTaskLatencySampleDuration = base::Seconds(3);
 }
 
-const base::Feature kThreadWrapperUsesMetronome{
-    "ThreadWrapperUsesMetronome", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Class intended to conditionally live for the duration of ThreadWrapper
 // that periodically captures task latencies (definition in docs for
 // SetLatencyAndTaskDurationCallbacks).
@@ -139,7 +136,6 @@
     : Thread(std::make_unique<rtc::PhysicalSocketServer>()),
       task_runner_(task_runner),
       send_allowed_(false),
-      use_metronome_(base::FeatureList::IsEnabled(kThreadWrapperUsesMetronome)),
       last_task_id_(0),
       pending_send_event_(base::WaitableEvent::ResetPolicy::MANUAL,
                           base::WaitableEvent::InitialState::NOT_SIGNALED) {
@@ -341,26 +337,17 @@
                                     uint32_t milliseconds) {
   base::TimeTicks target_time =
       base::TimeTicks::Now() + base::Milliseconds(milliseconds);
-  if (use_metronome_) {
-    // Coalesce tasks onto the metronome.
-    base::TimeTicks snapped_target_time =
-        blink::MetronomeSource::TimeSnappedToNextTick(target_time);
-    if (coalesced_tasks_.QueueDelayedTask(target_time, std::move(task),
-                                          snapped_target_time)) {
-      task_runner_->PostDelayedTaskAt(
-          base::subtle::PostDelayedTaskPassKey(), FROM_HERE,
-          base::BindOnce(&ThreadWrapper::RunCoalescedTaskQueueTasks, weak_ptr_,
-                         snapped_target_time),
-          snapped_target_time, base::subtle::DelayPolicy::kPrecise);
-    }
-    return;
+  // Coalesce low precision tasks onto the metronome.
+  base::TimeTicks snapped_target_time =
+      blink::MetronomeSource::TimeSnappedToNextTick(target_time);
+  if (coalesced_tasks_.QueueDelayedTask(target_time, std::move(task),
+                                        snapped_target_time)) {
+    task_runner_->PostDelayedTaskAt(
+        base::subtle::PostDelayedTaskPassKey(), FROM_HERE,
+        base::BindOnce(&ThreadWrapper::RunCoalescedTaskQueueTasks, weak_ptr_,
+                       snapped_target_time),
+        snapped_target_time, base::subtle::DelayPolicy::kPrecise);
   }
-  // Do not coalesce tasks onto the metronome.
-  task_runner_->PostDelayedTaskAt(
-      base::subtle::PostDelayedTaskPassKey(), FROM_HERE,
-      base::BindOnce(&ThreadWrapper::RunTaskQueueTask, weak_ptr_,
-                     std::move(task)),
-      target_time, base::subtle::DelayPolicy::kPrecise);
 }
 
 void ThreadWrapper::PostDelayedHighPrecisionTask(
diff --git a/components/webrtc/thread_wrapper.h b/components/webrtc/thread_wrapper.h
index df5572f..86ef52aa 100644
--- a/components/webrtc/thread_wrapper.h
+++ b/components/webrtc/thread_wrapper.h
@@ -26,10 +26,6 @@
 
 namespace webrtc {
 
-// Whether ThreadWrapper should schedule low-precision tasks on the metronome.
-// Default: disabled.
-extern const base::Feature kThreadWrapperUsesMetronome;
-
 // ThreadWrapper implements rtc::Thread interface on top of
 // Chromium's SingleThreadTaskRunner interface. Currently only the bare minimum
 // that is used by P2P part of libjingle is implemented. There are two ways to
@@ -174,7 +170,6 @@
 
   bool send_allowed_;
 
-  const bool use_metronome_;
   // |lock_| must be locked when accessing |messages_|.
   base::Lock lock_;
   int last_task_id_;
@@ -184,9 +179,8 @@
   std::unique_ptr<PostTaskLatencySampler> latency_sampler_;
   SampledDurationCallback task_latency_callback_;
   SampledDurationCallback task_duration_callback_;
-  // If |kThreadWrapperUsesMetronome| is enabled, low precision tasks are
-  // coalesced onto metronome ticks and stored in |coalesced_tasks_| until they
-  // are ready to run.
+  // Low precision tasks are coalesced onto metronome ticks and stored in
+  // `coalesced_tasks_` until they are ready to run.
   blink::CoalescedTasks coalesced_tasks_;
 
   base::WeakPtr<ThreadWrapper> weak_ptr_;
diff --git a/components/webrtc/thread_wrapper_unittest.cc b/components/webrtc/thread_wrapper_unittest.cc
index c7d0c15..13ea7e32 100644
--- a/components/webrtc/thread_wrapper_unittest.cc
+++ b/components/webrtc/thread_wrapper_unittest.cc
@@ -13,7 +13,6 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/task/thread_pool.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/threading/thread.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -319,7 +318,6 @@
 class ThreadWrapperProvider : public blink::MetronomeLikeTaskQueueProvider {
  public:
   void Initialize() override {
-    scoped_feature_list_.InitAndEnableFeature(kThreadWrapperUsesMetronome);
     ThreadWrapper::EnsureForCurrentMessageLoop();
     thread_ = rtc::Thread::Current();
   }
@@ -334,7 +332,6 @@
   webrtc::TaskQueueBase* TaskQueue() const override { return thread_; }
 
  private:
-  base::test::ScopedFeatureList scoped_feature_list_;
   // ThreadWrapper destroys itself when |message_loop_| is destroyed.
   raw_ptr<rtc::Thread> thread_;
 };
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
index 63e912c..313c258 100644
--- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc
+++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -310,6 +310,12 @@
       test_helper_.GetExpectationFilePath(file_path, expectations_qualifier);
   if (!expected_file.empty()) {
     expected_lines = test_helper_.LoadExpectationFile(expected_file);
+  } else if (GetParam() == ui::AXApiType::kWinUIA) {
+    // TODO: UIA is not yet supported, see crbug.com/1327652, crbug.com/1329523,
+    // crbug.com/1329847.
+    LOG(INFO) << "No expectation file present, ignoring test on this "
+                 "platform.";
+    return;
   }
 #if BUILDFLAG(IS_FUCHSIA)
   else {
@@ -318,13 +324,6 @@
     return;
   }
 #endif
-  // TODO: UIA is not yet supported, see crbug.com/1327652, crbug.com/1329523,
-  // crbug.com/1329847.
-  if (GetParam() == ui::AXApiType::kWinUIA) {
-    LOG(INFO) << "No expectation file present, ignoring test on this "
-                 "platform.";
-    return;
-  }
 
   // Get the test URL.
   GURL url(embedded_test_server()->GetURL(
diff --git a/content/browser/attribution_reporting/attributions_browsertest.cc b/content/browser/attribution_reporting/attributions_browsertest.cc
index 606711678..a6d38c499 100644
--- a/content/browser/attribution_reporting/attributions_browsertest.cc
+++ b/content/browser/attribution_reporting/attributions_browsertest.cc
@@ -112,25 +112,28 @@
 
     base::Value body = base::test::ParseJson(request.content);
     EXPECT_THAT(body, base::test::DictionaryHasValues(expected_body));
+    const base::Value::Dict& body_dict = body.GetDict();
 
     // The report ID is random, so just test that the field exists here and is a
     // valid GUID.
-    std::string* report_id = body.FindStringKey("report_id");
-    EXPECT_TRUE(report_id);
+    const std::string* report_id = body_dict.FindString("report_id");
+    ASSERT_TRUE(report_id);
     EXPECT_TRUE(base::GUID::ParseLowercase(*report_id).is_valid());
 
-    EXPECT_TRUE(body.FindDoubleKey("randomized_trigger_rate"));
+    EXPECT_TRUE(body_dict.FindDouble("randomized_trigger_rate"));
 
     if (source_debug_key.empty()) {
-      EXPECT_FALSE(body.FindStringKey("source_debug_key"));
+      EXPECT_FALSE(body_dict.FindString("source_debug_key"));
     } else {
-      base::ExpectDictStringValue(source_debug_key, body, "source_debug_key");
+      base::ExpectDictStringValue(source_debug_key, body_dict,
+                                  "source_debug_key");
     }
 
     if (trigger_debug_key.empty()) {
-      EXPECT_FALSE(body.FindStringKey("trigger_debug_key"));
+      EXPECT_FALSE(body_dict.FindString("trigger_debug_key"));
     } else {
-      base::ExpectDictStringValue(trigger_debug_key, body, "trigger_debug_key");
+      base::ExpectDictStringValue(trigger_debug_key, body_dict,
+                                  "trigger_debug_key");
     }
 
     // Clear the port as it is assigned by the EmbeddedTestServer at runtime.
diff --git a/content/browser/cache_storage/cache_storage.cc b/content/browser/cache_storage/cache_storage.cc
index 5923cfd..42e8025d 100644
--- a/content/browser/cache_storage/cache_storage.cc
+++ b/content/browser/cache_storage/cache_storage.cc
@@ -351,11 +351,14 @@
     // backwards compatibility with older data. The serializations are
     // subtly different, e.g. Origin does not include a trailing "/".
     // TODO(crbug.com/809329): Add a test for validating fields in the proto
-    //
-    // TODO(https://crbug.com/1199077): We need to serialize the entire
-    // `storage_key_` into the index file.
+    // TODO(https://crbug.com/1199077): Stop setting the origin field once
+    // `CacheStorageManager` no longer uses the origin as a fallback for
+    // getting the storage key associated with each cache (for more info, see
+    // `GetStorageKeysAndLastModifiedOnTaskRunner`).
     protobuf_index.set_origin(storage_key_.origin().GetURL().spec());
 
+    protobuf_index.set_storage_key(storage_key_.Serialize());
+
     for (const auto& cache_metadata : index.ordered_cache_metadata()) {
       DCHECK(base::Contains(cache_name_to_cache_dir_, cache_metadata.name));
 
@@ -548,6 +551,12 @@
       }
     }
 
+    if (!index.has_storage_key()) {
+      DCHECK(storage_key.origin().GetURL().spec() == index.origin());
+      index.set_storage_key(storage_key.Serialize());
+      index_modified = true;
+    }
+
     if (index_modified) {
       base::FilePath tmp_path = origin_path.AppendASCII("index.txt.tmp");
       if (!index.SerializeToString(&body) ||
diff --git a/content/browser/cache_storage/cache_storage.proto b/content/browser/cache_storage/cache_storage.proto
index 87fedf7..3a4ea30 100644
--- a/content/browser/cache_storage/cache_storage.proto
+++ b/content/browser/cache_storage/cache_storage.proto
@@ -18,7 +18,8 @@
     optional int32 padding_version = 6;
   }
   repeated Cache cache = 1;
-  optional string origin = 2;
+  optional string origin = 2 [deprecated = true];
+  optional string storage_key = 3;
 }
 
 message CacheHeaderMap {
diff --git a/content/browser/cache_storage/cache_storage_manager.cc b/content/browser/cache_storage/cache_storage_manager.cc
index b90a673..b0e5466 100644
--- a/content/browser/cache_storage/cache_storage_manager.cc
+++ b/content/browser/cache_storage/cache_storage_manager.cc
@@ -104,8 +104,9 @@
   kEmptyOriginUrl = 3,
   kPathMismatch = 4,
   kPathFileInfoFailed = 5,
+  kInvalidStorageKey = 6,
   // Add new enums above
-  kMaxValue = kPathFileInfoFailed,
+  kMaxValue = kInvalidStorageKey,
 };
 
 IndexResult ValidateIndex(proto::CacheStorageIndex index) {
@@ -116,6 +117,10 @@
   if (url.is_empty())
     return IndexResult::kEmptyOriginUrl;
 
+  // TODO(https://crbug.com/1199077): Consider adding a
+  // 'index.has_storage_key()' check here once we've ensured that a
+  // sufficient number of CacheStorage instances have been migrated (or
+  // verified that `ValidateIndex` won't be passed an unmigrated `index`).
   return IndexResult::kOk;
 }
 
@@ -157,8 +162,25 @@
       continue;
     }
 
-    auto storage_key =
-        blink::StorageKey(url::Origin::Create(GURL(index.origin())));
+    blink::StorageKey storage_key;
+    if (index.has_storage_key()) {
+      absl::optional<blink::StorageKey> result =
+          blink::StorageKey::Deserialize(index.storage_key());
+      if (!result) {
+        RecordIndexValidationResult(IndexResult::kInvalidStorageKey);
+        continue;
+      }
+      storage_key = result.value();
+    } else {
+      // TODO(https://crbug.com/1199077): Since index file migrations happen
+      // lazily, it's plausible that the index file we are reading doesn't have
+      // a storage key yet. For now, fall back to creating the storage key
+      // from the origin. This should be removed after either enough time has
+      // passed for most caches to have been migrated naturally or after we
+      // implement follow-on code that can force a migration.
+      storage_key =
+          blink::StorageKey(url::Origin::Create(GURL(index.origin())));
+    }
     DCHECK(!storage_key.origin().GetURL().is_empty());
 
     auto origin_path = CacheStorageManager::ConstructStorageKeyPath(
diff --git a/content/browser/cache_storage/cache_storage_manager_unittest.cc b/content/browser/cache_storage/cache_storage_manager_unittest.cc
index 5ac043a75..394d4ac 100644
--- a/content/browser/cache_storage/cache_storage_manager_unittest.cc
+++ b/content/browser/cache_storage/cache_storage_manager_unittest.cc
@@ -2597,6 +2597,22 @@
              }));
 }
 
+TEST_F(CacheStorageIndexMigrationTest, StorageKeyMigration) {
+  DoTest("content/test/data/cache_storage/storage_key/",
+         base::BindLambdaForTesting(
+             [this](const proto::CacheStorageIndex& original_index,
+                    const proto::CacheStorageIndex& upgraded_index,
+                    int64_t total_usage) {
+               EXPECT_FALSE(original_index.has_storage_key());
+               EXPECT_TRUE(upgraded_index.has_storage_key());
+
+               absl::optional<blink::StorageKey> result =
+                   blink::StorageKey::Deserialize(upgraded_index.storage_key());
+               ASSERT_TRUE(result.has_value());
+               EXPECT_EQ(this->storage_key1_, result.value());
+             }));
+}
+
 INSTANTIATE_TEST_SUITE_P(CacheStorageManagerTests,
                          CacheStorageManagerTestP,
                          ::testing::Values(TestStorage::kMemory,
diff --git a/content/browser/media/capture_handle_manager.cc b/content/browser/media/capture_handle_manager.cc
index a2174789..4475eac 100644
--- a/content/browser/media/capture_handle_manager.cc
+++ b/content/browser/media/capture_handle_manager.cc
@@ -43,7 +43,7 @@
 
   // Observing CaptureHandle wheneither the capturing or the captured party
   // is incognito is disallowed, except for self-capture.
-  if (capturer->GetMainFrame() != captured->GetMainFrame()) {
+  if (capturer->GetMainFrame() != captured->GetPrimaryMainFrame()) {
     if (capturer->GetBrowserContext()->IsOffTheRecord() ||
         captured->GetBrowserContext()->IsOffTheRecord()) {
       return nullptr;
@@ -52,7 +52,7 @@
 
   auto result = media::mojom::CaptureHandle::New();
   if (capture_handle_config.expose_origin) {
-    result->origin = captured->GetMainFrame()->GetLastCommittedOrigin();
+    result->origin = captured->GetPrimaryMainFrame()->GetLastCommittedOrigin();
   }
   result->capture_handle = capture_handle_config.capture_handle;
 
diff --git a/content/browser/preloading_data_impl.cc b/content/browser/preloading_data_impl.cc
index 0cf9bf05..56db477 100644
--- a/content/browser/preloading_data_impl.cc
+++ b/content/browser/preloading_data_impl.cc
@@ -37,7 +37,7 @@
   // TODO(crbug.com/1330783): Extend this for non-primary page and inner
   // WebContents preloading attempts.
   ukm::SourceId triggered_primary_page_source_id =
-      web_contents()->GetMainFrame()->GetPageUkmSourceId();
+      web_contents()->GetPrimaryMainFrame()->GetPageUkmSourceId();
 
   auto attempt = std::make_unique<PreloadingAttemptImpl>(
       predictor, preloading_type, triggered_primary_page_source_id,
@@ -59,7 +59,7 @@
   // TODO(crbug.com/1330783): Extend this for non-primary page and inner
   // WebContents preloading predictions.
   ukm::SourceId triggered_primary_page_source_id =
-      web_contents()->GetMainFrame()->GetPageUkmSourceId();
+      web_contents()->GetPrimaryMainFrame()->GetPageUkmSourceId();
 
   auto prediction = std::make_unique<PreloadingPrediction>(
       predictor, confidence, triggered_primary_page_source_id,
diff --git a/content/browser/renderer_host/input/fling_browsertest.cc b/content/browser/renderer_host/input/fling_browsertest.cc
index 61b5f7c..6988223 100644
--- a/content/browser/renderer_host/input/fling_browsertest.cc
+++ b/content/browser/renderer_host/input/fling_browsertest.cc
@@ -351,9 +351,10 @@
   EXPECT_TRUE(GetWidgetHost()->GetView()->view_stopped_flinging_for_test());
 }
 
-// Flaky on Linux ASAN and TSAN. https://crbug.com/1269960
-#if BUILDFLAG(IS_LINUX) && \
-    (defined(THREAD_SANITIZER) || defined(ADDRESS_SANITIZER))
+// Flaky on Linux ASAN, TSAN and MSAN. https://crbug.com/1269960
+#if BUILDFLAG(IS_LINUX) &&                                      \
+    (defined(THREAD_SANITIZER) || defined(ADDRESS_SANITIZER) || \
+     defined(MEMORY_SANITIZER))
 #define MAYBE_FlingingStopsAfterNavigation DISABLED_FlingingStopsAfterNavigation
 #else
 #define MAYBE_FlingingStopsAfterNavigation FlingingStopsAfterNavigation
diff --git a/content/browser/renderer_host/render_widget_host_browsertest.cc b/content/browser/renderer_host/render_widget_host_browsertest.cc
index 88a78e3..0bcbbc6 100644
--- a/content/browser/renderer_host/render_widget_host_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_browsertest.cc
@@ -978,4 +978,46 @@
       host()->render_frame_metadata_provider()->LastRenderFrameMetadata());
 }
 
+// If the DelegatedInkTrailPresenter creates a metadata that has the same
+// timestamp as the previous one, it does not set the metadata.
+IN_PROC_BROWSER_TEST_F(RenderWidgetHostDelegatedInkMetadataTest,
+                       DuplicateMetadata) {
+  ASSERT_TRUE(ExecJs(shell()->web_contents(), R"(
+      let presenter = null;
+      navigator.ink.requestPresenter().then(e => { presenter = e; });
+      let style = { color: 'green', diameter: 21 };
+      let first_move_event = null;
+
+      window.addEventListener('pointermove' , evt => {
+        if (first_move_event == null) {
+          first_move_event = evt;
+        }
+        presenter.updateInkTrailStartPoint(first_move_event, style);
+      });
+      )"));
+  SimulateRoutedMouseEvent(blink::WebInputEvent::Type::kMouseMove, 10, 10, 0,
+                           false);
+  RunUntilInputProcessed(host());
+
+  {
+    const cc::RenderFrameMetadata& last_metadata =
+        host()->render_frame_metadata_provider()->LastRenderFrameMetadata();
+    EXPECT_TRUE(last_metadata.delegated_ink_metadata.has_value());
+    EXPECT_TRUE(
+        last_metadata.delegated_ink_metadata.value().delegated_ink_is_hovering);
+  }
+
+  // Confirm metadata has no value when updateInkTrailStartPoint is called
+  // with the same event.
+  SimulateRoutedMouseEvent(blink::WebInputEvent::Type::kMouseMove, 20, 20,
+                           blink::WebInputEvent::kLeftButtonDown, false);
+  RunUntilInputProcessed(host());
+
+  {
+    const cc::RenderFrameMetadata& last_metadata =
+        host()->render_frame_metadata_provider()->LastRenderFrameMetadata();
+    EXPECT_FALSE(last_metadata.delegated_ink_metadata.has_value());
+  }
+}
+
 }  // namespace content
diff --git a/content/test/data/cache_storage/storage_key/0430f1a484a0ea6d8de562488c5fbeec0111d16f/ba31f73b-95e8-44fb-a273-265e7e76f5ab/3767fbd3edc759b5_0 b/content/test/data/cache_storage/storage_key/0430f1a484a0ea6d8de562488c5fbeec0111d16f/ba31f73b-95e8-44fb-a273-265e7e76f5ab/3767fbd3edc759b5_0
new file mode 100644
index 0000000..24161f27
--- /dev/null
+++ b/content/test/data/cache_storage/storage_key/0430f1a484a0ea6d8de562488c5fbeec0111d16f/ba31f73b-95e8-44fb-a273-265e7e76f5ab/3767fbd3edc759b5_0
Binary files differ
diff --git a/content/test/data/cache_storage/storage_key/0430f1a484a0ea6d8de562488c5fbeec0111d16f/ba31f73b-95e8-44fb-a273-265e7e76f5ab/index b/content/test/data/cache_storage/storage_key/0430f1a484a0ea6d8de562488c5fbeec0111d16f/ba31f73b-95e8-44fb-a273-265e7e76f5ab/index
new file mode 100644
index 0000000..79bd403a
--- /dev/null
+++ b/content/test/data/cache_storage/storage_key/0430f1a484a0ea6d8de562488c5fbeec0111d16f/ba31f73b-95e8-44fb-a273-265e7e76f5ab/index
Binary files differ
diff --git a/content/test/data/cache_storage/storage_key/0430f1a484a0ea6d8de562488c5fbeec0111d16f/ba31f73b-95e8-44fb-a273-265e7e76f5ab/index-dir/the-real-index b/content/test/data/cache_storage/storage_key/0430f1a484a0ea6d8de562488c5fbeec0111d16f/ba31f73b-95e8-44fb-a273-265e7e76f5ab/index-dir/the-real-index
new file mode 100644
index 0000000..d833a4cd
--- /dev/null
+++ b/content/test/data/cache_storage/storage_key/0430f1a484a0ea6d8de562488c5fbeec0111d16f/ba31f73b-95e8-44fb-a273-265e7e76f5ab/index-dir/the-real-index
Binary files differ
diff --git a/content/test/data/cache_storage/storage_key/0430f1a484a0ea6d8de562488c5fbeec0111d16f/index.txt b/content/test/data/cache_storage/storage_key/0430f1a484a0ea6d8de562488c5fbeec0111d16f/index.txt
new file mode 100644
index 0000000..227f284
--- /dev/null
+++ b/content/test/data/cache_storage/storage_key/0430f1a484a0ea6d8de562488c5fbeec0111d16f/index.txt
Binary files differ
diff --git a/docs/callback.md b/docs/callback.md
index c0aac4c0..c0dabf4 100644
--- a/docs/callback.md
+++ b/docs/callback.md
@@ -459,7 +459,7 @@
 ```cpp
 // Binds |foo_ptr| to a no-op OnceCallback takes a scoped_refptr<Foo>.
 // ANTIPATTERN WARNING: This should likely be changed to ReleaseSoon()!
-base::BindOnce(base::DoNothing::Once<scoped_refptr<Foo>>(), foo_ptr);
+base::BindOnce(base::DoNothingAs<void(scoped_refptr<Foo>)>(), foo_ptr);
 ```
 
 ### Passing Unbound Input Parameters
diff --git a/extensions/browser/app_window/app_window_contents.cc b/extensions/browser/app_window/app_window_contents.cc
index bf230ee..a6fda89 100644
--- a/extensions/browser/app_window/app_window_contents.cc
+++ b/extensions/browser/app_window/app_window_contents.cc
@@ -122,7 +122,7 @@
   // This message should come from a primary main frame.
   if (!sender->IsInPrimaryMainFrame()) {
     bad_message::ReceivedBadMessage(
-        web_contents_->GetMainFrame()->GetProcess(),
+        web_contents_->GetPrimaryMainFrame()->GetProcess(),
         bad_message::AWCI_INVALID_CALL_FROM_NOT_PRIMARY_MAIN_FRAME);
     return;
   }
diff --git a/extensions/renderer/bindings/listener_tracker.cc b/extensions/renderer/bindings/listener_tracker.cc
index 197afff..dba8f600 100644
--- a/extensions/renderer/bindings/listener_tracker.cc
+++ b/extensions/renderer/bindings/listener_tracker.cc
@@ -61,7 +61,8 @@
   EventMatcher* matcher = event_filter_.GetEventMatcher(filter_id);
   DCHECK(matcher);
   std::unique_ptr<base::DictionaryValue> filter_copy =
-      matcher->value()->CreateDeepCopy();
+      base::DictionaryValue::From(
+          base::Value::ToUniquePtrValue(matcher->value()->Clone()));
 
   FilteredEventListenerKey key(context_owner_id, event_name);
   FilteredListeners::const_iterator counts = filtered_listeners_.find(key);
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_angle_vulkan.cc b/gpu/command_buffer/service/shared_image_backing_factory_angle_vulkan.cc
index b7bfe43d..33206e1f 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_angle_vulkan.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_angle_vulkan.cc
@@ -597,7 +597,7 @@
                                         context_state->progress_reporter()),
       context_state_(context_state) {
   DCHECK(context_state_->GrContextIsVulkan());
-  DCHECK(gl::GLSurfaceEGL::GetGLDisplayEGL()->IsANGLEVulkanImageSupported());
+  DCHECK(gl::GLSurfaceEGL::GetGLDisplayEGL()->ext->b_EGL_ANGLE_vulkan_image);
 }
 
 SharedImageBackingFactoryAngleVulkan::~SharedImageBackingFactoryAngleVulkan() =
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_ozone.cc b/gpu/command_buffer/service/shared_image_backing_factory_ozone.cc
index ae564df0..8d5944e 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_ozone.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_ozone.cc
@@ -22,6 +22,7 @@
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/native_pixmap.h"
 #include "ui/gl/buildflags.h"
+#include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_surface_egl.h"
 #include "ui/ozone/public/ozone_platform.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
@@ -234,7 +235,7 @@
     return false;
   }
   if (used_by_gl &&
-      !gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension("EGL_KHR_image")) {
+      !gl::GLSurfaceEGL::GetGLDisplayEGL()->ext->b_EGL_KHR_image) {
     return false;
   }
 #else
diff --git a/gpu/command_buffer/service/shared_image_factory.cc b/gpu/command_buffer/service/shared_image_factory.cc
index a92b327..1f37a592b 100644
--- a/gpu/command_buffer/service/shared_image_factory.cc
+++ b/gpu/command_buffer/service/shared_image_factory.cc
@@ -264,7 +264,7 @@
 #endif  // BUILDFLAG(ENABLE_VULKAN)
 
     bool egl_ext_supported =
-        gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension("EGL_KHR_image");
+        gl::GLSurfaceEGL::GetGLDisplayEGL()->ext->b_EGL_KHR_image;
     bool glx_ext_supported = false;
 #if defined(USE_OZONE)
 #if BUILDFLAG(OZONE_PLATFORM_X11)
diff --git a/gpu/command_buffer/service/webgpu_decoder_impl.cc b/gpu/command_buffer/service/webgpu_decoder_impl.cc
index b18dd1f..d465294 100644
--- a/gpu/command_buffer/service/webgpu_decoder_impl.cc
+++ b/gpu/command_buffer/service/webgpu_decoder_impl.cc
@@ -1033,6 +1033,7 @@
     case WGPUFeatureName_PipelineStatisticsQuery:
     case WGPUFeatureName_ChromiumExperimentalDp4a:
     case WGPUFeatureName_DawnMultiPlanarFormats:
+    case WGPUFeatureName_DepthClipControl:
       return allow_unsafe_apis_;
     case WGPUFeatureName_Depth32FloatStencil8:
     case WGPUFeatureName_TextureCompressionBC:
diff --git a/gpu/config/gpu_info_collector.cc b/gpu/config/gpu_info_collector.cc
index 56406bb..d95ffa8 100644
--- a/gpu/config/gpu_info_collector.cc
+++ b/gpu/config/gpu_info_collector.cc
@@ -386,13 +386,11 @@
   base::UmaHistogramSparse("GPU.MaxMSAASampleCount", max_samples);
 
 #if BUILDFLAG(IS_ANDROID)
+  gl::GLDisplayEGL* display = gl::GLSurfaceEGL::GetGLDisplayEGL();
   gpu_info->can_support_threaded_texture_mailbox =
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension(
-          "EGL_KHR_fence_sync") &&
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension(
-          "EGL_KHR_image_base") &&
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension(
-          "EGL_KHR_gl_texture_2D_image") &&
+      display->ext->b_EGL_KHR_fence_sync &&
+      display->ext->b_EGL_KHR_image_base &&
+      display->ext->b_EGL_KHR_gl_texture_2D_image &&
       gfx::HasExtension(extension_set, "GL_OES_EGL_image");
 #else
   gl::GLWindowSystemBindingInfo window_system_binding_info;
@@ -566,7 +564,7 @@
                          const GpuPreferences& prefs) {
   // Populate the list of ANGLE features by querying the functions exposed by
   // EGL_ANGLE_feature_control if it's available.
-  if (gl::GLSurfaceEGL::GetGLDisplayEGL()->IsANGLEFeatureControlSupported()) {
+  if (gl::g_driver_egl.client_ext.b_EGL_ANGLE_feature_control) {
     EGLDisplay display =
         gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
     EGLAttrib feature_count = 0;
diff --git a/headless/BUILD.gn b/headless/BUILD.gn
index a6e8bfd..42249c7 100644
--- a/headless/BUILD.gn
+++ b/headless/BUILD.gn
@@ -373,6 +373,8 @@
     "lib/browser/headless_quota_permission_context.h",
     "lib/browser/headless_request_context_manager.cc",
     "lib/browser/headless_request_context_manager.h",
+    "lib/browser/headless_select_file_dialog_factory.cc",
+    "lib/browser/headless_select_file_dialog_factory.h",
     "lib/browser/headless_window_tree_host.h",
     "lib/browser/protocol/browser_handler.cc",
     "lib/browser/protocol/browser_handler.h",
@@ -477,6 +479,7 @@
     "//ui/display",
     "//ui/events/devices",
     "//ui/gfx",
+    "//ui/shell_dialogs",
     "//url",
   ]
 
@@ -846,6 +849,7 @@
     "//testing/gmock",
     "//testing/gtest",
     "//ui/base/clipboard",
+    "//ui/shell_dialogs",
   ]
 
   if (is_mac) {
diff --git a/headless/lib/browser/DEPS b/headless/lib/browser/DEPS
index 10d356d..aba14f0 100644
--- a/headless/lib/browser/DEPS
+++ b/headless/lib/browser/DEPS
@@ -40,4 +40,7 @@
   "headless_web_contents_impl.cc": [
     "+components/printing/browser/print_to_pdf",
   ],
+  "headless_select_file_dialog_factory.*": [
+    "+ui/shell_dialogs",
+  ],
 }
diff --git a/headless/lib/browser/headless_browser_main_parts.cc b/headless/lib/browser/headless_browser_main_parts.cc
index 1dad925..2dbdd29 100644
--- a/headless/lib/browser/headless_browser_main_parts.cc
+++ b/headless/lib/browser/headless_browser_main_parts.cc
@@ -15,6 +15,7 @@
 #include "headless/lib/browser/headless_browser_impl.h"
 #include "headless/lib/browser/headless_devtools.h"
 #include "headless/lib/browser/headless_screen.h"
+#include "headless/lib/browser/headless_select_file_dialog_factory.h"
 
 #if defined(HEADLESS_USE_PREFS)
 #include "components/os_crypt/os_crypt.h"  // nogncheck
@@ -61,6 +62,7 @@
   MaybeStartLocalDevToolsHttpHandler();
   browser_->PlatformInitialize();
   browser_->RunOnStartCallback();
+  HeadlessSelectFileDialogFactory::SetUp();
   return content::RESULT_CODE_NORMAL_EXIT;
 }
 
diff --git a/headless/lib/browser/headless_select_file_dialog_factory.cc b/headless/lib/browser/headless_select_file_dialog_factory.cc
new file mode 100644
index 0000000..22a6d95
--- /dev/null
+++ b/headless/lib/browser/headless_select_file_dialog_factory.cc
@@ -0,0 +1,91 @@
+// Copyright 2022 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 "headless/lib/browser/headless_select_file_dialog_factory.h"
+
+namespace headless {
+
+namespace {
+// SelectFileDialogFactory is a destructable singleton, see
+// SelectFileDialog::SetFactory(), so we must make it disposable.
+HeadlessSelectFileDialogFactory* g_factory_instance = nullptr;
+}  // namespace
+
+// HeadlessSelectFileDialog implements a stub select file dialog
+// that cancels itself as soon as it gets open, optionally calling
+// back the owner.
+
+class HeadlessSelectFileDialog : public ui::SelectFileDialog {
+ public:
+  HeadlessSelectFileDialog(Listener* listener,
+                           std::unique_ptr<ui::SelectFilePolicy> policy,
+                           SelectFileDialogCallback callback)
+      : ui::SelectFileDialog(listener, std::move(policy)),
+        callback_(std::move(callback)) {}
+
+ protected:
+  ~HeadlessSelectFileDialog() override = default;
+
+  // ui::BaseShellDialog
+  bool IsRunning(gfx::NativeWindow owning_window) const override {
+    return false;
+  }
+
+  void ListenerDestroyed() override { listener_ = nullptr; }
+
+  // ui::SelectFileDialog
+  void SelectFileImpl(Type type,
+                      const std::u16string& title,
+                      const base::FilePath& default_path,
+                      const FileTypeInfo* file_types,
+                      int file_type_index,
+                      const base::FilePath::StringType& default_extension,
+                      gfx::NativeWindow owning_window,
+                      void* params) override {
+    if (callback_)
+      std::move(callback_).Run(type);
+
+    if (listener_)
+      listener_->FileSelectionCanceled(/*params=*/nullptr);
+  }
+
+ private:
+  // ui::SelectFileDialog:
+  bool HasMultipleFileTypeChoicesImpl() override { return false; }
+
+  SelectFileDialogCallback callback_;
+};
+
+// HeadlessSelectFileDialogFactory creates cancelable SelectFileDialog's
+
+// static
+void HeadlessSelectFileDialogFactory::SetUp() {
+  ui::SelectFileDialog::SetFactory(new HeadlessSelectFileDialogFactory());
+}
+
+// static
+void HeadlessSelectFileDialogFactory::SetSelectFileDialogOnceCallbackForTests(
+    SelectFileDialogCallback callback) {
+  DCHECK(g_factory_instance);
+  g_factory_instance->callback_ = std::move(callback);
+}
+
+ui::SelectFileDialog* HeadlessSelectFileDialogFactory::Create(
+    ui::SelectFileDialog::Listener* listener,
+    std::unique_ptr<ui::SelectFilePolicy> policy) {
+  return new HeadlessSelectFileDialog(listener, std::move(policy),
+                                      std::move(callback_));
+}
+
+HeadlessSelectFileDialogFactory::HeadlessSelectFileDialogFactory() {
+  DCHECK(!g_factory_instance);
+  g_factory_instance = this;
+}
+
+HeadlessSelectFileDialogFactory::~HeadlessSelectFileDialogFactory() {
+  DCHECK_EQ(g_factory_instance, this);
+  g_factory_instance = nullptr;
+}
+
+}  // namespace headless
diff --git a/headless/lib/browser/headless_select_file_dialog_factory.h b/headless/lib/browser/headless_select_file_dialog_factory.h
new file mode 100644
index 0000000..5ec6be54
--- /dev/null
+++ b/headless/lib/browser/headless_select_file_dialog_factory.h
@@ -0,0 +1,54 @@
+// Copyright 2022 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 HEADLESS_LIB_BROWSER_HEADLESS_SELECT_FILE_DIALOG_FACTORY_H_
+#define HEADLESS_LIB_BROWSER_HEADLESS_SELECT_FILE_DIALOG_FACTORY_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "headless/public/headless_export.h"
+#include "ui/shell_dialogs/select_file_dialog.h"
+#include "ui/shell_dialogs/select_file_dialog_factory.h"
+#include "ui/shell_dialogs/select_file_policy.h"
+
+namespace headless {
+
+using SelectFileDialogCallback =
+    base::OnceCallback<void(ui::SelectFileDialog::Type type)>;
+
+class HEADLESS_EXPORT HeadlessSelectFileDialogFactory
+    : public ui::SelectFileDialogFactory {
+ public:
+  HeadlessSelectFileDialogFactory(const HeadlessSelectFileDialogFactory&) =
+      delete;
+  HeadlessSelectFileDialogFactory& operator=(
+      const HeadlessSelectFileDialogFactory&) = delete;
+
+  // Creates the factory and sets it into ui::SelectFileDialog.
+  static void SetUp();
+
+  // Registers a one time callback that would be called when the next Select
+  // File Dialog comes up. This can only be called after SetUp().
+  static void SetSelectFileDialogOnceCallbackForTests(
+      SelectFileDialogCallback callback);
+
+ private:
+  friend class HeadlessSelectFileDialog;
+
+  // ui::SelectFileDialogFactory
+  ui::SelectFileDialog* Create(
+      ui::SelectFileDialog::Listener* listener,
+      std::unique_ptr<ui::SelectFilePolicy> policy) override;
+
+  HeadlessSelectFileDialogFactory();
+  ~HeadlessSelectFileDialogFactory() override;
+
+  SelectFileDialogCallback callback_;
+};
+
+}  // namespace headless
+
+#endif  // HEADLESS_LIB_BROWSER_HEADLESS_SELECT_FILE_DIALOG_FACTORY_H_
diff --git a/headless/test/DEPS b/headless/test/DEPS
index 65b1bf2..568cd2db 100644
--- a/headless/test/DEPS
+++ b/headless/test/DEPS
@@ -12,3 +12,9 @@
   "+components/prefs",
   "+services/device/public/cpp/test/fake_geolocation_manager.h",
 ]
+specific_include_rules = {
+  "headless_browser_browsertest.*": [
+    "+storage/browser",
+    "+ui/shell_dialogs",
+  ],
+}
diff --git a/headless/test/headless_browser_browsertest.cc b/headless/test/headless_browser_browsertest.cc
index 5dd9fb6..d147bfc 100644
--- a/headless/test/headless_browser_browsertest.cc
+++ b/headless/test/headless_browser_browsertest.cc
@@ -3,7 +3,9 @@
 // found in the LICENSE file.
 
 #include <memory>
+#include <string>
 #include <tuple>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -11,6 +13,7 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/raw_ptr.h"
+#include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
@@ -27,6 +30,7 @@
 #include "headless/app/headless_shell_switches.h"
 #include "headless/lib/browser/headless_browser_context_impl.h"
 #include "headless/lib/browser/headless_browser_impl.h"
+#include "headless/lib/browser/headless_select_file_dialog_factory.h"
 #include "headless/lib/browser/headless_web_contents_impl.h"
 #include "headless/public/devtools/domains/inspector.h"
 #include "headless/public/devtools/domains/network.h"
@@ -41,16 +45,19 @@
 #include "net/cert/cert_status_flags.h"
 #include "net/ssl/ssl_server_config.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "storage/browser/file_system/external_mount_points.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/chrome_debug_urls.h"
 #include "third_party/blink/public/common/permissions/permission_utils.h"
+#include "third_party/blink/public/mojom/frame/user_activation_notification_type.mojom.h"
 #include "third_party/blink/public/resources/grit/blink_resources.h"
 #include "third_party/blink/public/strings/grit/blink_strings.h"
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/geometry/size.h"
+#include "ui/shell_dialogs/select_file_dialog.h"
 
 #if !BUILDFLAG(IS_FUCHSIA)
 #include "third_party/crashpad/crashpad/client/crash_report_database.h"  // nogncheck
@@ -813,4 +820,108 @@
               testing::Ne(""));
 }
 
+class SelectFileDialogHeadlessBrowserTest
+    : public HeadlessBrowserTest,
+      public testing::WithParamInterface<
+          std::tuple<const char*, ui::SelectFileDialog::Type>> {
+ public:
+  static constexpr char kTestMountPoint[] = "testfs";
+
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+    // Register an external mount point to test support for virtual paths.
+    // This maps the virtual path a native local path to make these tests work
+    // on all platforms.
+    storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
+        kTestMountPoint, storage::kFileSystemTypeLocal,
+        storage::FileSystemMountOption(), temp_dir_.GetPath());
+
+    HeadlessBrowserTest::SetUp();
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    // Enable experimental web platform features to enable write access.
+    command_line->AppendSwitch(
+        ::switches::kEnableExperimentalWebPlatformFeatures);
+  }
+
+  void TearDown() override {
+    HeadlessBrowserTest::TearDown();
+    storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
+        kTestMountPoint);
+    ASSERT_TRUE(temp_dir_.Delete());
+  }
+
+  void WaitForSelectFileDialogCallback() {
+    if (select_file_dialog_type_ != ui::SelectFileDialog::SELECT_NONE)
+      return;
+
+    ASSERT_FALSE(run_loop_);
+    run_loop_ = std::make_unique<base::RunLoop>(
+        base::RunLoop::Type::kNestableTasksAllowed);
+    run_loop_->Run();
+    run_loop_ = nullptr;
+  }
+
+  void OnSelectFileDialogCallback(ui::SelectFileDialog::Type type) {
+    select_file_dialog_type_ = type;
+
+    if (run_loop_)
+      run_loop_->Quit();
+  }
+
+  const char* file_dialog_script() { return std::get<0>(GetParam()); }
+  ui::SelectFileDialog::Type expected_type() { return std::get<1>(GetParam()); }
+
+ protected:
+  std::unique_ptr<base::RunLoop> run_loop_;
+  base::ScopedTempDir temp_dir_;
+  ui::SelectFileDialog::Type select_file_dialog_type_ =
+      ui::SelectFileDialog::SELECT_NONE;
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    SelectFileDialogHeadlessBrowserTest,
+    SelectFileDialogHeadlessBrowserTest,
+    testing::Values(std::make_tuple("window.showOpenFilePicker()",
+                                    ui::SelectFileDialog::SELECT_OPEN_FILE),
+                    std::make_tuple("window.showSaveFilePicker()",
+                                    ui::SelectFileDialog::SELECT_SAVEAS_FILE),
+                    std::make_tuple("window.showDirectoryPicker()",
+                                    ui::SelectFileDialog::SELECT_FOLDER)));
+
+IN_PROC_BROWSER_TEST_P(SelectFileDialogHeadlessBrowserTest, SelectFileDialog) {
+  base::ScopedAllowBlockingForTesting allow_blocking;
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  HeadlessBrowserContext* browser_context =
+      browser()->CreateBrowserContextBuilder().Build();
+
+  HeadlessWebContents* web_contents =
+      browser_context->CreateWebContentsBuilder()
+          .SetInitialURL(embedded_test_server()->GetURL("/hello.html"))
+          .Build();
+  ASSERT_TRUE(WaitForLoad(web_contents));
+
+  // Select file dialog will not be shown if the owning frame does not
+  // have user activation, see VerifyIsAllowedToShowFilePicker in
+  // third_party/blink/renderer/.../global_file_system_access.cc
+  content::WebContents* content =
+      HeadlessWebContentsImpl::From(web_contents)->web_contents();
+  content::RenderFrameHost* main_frame = content->GetMainFrame();
+  main_frame->NotifyUserActivation(
+      blink::mojom::UserActivationNotificationType::kTest);
+
+  HeadlessSelectFileDialogFactory::SetSelectFileDialogOnceCallbackForTests(
+      base::BindOnce(
+          &SelectFileDialogHeadlessBrowserTest::OnSelectFileDialogCallback,
+          base::Unretained(this)));
+
+  EvaluateScript(web_contents, file_dialog_script());
+  WaitForSelectFileDialogCallback();
+
+  EXPECT_EQ(select_file_dialog_type_, expected_type());
+}
+
 }  // namespace headless
diff --git a/headless/test/headless_browser_test.cc b/headless/test/headless_browser_test.cc
index 6c0ef2d..0683c01 100644
--- a/headless/test/headless_browser_test.cc
+++ b/headless/test/headless_browser_test.cc
@@ -237,7 +237,7 @@
   // is issued first is undefined. The following code is waiting on both, in any
   // order.
   content::TestNavigationObserver load_observer(content, 1);
-  content::FrameFocusedObserver focus_observer(content->GetMainFrame());
+  content::FrameFocusedObserver focus_observer(content->GetPrimaryMainFrame());
   load_observer.Wait();
   focus_observer.Wait();
 }
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 8815a1a8..0fd1674 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -45745,7 +45745,7 @@
     builders {
       name: "ios-simulator reclient staging"
       swarming_host: "chromium-swarm.appspot.com"
-      dimensions: "builder:ios-simulator reclient staging"
+      dimensions: "builderless:1"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "os:Mac-11|Mac-12"
@@ -45823,7 +45823,7 @@
     builders {
       name: "ios-simulator reclient test"
       swarming_host: "chromium-swarm.appspot.com"
-      dimensions: "builder:ios-simulator reclient test"
+      dimensions: "builderless:1"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       dimensions: "os:Mac-11|Mac-12"
diff --git a/infra/config/lib/args.star b/infra/config/lib/args.star
index 2f3bbb42a..a5947a94 100644
--- a/infra/config/lib/args.star
+++ b/infra/config/lib/args.star
@@ -96,6 +96,8 @@
                 return listify(value)
             return listify(default, value)
 
+        fail("unknown merge value: {}".format(merge))
+
     def get_value_from_kwargs(name, kwargs, merge = None):
         return get_value(name, kwargs.get(name, DEFAULT), merge = merge)
 
diff --git a/infra/config/lib/consoles.star b/infra/config/lib/consoles.star
index 3eed963..d07a73b 100644
--- a/infra/config/lib/consoles.star
+++ b/infra/config/lib/consoles.star
@@ -40,7 +40,7 @@
 _CONSOLE_VIEW_ORDERING = nodes.create_unscoped_node_type("console_view_ordering")
 _OVERVIEW_CONSOLE_ORDERING = nodes.create_unscoped_node_type("overview_console_ordering")
 
-def _console_view_ordering_impl(ctx, *, console_name, ordering):
+def _console_view_ordering_impl(_ctx, *, console_name, ordering):
     key = _CONSOLE_VIEW_ORDERING.add(console_name, props = {
         "ordering": ordering,
     })
@@ -49,7 +49,7 @@
 
 _console_view_ordering = lucicfg.rule(impl = _console_view_ordering_impl)
 
-def _overview_console_view_ordering_impl(ctx, *, console_name, top_level_ordering):
+def _overview_console_view_ordering_impl(_ctx, *, console_name, top_level_ordering):
     key = _OVERVIEW_CONSOLE_ORDERING.add(console_name, props = {
         "top_level_ordering": top_level_ordering,
     })
@@ -266,7 +266,7 @@
         ordering = ordering or {},
     )
 
-def overview_console_view(*, name, top_level_ordering, branch_selector = branches.MAIN, **kwargs):
+def overview_console_view(*, name, top_level_ordering, **kwargs):
     """Create an overview console view.
 
     An overview console view is a console view that contains a subset of
@@ -285,9 +285,6 @@
         name does not appear in the list will be sorted lexicographically
         by the console name and appear after entries whose console does
         appear in the list.
-      branch_selector - A branch selector value controlling whether the
-        console view definition is executed. See branches.star for
-        more information.
       kwargs - Additional keyword arguments to forward on to
         `luci.console_view`. The header and repo arguments support
          module-level defaults.
@@ -351,7 +348,7 @@
         return None
     return lambda b: b.name
 
-def _sorted_list_view_impl(ctx, *, console_name):
+def _sorted_list_view_impl(_ctx, *, console_name):
     key = _sorted_list_view_graph_key(console_name)
     graph.add_node(key)
     graph.add_edge(keys.project(), key)
diff --git a/infra/config/outages/outages.star b/infra/config/outages/outages.star
index 1673612..6ada1be 100644
--- a/infra/config/outages/outages.star
+++ b/infra/config/outages/outages.star
@@ -33,7 +33,7 @@
         for b in c.verifiers.tryjob.builders:
             if not b.experiment_percentage:
                 continue
-            project, bucket, builder = b.name.split("/", 2)
+            project, bucket, _ = b.name.split("/", 2)
             if project == "chromium" and bucket == "try":
                 b.includable_only = True
                 b.experiment_percentage = 0
diff --git a/infra/config/subprojects/reclient/reclient.star b/infra/config/subprojects/reclient/reclient.star
index 6cfae324..36e0168 100644
--- a/infra/config/subprojects/reclient/reclient.star
+++ b/infra/config/subprojects/reclient/reclient.star
@@ -222,6 +222,7 @@
     ),
     console_view_category = "ios",
     os = os.MAC_DEFAULT,
+    builderless = True,
 )
 
 fyi_reclient_staging_builder(
@@ -242,4 +243,5 @@
     ),
     console_view_category = "ios",
     os = os.MAC_DEFAULT,
+    builderless = True,
 )
diff --git a/media/audio/audio_output_dispatcher_impl.cc b/media/audio/audio_output_dispatcher_impl.cc
index 72f824b..dd9279f 100644
--- a/media/audio/audio_output_dispatcher_impl.cc
+++ b/media/audio/audio_output_dispatcher_impl.cc
@@ -75,8 +75,7 @@
     AudioOutputStream::AudioSourceCallback* callback,
     AudioOutputProxy* stream_proxy) {
   DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
-  DCHECK(proxy_to_physical_map_.find(stream_proxy) ==
-         proxy_to_physical_map_.end());
+  DCHECK(!proxy_to_physical_map_.contains(stream_proxy));
 
   if (idle_streams_.empty() && !CreateAndOpenStream())
     return false;
diff --git a/media/base/android/android_cdm_factory.cc b/media/base/android/android_cdm_factory.cc
index 53f4a29..15084f3 100644
--- a/media/base/android/android_cdm_factory.cc
+++ b/media/base/android/android_cdm_factory.cc
@@ -99,7 +99,7 @@
     const std::string& error_message) {
   DVLOG(1) << __func__ << ": creation_id = " << creation_id;
 
-  DCHECK(pending_creations_.count(creation_id));
+  DCHECK(pending_creations_.contains(creation_id));
   CdmCreatedCB cdm_created_cb =
       std::move(pending_creations_[creation_id].second);
   pending_creations_.erase(creation_id);
diff --git a/media/base/mime_util_internal.cc b/media/base/mime_util_internal.cc
index 0ba71149..1f9a1af 100644
--- a/media/base/mime_util_internal.cc
+++ b/media/base/mime_util_internal.cc
@@ -424,8 +424,7 @@
 }
 
 bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const {
-  return media_format_map_.find(base::ToLowerASCII(mime_type)) !=
-         media_format_map_.end();
+  return media_format_map_.contains(base::ToLowerASCII(mime_type));
 }
 
 void MimeUtil::SplitCodecs(const std::string& codecs,
diff --git a/media/base/video_frame_metadata.h b/media/base/video_frame_metadata.h
index 26dbe8a..3f92d91 100644
--- a/media/base/video_frame_metadata.h
+++ b/media/base/video_frame_metadata.h
@@ -57,6 +57,10 @@
   // If cropping was applied due to Region Capture to produce this frame,
   // then this reflects where the frame's contents originate from in the
   // original uncropped frame.
+  //
+  // NOTE: May also be nullopt if region capture is enabled but the capture rect
+  // is in a different coordinate space. For more info, see
+  // https://crbug.com/1327560.
   absl::optional<gfx::Rect> region_capture_rect;
 
   // Whenever cropTo() is called, Blink increments the crop_version and records
diff --git a/media/fuchsia/cdm/fuchsia_cdm.cc b/media/fuchsia/cdm/fuchsia_cdm.cc
index 4cedfff..51297937 100644
--- a/media/fuchsia/cdm/fuchsia_cdm.cc
+++ b/media/fuchsia/cdm/fuchsia_cdm.cc
@@ -407,7 +407,7 @@
   }
 
   session->set_session_id(session_id);
-  DCHECK(session_map_.find(session_id) == session_map_.end())
+  DCHECK(!session_map_.contains(session_id))
       << "Duplicated session id " << session_id;
   session_map_[session_id] = std::move(session);
 }
@@ -467,7 +467,7 @@
   }
 
   std::string session_id = session->session_id();
-  DCHECK(session_map_.find(session_id) == session_map_.end())
+  DCHECK(!session_map_.contains(session_id))
       << "Duplicated session id " << session_id;
 
   session_map_.emplace(session_id, std::move(session));
diff --git a/media/fuchsia/common/stream_processor_helper.cc b/media/fuchsia/common/stream_processor_helper.cc
index b4f71511..95449cd1 100644
--- a/media/fuchsia/common/stream_processor_helper.cc
+++ b/media/fuchsia/common/stream_processor_helper.cc
@@ -104,7 +104,7 @@
                                         fidl::Clone(input.format()));
   }
 
-  DCHECK(input_packets_.find(input.buffer_index()) == input_packets_.end());
+  DCHECK(!input_packets_.contains(input.buffer_index()));
   input_packets_.insert_or_assign(input.buffer_index(), std::move(input));
   processor_->QueueInputPacket(std::move(packet));
 }
diff --git a/media/gpu/mac/vt_video_decode_accelerator_mac.cc b/media/gpu/mac/vt_video_decode_accelerator_mac.cc
index 45395a6..9b6818c 100644
--- a/media/gpu/mac/vt_video_decode_accelerator_mac.cc
+++ b/media/gpu/mac/vt_video_decode_accelerator_mac.cc
@@ -1086,8 +1086,8 @@
           }
 
           // Record the configuration.
-          DCHECK(seen_pps_.count(slice_hdr.pic_parameter_set_id));
-          DCHECK(seen_sps_.count(pps->seq_parameter_set_id));
+          DCHECK(seen_pps_.contains(slice_hdr.pic_parameter_set_id));
+          DCHECK(seen_sps_.contains(pps->seq_parameter_set_id));
           active_sps_ = seen_sps_[pps->seq_parameter_set_id];
           // Note: SPS extension lookup may create an empty entry.
           active_spsext_ = seen_spsext_[pps->seq_parameter_set_id];
@@ -1481,9 +1481,9 @@
         }
 
         // Record the configuration.
-        DCHECK(seen_pps_.count(curr_slice_hdr->slice_pic_parameter_set_id));
-        DCHECK(seen_sps_.count(pps->pps_seq_parameter_set_id));
-        DCHECK(seen_vps_.count(sps->sps_video_parameter_set_id));
+        DCHECK(seen_pps_.contains(curr_slice_hdr->slice_pic_parameter_set_id));
+        DCHECK(seen_sps_.contains(pps->pps_seq_parameter_set_id));
+        DCHECK(seen_vps_.contains(sps->sps_video_parameter_set_id));
         active_vps_ = seen_vps_[sps->sps_video_parameter_set_id];
         active_sps_ = seen_sps_[pps->pps_seq_parameter_set_id];
         active_pps_ = seen_pps_[curr_slice_hdr->slice_pic_parameter_set_id];
@@ -1696,7 +1696,7 @@
 
   // pending_frames_.erase() will delete |frame|.
   int32_t bitstream_id = frame->bitstream_id;
-  DCHECK_EQ(1u, pending_frames_.count(bitstream_id));
+  DCHECK(pending_frames_.contains(bitstream_id));
 
   if (state_ == STATE_ERROR || state_ == STATE_DESTROYING) {
     // Destroy() handles NotifyEndOfBitstreamBuffer().
@@ -1809,7 +1809,7 @@
 
   for (const PictureBuffer& picture : pictures) {
     DVLOG(3) << "AssignPictureBuffer(" << picture.id() << ")";
-    DCHECK(!picture_info_map_.count(picture.id()));
+    DCHECK(!picture_info_map_.contains(picture.id()));
     assigned_picture_ids_.insert(picture.id());
     available_picture_ids_.push_back(picture.id());
     if (picture.client_texture_ids().empty() &&
diff --git a/media/gpu/v4l2/BUILD.gn b/media/gpu/v4l2/BUILD.gn
index 6a635eff..1223202 100644
--- a/media/gpu/v4l2/BUILD.gn
+++ b/media/gpu/v4l2/BUILD.gn
@@ -161,6 +161,8 @@
     "test/av1_decoder.cc",
     "test/av1_decoder.h",
     "test/av1_pix_fmt.h",
+    "test/h264_decoder.cc",
+    "test/h264_decoder.h",
     "test/v4l2_ioctl_shim.cc",
     "test/v4l2_ioctl_shim.h",
     "test/v4l2_stateless_decoder.cc",
diff --git a/media/gpu/v4l2/test/h264_decoder.cc b/media/gpu/v4l2/test/h264_decoder.cc
new file mode 100644
index 0000000..ebe3bbf
--- /dev/null
+++ b/media/gpu/v4l2/test/h264_decoder.cc
@@ -0,0 +1,73 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/gpu/v4l2/test/h264_decoder.h"
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "media/video/h264_parser.h"
+
+namespace media {
+
+namespace v4l2_test {
+
+constexpr uint32_t kNumberOfBuffersInCaptureQueue = 10;
+
+static_assert(kNumberOfBuffersInCaptureQueue <= 16,
+              "Too many CAPTURE buffers are used. The number of CAPTURE "
+              "buffers is currently assumed to be no larger than 16.");
+
+// static
+std::unique_ptr<H264Decoder> H264Decoder::Create(
+    const base::MemoryMappedFile& stream) {
+  H264Parser parser;
+  parser.SetStream(stream.data(), stream.length());
+
+  // Advance through NALUs until the first SPS.  The start of the decodable
+  // data in an h.264 bistreams starts with an SPS.
+  while (true) {
+    H264NALU nalu;
+    H264Parser::Result res = parser.AdvanceToNextNALU(&nalu);
+    if (res != H264Parser::kOk) {
+      LOG(ERROR) << "Unable to find SPS in stream";
+      return nullptr;
+    }
+
+    if (nalu.nal_unit_type == H264NALU::kSPS)
+      break;
+  }
+
+  int id;
+  H264Parser::Result res = parser.ParseSPS(&id);
+  CHECK(res == H264Parser::kOk);
+
+  const H264SPS* sps = parser.GetSPS(id);
+  CHECK(sps);
+
+  absl::optional<gfx::Size> coded_size = sps->GetCodedSize();
+  CHECK(coded_size);
+  LOG(INFO) << "h.264 coded size : " << coded_size->ToString();
+
+  return nullptr;
+}
+
+H264Decoder::H264Decoder(std::unique_ptr<V4L2IoctlShim> v4l2_ioctl,
+                         std::unique_ptr<V4L2Queue> OUTPUT_queue,
+                         std::unique_ptr<V4L2Queue> CAPTURE_queue)
+    : VideoDecoder::VideoDecoder(std::move(v4l2_ioctl),
+                                 std::move(OUTPUT_queue),
+                                 std::move(CAPTURE_queue)) {}
+
+H264Decoder::~H264Decoder() = default;
+
+VideoDecoder::Result H264Decoder::DecodeNextFrame(std::vector<char>& y_plane,
+                                                  std::vector<char>& u_plane,
+                                                  std::vector<char>& v_plane,
+                                                  gfx::Size& size,
+                                                  const int frame_number) {
+  return VideoDecoder::kError;
+}
+
+}  // namespace v4l2_test
+}  // namespace media
diff --git a/media/gpu/v4l2/test/h264_decoder.h b/media/gpu/v4l2/test/h264_decoder.h
new file mode 100644
index 0000000..874016ad
--- /dev/null
+++ b/media/gpu/v4l2/test/h264_decoder.h
@@ -0,0 +1,43 @@
+// Copyright 2022 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 MEDIA_GPU_V4L2_TEST_H264_DECODER_H_
+#define MEDIA_GPU_V4L2_TEST_H264_DECODER_H_
+
+#include "media/gpu/v4l2/test/video_decoder.h"
+
+#include "base/files/memory_mapped_file.h"
+#include "media/gpu/v4l2/test/v4l2_ioctl_shim.h"
+
+namespace media {
+namespace v4l2_test {
+class H264Decoder : public VideoDecoder {
+ public:
+  H264Decoder(const H264Decoder&) = delete;
+  H264Decoder& operator=(const H264Decoder&) = delete;
+  ~H264Decoder() override;
+
+  // Creates a H264Decoder after verifying that the bitstream is h.264
+  // and the underlying implementation supports H.264 slice decoding.
+  static std::unique_ptr<H264Decoder> Create(
+      const base::MemoryMappedFile& stream);
+
+  // Parses next frame from IVF stream and decodes the frame. This method will
+  // place the Y, U, and V values into the respective vectors and update the
+  // size with the display area size of the decoded frame.
+  VideoDecoder::Result DecodeNextFrame(std::vector<char>& y_plane,
+                                       std::vector<char>& u_plane,
+                                       std::vector<char>& v_plane,
+                                       gfx::Size& size,
+                                       const int frame_number) override;
+
+ private:
+  H264Decoder(std::unique_ptr<V4L2IoctlShim> v4l2_ioctl,
+              std::unique_ptr<V4L2Queue> OUTPUT_queue,
+              std::unique_ptr<V4L2Queue> CAPTURE_queue);
+};
+
+}  // namespace v4l2_test
+}  // namespace media
+
+#endif  // MEDIA_GPU_V4L2_TEST_H264_DECODER_H_
diff --git a/media/gpu/v4l2/test/v4l2_stateless_decoder.cc b/media/gpu/v4l2/test/v4l2_stateless_decoder.cc
index 6ed2821..2b444e5 100644
--- a/media/gpu/v4l2/test/v4l2_stateless_decoder.cc
+++ b/media/gpu/v4l2/test/v4l2_stateless_decoder.cc
@@ -14,10 +14,12 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "media/gpu/v4l2/test/av1_decoder.h"
+#include "media/gpu/v4l2/test/h264_decoder.h"
 #include "media/gpu/v4l2/test/video_decoder.h"
 #include "media/gpu/v4l2/test/vp9_decoder.h"
 
 using media::v4l2_test::Av1Decoder;
+using media::v4l2_test::H264Decoder;
 using media::v4l2_test::VideoDecoder;
 using media::v4l2_test::Vp9Decoder;
 
@@ -79,6 +81,9 @@
   if (!decoder)
     decoder = Vp9Decoder::Create(stream);
 
+  if (!decoder)
+    decoder = H264Decoder::Create(stream);
+
   return decoder;
 }
 
@@ -102,26 +107,33 @@
       cmd->GetSwitchValueASCII("output_path_prefix");
 
   const base::FilePath video_path = cmd->GetSwitchValuePath("video");
-  if (video_path.empty())
-    LOG(FATAL) << "No input video path provided to decode.\n" << kUsageMsg;
+  if (video_path.empty()) {
+    LOG(ERROR) << "No input video path provided to decode.\n" << kUsageMsg;
+    return EXIT_FAILURE;
+  }
 
   const std::string frames = cmd->GetSwitchValueASCII("frames");
   int n_frames;
   if (frames.empty()) {
     n_frames = 0;
   } else if (!base::StringToInt(frames, &n_frames) || n_frames <= 0) {
-    LOG(FATAL) << "Number of frames to decode must be positive integer, got "
+    LOG(ERROR) << "Number of frames to decode must be positive integer, got "
                << frames;
+    return EXIT_FAILURE;
   }
 
   // Set up video stream.
   base::MemoryMappedFile stream;
-  if (!stream.Initialize(video_path))
-    LOG(FATAL) << "Couldn't open file: " << video_path;
+  if (!stream.Initialize(video_path)) {
+    LOG(ERROR) << "Couldn't open file: " << video_path;
+    return EXIT_FAILURE;
+  }
 
   const std::unique_ptr<VideoDecoder> dec = CreateVideoDecoder(stream);
-  if (!dec)
-    LOG(FATAL) << "Failed to create decoder for file: " << video_path;
+  if (!dec) {
+    LOG(ERROR) << "Failed to create decoder for file: " << video_path;
+    return EXIT_FAILURE;
+  }
 
   dec->Initialize();
 
@@ -137,6 +149,9 @@
     if (res == VideoDecoder::kEOStream) {
       LOG(INFO) << "End of stream.";
       break;
+    } else if (res == VideoDecoder::kError) {
+      LOG(ERROR) << "Unable to decode next frame.";
+      break;
     }
 
     if (cmd->HasSwitch("visible") && !dec->LastDecodedFrameVisible())
diff --git a/media/gpu/windows/dxva_video_decode_accelerator_win.cc b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
index 622686b1..88c4996 100644
--- a/media/gpu/windows/dxva_video_decode_accelerator_win.cc
+++ b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
@@ -1554,11 +1554,11 @@
     RETURN_ON_HR_FAILURE(hr, "Failed to pass D3D manager to decoder", false);
   }
 
-  if (!gl::GLSurfaceEGL::GetGLDisplayEGL()->IsPixelFormatFloatSupported())
+  gl::GLDisplayEGL* display = gl::GLSurfaceEGL::GetGLDisplayEGL();
+  if (!display->ext->b_EGL_EXT_pixel_format_float)
     use_fp16_ = false;
 
-  EGLDisplay egl_display =
-      gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
+  EGLDisplay egl_display = display->GetHardwareDisplay();
 
   while (true) {
     std::vector<EGLint> config_attribs = {EGL_BUFFER_SIZE,  32,
diff --git a/media/learning/impl/random_tree_trainer.cc b/media/learning/impl/random_tree_trainer.cc
index 041cd88..c2749d6 100644
--- a/media/learning/impl/random_tree_trainer.cc
+++ b/media/learning/impl/random_tree_trainer.cc
@@ -78,7 +78,7 @@
 
   // Add |child| has the node for feature value |v|.
   void AddChild(FeatureValue v, std::unique_ptr<Model> child) {
-    DCHECK_EQ(children_.count(v), 0u);
+    DCHECK(!children_.contains(v));
     children_.emplace(v, std::move(child));
   }
 
diff --git a/media/renderers/win/media_foundation_texture_pool.cc b/media/renderers/win/media_foundation_texture_pool.cc
index 0c3ad4dd..6b1838a4 100644
--- a/media/renderers/win/media_foundation_texture_pool.cc
+++ b/media/renderers/win/media_foundation_texture_pool.cc
@@ -122,8 +122,9 @@
 
 void MediaFoundationTexturePool::ReleaseTexture(
     const base::UnguessableToken& texture_token) {
-  if (texture_pool_.count(texture_token) > 0) {
-    texture_pool_.at(texture_token).texture_in_use_ = false;
+  auto it = texture_pool_.find(texture_token);
+  if (it != texture_pool_.end()) {
+    it->second.texture_in_use_ = false;
   }
 }
 
diff --git a/net/base/features.cc b/net/base/features.cc
index a732dca..d9127ee 100644
--- a/net/base/features.cc
+++ b/net/base/features.cc
@@ -212,6 +212,11 @@
 const base::FeatureParam<int> kCertDualVerificationTrialCacheSize{
     &kCertDualVerificationTrialFeature, "cachesize", 0};
 #endif /* BUILDFLAG(IS_MAC) */
+#if BUILDFLAG(BUILTIN_CERT_VERIFIER_FEATURE_SUPPORTED) && \
+    BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
+const base::FeatureParam<bool> kCertDualVerificationTrialUseCrs{
+    &kCertDualVerificationTrialFeature, "use_crs", false};
+#endif
 #endif
 
 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
diff --git a/net/base/features.h b/net/base/features.h
index 0bb96470..e053127c 100644
--- a/net/base/features.h
+++ b/net/base/features.h
@@ -314,6 +314,14 @@
 NET_EXPORT extern const base::FeatureParam<int>
     kCertDualVerificationTrialCacheSize;
 #endif /* BUILDFLAG(IS_MAC) */
+#if BUILDFLAG(BUILTIN_CERT_VERIFIER_FEATURE_SUPPORTED) && \
+    BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
+// If both builtin verifier+system roots and builtin verifier+CRS flags are
+// supported in the same build, this param can be used to choose which to test
+// in the trial.
+NET_EXPORT extern const base::FeatureParam<bool>
+    kCertDualVerificationTrialUseCrs;
+#endif
 #endif /* BUILDFLAG(TRIAL_COMPARISON_CERT_VERIFIER_SUPPORTED) */
 
 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc
index 19608b6..6b52912 100644
--- a/net/cert/cert_verify_proc_unittest.cc
+++ b/net/cert/cert_verify_proc_unittest.cc
@@ -229,7 +229,8 @@
 #elif BUILDFLAG(IS_IOS)
     CERT_VERIFY_PROC_IOS
 #elif BUILDFLAG(IS_MAC)
-    CERT_VERIFY_PROC_MAC, CERT_VERIFY_PROC_BUILTIN
+    CERT_VERIFY_PROC_MAC, CERT_VERIFY_PROC_BUILTIN,
+    CERT_VERIFY_PROC_BUILTIN_CHROME_ROOTS
 #elif BUILDFLAG(IS_WIN)
     CERT_VERIFY_PROC_WIN, CERT_VERIFY_PROC_BUILTIN_CHROME_ROOTS
 #elif BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
@@ -1621,7 +1622,7 @@
                              << "against mattm.";
   EXPECT_TRUE(verify_result.is_issued_by_known_root);
 #if BUILDFLAG(IS_MAC)
-  if (VerifyProcTypeIsBuiltin()) {
+  if (verify_proc_type() == CERT_VERIFY_PROC_BUILTIN) {
     auto* mac_trust_debug_info =
         net::TrustStoreMac::ResultDebugData::Get(&verify_result);
     ASSERT_TRUE(mac_trust_debug_info);
diff --git a/net/cert/internal/system_trust_store.cc b/net/cert/internal/system_trust_store.cc
index c5ba97f..a665c3b 100644
--- a/net/cert/internal/system_trust_store.cc
+++ b/net/cert/internal/system_trust_store.cc
@@ -4,6 +4,7 @@
 
 #include "net/cert/internal/system_trust_store.h"
 
+#include "base/memory/ptr_util.h"
 #include "build/build_config.h"
 #include "crypto/crypto_buildflags.h"
 
@@ -78,15 +79,18 @@
 }  // namespace
 
 #if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
-class SystemTrustStoreChrome : public SystemTrustStore {
+class SystemTrustStoreChromeWithUnOwnedSystemStore : public SystemTrustStore {
  public:
-  explicit SystemTrustStoreChrome(
+  // Creates a SystemTrustStore that gets publicly trusted roots from
+  // |trust_store_chrome| and local trust settings from |trust_store_system|.
+  // Does not take ownership of |trust_store_system|, which must outlive this
+  // object.
+  explicit SystemTrustStoreChromeWithUnOwnedSystemStore(
       std::unique_ptr<TrustStoreChrome> trust_store_chrome,
-      std::unique_ptr<TrustStore> trust_store_system)
-      : trust_store_chrome_(std::move(trust_store_chrome)),
-        trust_store_system_(std::move(trust_store_system)) {
+      TrustStore* trust_store_system)
+      : trust_store_chrome_(std::move(trust_store_chrome)) {
     trust_store_collection_.AddTrustStore(trust_store_chrome_.get());
-    trust_store_collection_.AddTrustStore(trust_store_system_.get());
+    trust_store_collection_.AddTrustStore(trust_store_system);
   }
 
   TrustStore* GetTrustStore() override { return &trust_store_collection_; }
@@ -105,17 +109,32 @@
 
  private:
   std::unique_ptr<TrustStoreChrome> trust_store_chrome_;
-  std::unique_ptr<TrustStore> trust_store_system_;
   TrustStoreCollection trust_store_collection_;
 };
 
+class SystemTrustStoreChrome
+    : public SystemTrustStoreChromeWithUnOwnedSystemStore {
+ public:
+  // Creates a SystemTrustStore that gets publicly trusted roots from
+  // |trust_store_chrome| and local trust settings from |trust_store_system|.
+  explicit SystemTrustStoreChrome(
+      std::unique_ptr<TrustStoreChrome> trust_store_chrome,
+      std::unique_ptr<TrustStore> trust_store_system)
+      : SystemTrustStoreChromeWithUnOwnedSystemStore(
+            std::move(trust_store_chrome),
+            trust_store_system.get()),
+        trust_store_system_(std::move(trust_store_system)) {}
+
+ private:
+  std::unique_ptr<TrustStore> trust_store_system_;
+};
+
 std::unique_ptr<SystemTrustStore> CreateSystemTrustStoreChromeForTesting(
     std::unique_ptr<TrustStoreChrome> trust_store_chrome,
     std::unique_ptr<TrustStore> trust_store_system) {
   return std::make_unique<SystemTrustStoreChrome>(
       std::move(trust_store_chrome), std::move(trust_store_system));
 }
-
 #endif  // CHROME_ROOT_STORE_SUPPORTED
 
 #if BUILDFLAG(USE_NSS_CERTS)
@@ -193,6 +212,61 @@
 
 #elif BUILDFLAG(IS_MAC)
 
+namespace {
+
+TrustStoreMac::TrustImplType ParamToTrustImplType(
+    int param,
+    TrustStoreMac::TrustImplType default_impl) {
+  switch (param) {
+    case 1:
+      return TrustStoreMac::TrustImplType::kDomainCache;
+    case 2:
+      return TrustStoreMac::TrustImplType::kSimple;
+    case 3:
+      return TrustStoreMac::TrustImplType::kLruCache;
+    default:
+      return default_impl;
+  }
+}
+
+TrustStoreMac::TrustImplType GetTrustStoreImplParam(
+    TrustStoreMac::TrustImplType default_impl) {
+  // TODO(https://crbug.com/1327433): A limitation of this approach is that if
+  // the primary verifier is being set to use the builtin verifier via a
+  // feature flag, it isn't possible to run dual verifier trial comparing that
+  // to the builtin verifier with different flags, since this method can't tell
+  // which flags to use for which verifier.
+  // If handling that becomes necessary, the flags should be checked in the
+  // higher level code (maybe in cert_verifier_creation.cc) so that each
+  // type of CertVerifyProc could be created with the appropriate flags.
+  if (base::FeatureList::IsEnabled(features::kCertVerifierBuiltinFeature)) {
+    return ParamToTrustImplType(features::kCertVerifierBuiltinImpl.Get(),
+                                default_impl);
+  }
+  if (base::FeatureList::IsEnabled(
+          features::kCertDualVerificationTrialFeature)) {
+    return ParamToTrustImplType(features::kCertDualVerificationTrialImpl.Get(),
+                                default_impl);
+  }
+  return default_impl;
+}
+
+size_t GetTrustStoreCacheSize() {
+  if (base::FeatureList::IsEnabled(features::kCertVerifierBuiltinFeature) &&
+      features::kCertVerifierBuiltinCacheSize.Get() > 0) {
+    return features::kCertVerifierBuiltinCacheSize.Get();
+  }
+  if (base::FeatureList::IsEnabled(
+          features::kCertDualVerificationTrialFeature) &&
+      features::kCertDualVerificationTrialCacheSize.Get() > 0) {
+    return features::kCertDualVerificationTrialCacheSize.Get();
+  }
+  constexpr size_t kDefaultCacheSize = 512;
+  return kDefaultCacheSize;
+}
+
+}  // namespace
+
 class SystemTrustStoreMac : public SystemTrustStore {
  public:
   SystemTrustStoreMac() = default;
@@ -211,50 +285,18 @@
     GetGlobalTrustStoreMac()->InitializeTrustCache();
   }
 
+#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
+  int64_t chrome_root_store_version() override { return 0; }
+#endif
+
  private:
   static constexpr TrustStoreMac::TrustImplType kDefaultTrustImpl =
       TrustStoreMac::TrustImplType::kLruCache;
 
-  static TrustStoreMac::TrustImplType ParamToTrustImplType(int param) {
-    switch (param) {
-      case 1:
-        return TrustStoreMac::TrustImplType::kDomainCache;
-      case 2:
-        return TrustStoreMac::TrustImplType::kSimple;
-      case 3:
-        return TrustStoreMac::TrustImplType::kLruCache;
-      default:
-        return kDefaultTrustImpl;
-    }
-  }
-
-  static TrustStoreMac::TrustImplType GetTrustStoreImplParam() {
-    if (base::FeatureList::IsEnabled(features::kCertVerifierBuiltinFeature))
-      return ParamToTrustImplType(features::kCertVerifierBuiltinImpl.Get());
-    if (base::FeatureList::IsEnabled(
-            features::kCertDualVerificationTrialFeature))
-      return ParamToTrustImplType(
-          features::kCertDualVerificationTrialImpl.Get());
-    return kDefaultTrustImpl;
-  }
-
-  static size_t GetTrustStoreCacheSize() {
-    if (base::FeatureList::IsEnabled(features::kCertVerifierBuiltinFeature) &&
-        features::kCertVerifierBuiltinCacheSize.Get() > 0) {
-      return features::kCertVerifierBuiltinCacheSize.Get();
-    }
-    if (base::FeatureList::IsEnabled(
-            features::kCertDualVerificationTrialFeature) &&
-        features::kCertDualVerificationTrialCacheSize.Get() > 0) {
-      return features::kCertDualVerificationTrialCacheSize.Get();
-    }
-    constexpr size_t kDefaultCacheSize = 512;
-    return kDefaultCacheSize;
-  }
-
   static TrustStoreMac* GetGlobalTrustStoreMac() {
     static base::NoDestructor<TrustStoreMac> static_trust_store_mac(
-        kSecPolicyAppleSSL, GetTrustStoreImplParam(), GetTrustStoreCacheSize());
+        kSecPolicyAppleSSL, GetTrustStoreImplParam(kDefaultTrustImpl),
+        GetTrustStoreCacheSize(), TrustStoreMac::TrustDomains::kAll);
     return static_trust_store_mac.get();
   }
 };
@@ -263,11 +305,45 @@
   return std::make_unique<SystemTrustStoreMac>();
 }
 
+#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
+namespace {
+
+TrustStoreMac* GetGlobalTrustStoreMacForCRS() {
+  constexpr TrustStoreMac::TrustImplType kDefaultMacTrustImplForCRS =
+      TrustStoreMac::TrustImplType::kDomainCache;
+  static base::NoDestructor<TrustStoreMac> static_trust_store_mac(
+      kSecPolicyAppleSSL, GetTrustStoreImplParam(kDefaultMacTrustImplForCRS),
+      GetTrustStoreCacheSize(), TrustStoreMac::TrustDomains::kUserAndAdmin);
+  return static_trust_store_mac.get();
+}
+
+void InitializeTrustCacheForCRSOnWorkerThread() {
+  GetGlobalTrustStoreMacForCRS()->InitializeTrustCache();
+}
+
+}  // namespace
+
+std::unique_ptr<SystemTrustStore> CreateSslSystemTrustStoreChromeRoot(
+    std::unique_ptr<TrustStoreChrome> chrome_root) {
+  return std::make_unique<SystemTrustStoreChromeWithUnOwnedSystemStore>(
+      std::move(chrome_root), GetGlobalTrustStoreMacForCRS());
+}
+#endif  // CHROME_ROOT_STORE_SUPPORTED
+
 void InitializeTrustStoreMacCache() {
-  base::ThreadPool::PostTask(
-      FROM_HERE,
-      {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-      base::BindOnce(&SystemTrustStoreMac::InitializeTrustCacheOnWorkerThread));
+  if (base::FeatureList::IsEnabled(net::features::kChromeRootStoreUsed)) {
+    base::ThreadPool::PostTask(
+        FROM_HERE,
+        {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+        base::BindOnce(&InitializeTrustCacheForCRSOnWorkerThread));
+  } else if (base::FeatureList::IsEnabled(
+                 net::features::kCertVerifierBuiltinFeature)) {
+    base::ThreadPool::PostTask(
+        FROM_HERE,
+        {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+        base::BindOnce(
+            &SystemTrustStoreMac::InitializeTrustCacheOnWorkerThread));
+  }
 }
 
 #elif BUILDFLAG(IS_FUCHSIA)
diff --git a/net/cert/internal/system_trust_store.h b/net/cert/internal/system_trust_store.h
index 9cbf4da..cc1cd6be 100644
--- a/net/cert/internal/system_trust_store.h
+++ b/net/cert/internal/system_trust_store.h
@@ -99,7 +99,8 @@
 NET_EXPORT std::unique_ptr<SystemTrustStore> CreateEmptySystemTrustStore();
 
 #if BUILDFLAG(IS_MAC)
-// Initializes trust cache on a worker thread.
+// Initializes trust cache on a worker thread, if the builtin verifier is
+// enabled.
 NET_EXPORT void InitializeTrustStoreMacCache();
 #endif
 
diff --git a/net/cert/internal/trust_store_mac.cc b/net/cert/internal/trust_store_mac.cc
index fed6c8e..5a179e71 100644
--- a/net/cert/internal/trust_store_mac.cc
+++ b/net/cert/internal/trust_store_mac.cc
@@ -288,6 +288,7 @@
 
 TrustStatus IsCertificateTrustedForPolicy(const ParsedCertificate* cert,
                                           const CFStringRef policy_oid,
+                                          TrustStoreMac::TrustDomains domains,
                                           int* debug_info,
                                           KnownRootStatus* out_is_known_root) {
   // |*out_is_known_root| is intentionally not cleared before starting, as
@@ -309,6 +310,10 @@
   for (const auto& trust_domain :
        {kSecTrustSettingsDomainUser, kSecTrustSettingsDomainAdmin,
         kSecTrustSettingsDomainSystem}) {
+    if (domains == TrustStoreMac::TrustDomains::kUserAndAdmin &&
+        trust_domain == kSecTrustSettingsDomainSystem) {
+      continue;
+    }
     base::ScopedCFTypeRef<CFArrayRef> trust_settings;
     OSStatus err;
     {
@@ -596,10 +601,14 @@
 // modified.
 class TrustStoreMac::TrustImplDomainCache : public TrustStoreMac::TrustImpl {
  public:
-  explicit TrustImplDomainCache(CFStringRef policy_oid)
-      : system_domain_cache_(kSecTrustSettingsDomainSystem, policy_oid),
+  explicit TrustImplDomainCache(CFStringRef policy_oid, TrustDomains domains)
+      : use_system_domain_cache_(domains == TrustDomains::kAll),
         admin_domain_cache_(kSecTrustSettingsDomainAdmin, policy_oid),
         user_domain_cache_(kSecTrustSettingsDomainUser, policy_oid) {
+    if (use_system_domain_cache_) {
+      system_domain_cache_ = std::make_unique<TrustDomainCache>(
+          kSecTrustSettingsDomainSystem, policy_oid);
+    }
     keychain_observer_ = std::make_unique<KeychainTrustObserver>();
   }
 
@@ -613,11 +622,13 @@
 
   // Returns true if |cert| is present in kSecTrustSettingsDomainSystem.
   bool IsKnownRoot(const ParsedCertificate* cert) override {
+    if (!use_system_domain_cache_)
+      return false;
     SHA256HashValue cert_hash = CalculateFingerprint256(cert->der_cert());
 
     base::AutoLock lock(cache_lock_);
     MaybeInitializeCache();
-    return system_domain_cache_.ContainsCert(cert_hash);
+    return system_domain_cache_->ContainsCert(cert_hash);
   }
 
   // Returns the trust status for |cert|.
@@ -632,12 +643,15 @@
     // override system ones, and user settings can override both admin and
     // system.
     for (TrustDomainCache* trust_domain_cache :
-         {&user_domain_cache_, &admin_domain_cache_, &system_domain_cache_}) {
+         {&user_domain_cache_, &admin_domain_cache_}) {
       TrustStatus ts =
           trust_domain_cache->IsCertTrusted(cert, cert_hash, debug_data);
       if (ts != TrustStatus::UNSPECIFIED)
         return ts;
     }
+    if (use_system_domain_cache_) {
+      return system_domain_cache_->IsCertTrusted(cert, cert_hash, debug_data);
+    }
 
     // Cert did not have trust settings in any domain.
     return TrustStatus::UNSPECIFIED;
@@ -661,22 +675,26 @@
     iteration_ = keychain_iteration;
     user_domain_cache_.Initialize();
     admin_domain_cache_.Initialize();
-    if (!system_domain_initialized_) {
+    if (use_system_domain_cache_ && !system_domain_initialized_) {
       // In practice, the system trust domain does not change during runtime,
       // and SecTrustSettingsCopyCertificates on the system domain is quite
       // slow, so the system domain cache is not reset on keychain changes.
-      system_domain_cache_.Initialize();
+      system_domain_cache_->Initialize();
       system_domain_initialized_ = true;
     }
   }
 
   std::unique_ptr<KeychainTrustObserver> keychain_observer_;
+  // Store whether to use the system domain in a const bool that is initialized
+  // in constructor so it is safe to read without having to lock first.
+  const bool use_system_domain_cache_;
 
   base::Lock cache_lock_;
   // |cache_lock_| must be held while accessing any following members.
   int64_t iteration_ GUARDED_BY(cache_lock_) = -1;
   bool system_domain_initialized_ GUARDED_BY(cache_lock_) = false;
-  TrustDomainCache system_domain_cache_ GUARDED_BY(cache_lock_);
+  std::unique_ptr<TrustDomainCache> system_domain_cache_
+      GUARDED_BY(cache_lock_);
   TrustDomainCache admin_domain_cache_ GUARDED_BY(cache_lock_);
   TrustDomainCache user_domain_cache_ GUARDED_BY(cache_lock_);
 };
@@ -685,7 +703,8 @@
 // SecTrustSettingsCopyTrustSettings on every cert checked, with no caching.
 class TrustStoreMac::TrustImplNoCache : public TrustStoreMac::TrustImpl {
  public:
-  explicit TrustImplNoCache(CFStringRef policy_oid) : policy_oid_(policy_oid) {}
+  explicit TrustImplNoCache(CFStringRef policy_oid, TrustDomains domains)
+      : policy_oid_(policy_oid), domains_(domains) {}
 
   TrustImplNoCache(const TrustImplNoCache&) = delete;
   TrustImplNoCache& operator=(const TrustImplNoCache&) = delete;
@@ -694,6 +713,8 @@
 
   // Returns true if |cert| is present in kSecTrustSettingsDomainSystem.
   bool IsKnownRoot(const ParsedCertificate* cert) override {
+    if (domains_ == TrustDomains::kUserAndAdmin)
+      return false;
     HashValue cert_hash(CalculateFingerprint256(cert->der_cert()));
     base::AutoLock lock(crypto::GetMacSecurityServicesLock());
     return net::IsKnownRoot(cert_hash);
@@ -703,8 +724,9 @@
   TrustStatus IsCertTrusted(const ParsedCertificate* cert,
                             base::SupportsUserData* debug_data) override {
     int debug_info = 0;
-    TrustStatus result = IsCertificateTrustedForPolicy(
-        cert, policy_oid_, &debug_info, /*out_is_known_root=*/nullptr);
+    TrustStatus result =
+        IsCertificateTrustedForPolicy(cert, policy_oid_, domains_, &debug_info,
+                                      /*out_is_known_root=*/nullptr);
     UpdateUserData(debug_info, debug_data,
                    TrustStoreMac::TrustImplType::kSimple);
     return result;
@@ -716,6 +738,7 @@
 
  private:
   const CFStringRef policy_oid_;
+  const TrustDomains domains_;
 };
 
 // TrustImplLRUCache is calls SecTrustSettingsCopyTrustSettings on every cert
@@ -723,8 +746,12 @@
 // keychain updates.
 class TrustStoreMac::TrustImplLRUCache : public TrustStoreMac::TrustImpl {
  public:
-  TrustImplLRUCache(CFStringRef policy_oid, size_t cache_size)
-      : policy_oid_(policy_oid), trust_status_cache_(cache_size) {
+  TrustImplLRUCache(CFStringRef policy_oid,
+                    size_t cache_size,
+                    TrustDomains domains)
+      : policy_oid_(policy_oid),
+        domains_(domains),
+        trust_status_cache_(cache_size) {
     keychain_observer_ = std::make_unique<KeychainTrustObserver>();
   }
 
@@ -738,6 +765,8 @@
 
   // Returns true if |cert| has trust settings in kSecTrustSettingsDomainSystem.
   bool IsKnownRoot(const ParsedCertificate* cert) override {
+    if (domains_ == TrustDomains::kUserAndAdmin)
+      return false;
     return GetKnownRootStatus(cert) == KnownRootStatus::IS_KNOWN_ROOT;
   }
 
@@ -818,7 +847,7 @@
     }
 
     trust_details.trust_status = IsCertificateTrustedForPolicy(
-        cert, policy_oid_, &trust_details.debug_info,
+        cert, policy_oid_, domains_, &trust_details.debug_info,
         &trust_details.is_known_root);
 
     {
@@ -841,6 +870,7 @@
   }
 
   const CFStringRef policy_oid_;
+  const TrustDomains domains_;
   std::unique_ptr<KeychainTrustObserver> keychain_observer_;
 
   base::Lock cache_lock_;
@@ -858,20 +888,23 @@
 
 TrustStoreMac::TrustStoreMac(CFStringRef policy_oid,
                              TrustImplType impl,
-                             size_t cache_size) {
+                             size_t cache_size,
+                             TrustDomains domains)
+    : domains_(domains) {
   switch (impl) {
     case TrustImplType::kUnknown:
       DCHECK(false);
       break;
     case TrustImplType::kDomainCache:
-      trust_cache_ = std::make_unique<TrustImplDomainCache>(policy_oid);
+      trust_cache_ =
+          std::make_unique<TrustImplDomainCache>(policy_oid, domains);
       break;
     case TrustImplType::kSimple:
-      trust_cache_ = std::make_unique<TrustImplNoCache>(policy_oid);
+      trust_cache_ = std::make_unique<TrustImplNoCache>(policy_oid, domains);
       break;
     case TrustImplType::kLruCache:
       trust_cache_ =
-          std::make_unique<TrustImplLRUCache>(policy_oid, cache_size);
+          std::make_unique<TrustImplLRUCache>(policy_oid, cache_size, domains);
       break;
   }
 }
@@ -893,7 +926,7 @@
     return;
 
   std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> matching_cert_buffers =
-      FindMatchingCertificatesForMacNormalizedSubject(name_data);
+      FindMatchingCertificatesForMacNormalizedSubject(name_data, domains_);
 
   // Convert to ParsedCertificate.
   for (auto& buffer : matching_cert_buffers) {
@@ -937,7 +970,8 @@
 // static
 std::vector<bssl::UniquePtr<CRYPTO_BUFFER>>
 TrustStoreMac::FindMatchingCertificatesForMacNormalizedSubject(
-    CFDataRef name_data) {
+    CFDataRef name_data,
+    TrustDomains domains) {
   std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> matching_cert_buffers;
   base::ScopedCFTypeRef<CFMutableDictionaryRef> query(
       CFDictionaryCreateMutable(nullptr, 0, &kCFTypeDictionaryKeyCallBacks,
@@ -961,43 +995,48 @@
     }
   }
 
-  // If a TestKeychainSearchList is present, it will have already set
-  // |scoped_alternate_keychain_search_list|, which will be used as the
-  // basis for reordering the keychain. Otherwise, get the current keychain
-  // search list and use that.
-  if (!scoped_alternate_keychain_search_list) {
-    OSStatus status = SecKeychainCopySearchList(
-        scoped_alternate_keychain_search_list.InitializeInto());
-    if (status) {
-      OSSTATUS_LOG(ERROR, status) << "SecKeychainCopySearchList error";
+  if (domains == TrustDomains::kAll) {
+    // If a TestKeychainSearchList is present, it will have already set
+    // |scoped_alternate_keychain_search_list|, which will be used as the
+    // basis for reordering the keychain. Otherwise, get the current keychain
+    // search list and use that.
+    if (!scoped_alternate_keychain_search_list) {
+      OSStatus status = SecKeychainCopySearchList(
+          scoped_alternate_keychain_search_list.InitializeInto());
+      if (status) {
+        OSSTATUS_LOG(ERROR, status) << "SecKeychainCopySearchList error";
+        return matching_cert_buffers;
+      }
+    }
+
+    CFMutableArrayRef mutable_keychain_search_list = CFArrayCreateMutableCopy(
+        kCFAllocatorDefault,
+        CFArrayGetCount(scoped_alternate_keychain_search_list.get()) + 1,
+        scoped_alternate_keychain_search_list.get());
+    if (!mutable_keychain_search_list) {
+      LOG(ERROR) << "CFArrayCreateMutableCopy";
       return matching_cert_buffers;
     }
+    scoped_alternate_keychain_search_list.reset(mutable_keychain_search_list);
+
+    base::ScopedCFTypeRef<SecKeychainRef> roots_keychain;
+    // The System Roots keychain is not normally searched by
+    // SecItemCopyMatching. Get a reference to it and include in the keychain
+    // search list.
+    OSStatus status = SecKeychainOpen(
+        "/System/Library/Keychains/SystemRootCertificates.keychain",
+        roots_keychain.InitializeInto());
+    if (status) {
+      OSSTATUS_LOG(ERROR, status) << "SecKeychainOpen error";
+      return matching_cert_buffers;
+    }
+    CFArrayAppendValue(mutable_keychain_search_list, roots_keychain);
   }
 
-  CFMutableArrayRef mutable_keychain_search_list = CFArrayCreateMutableCopy(
-      kCFAllocatorDefault,
-      CFArrayGetCount(scoped_alternate_keychain_search_list.get()) + 1,
-      scoped_alternate_keychain_search_list.get());
-  if (!mutable_keychain_search_list) {
-    LOG(ERROR) << "CFArrayCreateMutableCopy";
-    return matching_cert_buffers;
+  if (scoped_alternate_keychain_search_list) {
+    CFDictionarySetValue(query, kSecMatchSearchList,
+                         scoped_alternate_keychain_search_list.get());
   }
-  scoped_alternate_keychain_search_list.reset(mutable_keychain_search_list);
-
-  base::ScopedCFTypeRef<SecKeychainRef> roots_keychain;
-  // The System Roots keychain is not normally searched by SecItemCopyMatching.
-  // Get a reference to it and include in the keychain search list.
-  OSStatus status = SecKeychainOpen(
-      "/System/Library/Keychains/SystemRootCertificates.keychain",
-      roots_keychain.InitializeInto());
-  if (status) {
-    OSSTATUS_LOG(ERROR, status) << "SecKeychainOpen error";
-    return matching_cert_buffers;
-  }
-  CFArrayAppendValue(mutable_keychain_search_list, roots_keychain);
-
-  CFDictionarySetValue(query, kSecMatchSearchList,
-                       scoped_alternate_keychain_search_list.get());
 
   base::ScopedCFTypeRef<CFArrayRef> matching_items;
   OSStatus err = SecItemCopyMatching(
diff --git a/net/cert/internal/trust_store_mac.h b/net/cert/internal/trust_store_mac.h
index 02c39fc..693cb122 100644
--- a/net/cert/internal/trust_store_mac.h
+++ b/net/cert/internal/trust_store_mac.h
@@ -81,6 +81,17 @@
     kLruCache = 3,
   };
 
+  enum class TrustDomains {
+    // Load trust settings and certificates from all three trust domains
+    // (user, admin, system).
+    kAll = 0,
+
+    // Load trust settings and certificates from only the user and admin trust
+    // domains. This will find trust settings that have been set locally or by
+    // an enterprise, but not those distributed with the OS.
+    kUserAndAdmin = 1,
+  };
+
   class ResultDebugData : public base::SupportsUserData::Data {
    public:
     static const ResultDebugData* Get(const base::SupportsUserData* debug_data);
@@ -111,7 +122,10 @@
   // |impl| selects which internal implementation is used for checking trust
   // settings, and the interpretation of |cache_size| varies depending on
   // |impl|.
-  TrustStoreMac(CFStringRef policy_oid, TrustImplType impl, size_t cache_size);
+  TrustStoreMac(CFStringRef policy_oid,
+                TrustImplType impl,
+                size_t cache_size,
+                TrustDomains domains);
 
   TrustStoreMac(const TrustStoreMac&) = delete;
   TrustStoreMac& operator=(const TrustStoreMac&) = delete;
@@ -143,7 +157,8 @@
   // The result is an array of CRYPTO_BUFFERs containing the DER certificate
   // data.
   static std::vector<bssl::UniquePtr<CRYPTO_BUFFER>>
-  FindMatchingCertificatesForMacNormalizedSubject(CFDataRef name_data);
+  FindMatchingCertificatesForMacNormalizedSubject(CFDataRef name_data,
+                                                  TrustDomains domains);
 
   // Returns the OS-normalized issuer of |cert|.
   // macOS internally uses a normalized form of subject/issuer names for
@@ -152,6 +167,7 @@
   static base::ScopedCFTypeRef<CFDataRef> GetMacNormalizedIssuer(
       const ParsedCertificate* cert);
 
+  TrustDomains domains_;
   std::unique_ptr<TrustImpl> trust_cache_;
 };
 
diff --git a/net/cert/internal/trust_store_mac_unittest.cc b/net/cert/internal/trust_store_mac_unittest.cc
index 095b90d..1d5ab31 100644
--- a/net/cert/internal/trust_store_mac_unittest.cc
+++ b/net/cert/internal/trust_store_mac_unittest.cc
@@ -4,15 +4,20 @@
 
 #include "net/cert/internal/trust_store_mac.h"
 
+#include <algorithm>
+#include <set>
+
 #include "base/base_paths.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
 #include "base/path_service.h"
 #include "base/process/launch.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/synchronization/lock.h"
 #include "crypto/mac_security_services_lock.h"
+#include "crypto/sha2.h"
 #include "net/cert/internal/cert_errors.h"
 #include "net/cert/internal/test_helpers.h"
 #include "net/cert/known_roots_mac.h"
@@ -83,6 +88,28 @@
   return result;
 }
 
+std::set<std::string> ParseFindCertificateOutputToDerCerts(std::string output) {
+  std::set<std::string> certs;
+  for (const std::string& hash_and_pem_partial : base::SplitStringUsingSubstr(
+           output, "-----END CERTIFICATE-----", base::TRIM_WHITESPACE,
+           base::SPLIT_WANT_NONEMPTY)) {
+    // Re-add the PEM ending mark, since SplitStringUsingSubstr eats it.
+    const std::string hash_and_pem =
+        hash_and_pem_partial + "\n-----END CERTIFICATE-----\n";
+
+    // Parse the PEM encoded text to DER bytes.
+    PEMTokenizer pem_tokenizer(hash_and_pem, {kCertificateHeader});
+    if (!pem_tokenizer.GetNext()) {
+      ADD_FAILURE() << "!pem_tokenizer.GetNext()";
+      continue;
+    }
+    std::string cert_der(pem_tokenizer.data());
+    EXPECT_FALSE(pem_tokenizer.GetNext());
+    certs.insert(cert_der);
+  }
+  return certs;
+}
+
 class DebugData : public base::SupportsUserData {
  public:
   ~DebugData() override = default;
@@ -96,8 +123,9 @@
 }  // namespace
 
 class TrustStoreMacImplTest
-    : public testing::TestWithParam<
-          std::tuple<TrustStoreMac::TrustImplType, IsKnownRootTestOrder>> {};
+    : public testing::TestWithParam<std::tuple<TrustStoreMac::TrustImplType,
+                                               IsKnownRootTestOrder,
+                                               TrustStoreMac::TrustDomains>> {};
 
 // Test the trust store using known test certificates in a keychain.  Tests
 // that issuer searching returns the expected certificates, and that none of
@@ -120,7 +148,9 @@
 
   const TrustStoreMac::TrustImplType trust_impl = std::get<0>(GetParam());
   const IsKnownRootTestOrder is_known_root_test_order = std::get<1>(GetParam());
-  TrustStoreMac trust_store(kSecPolicyAppleSSL, trust_impl, kDefaultCacheSize);
+  const TrustStoreMac::TrustDomains trust_domains = std::get<2>(GetParam());
+  TrustStoreMac trust_store(kSecPolicyAppleSSL, trust_impl, kDefaultCacheSize,
+                            trust_domains);
 
   scoped_refptr<ParsedCertificate> a_by_b, b_by_c, b_by_f, c_by_d, c_by_e,
       f_by_e, d_by_d, e_by_e;
@@ -155,7 +185,7 @@
   {
     std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> scoped_matching_items =
         TrustStoreMac::FindMatchingCertificatesForMacNormalizedSubject(
-            normalized_name_b.get());
+            normalized_name_b.get(), trust_domains);
 
     EXPECT_THAT(CryptoBufferVectorAsStringVector(scoped_matching_items),
                 UnorderedElementsAreArray(
@@ -165,7 +195,7 @@
   {
     std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> scoped_matching_items =
         TrustStoreMac::FindMatchingCertificatesForMacNormalizedSubject(
-            normalized_name_c.get());
+            normalized_name_c.get(), trust_domains);
     EXPECT_THAT(CryptoBufferVectorAsStringVector(scoped_matching_items),
                 UnorderedElementsAreArray(
                     ParsedCertificateListAsDER({c_by_d, c_by_e})));
@@ -174,7 +204,7 @@
   {
     std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> scoped_matching_items =
         TrustStoreMac::FindMatchingCertificatesForMacNormalizedSubject(
-            normalized_name_f.get());
+            normalized_name_f.get(), trust_domains);
     EXPECT_THAT(
         CryptoBufferVectorAsStringVector(scoped_matching_items),
         UnorderedElementsAreArray(ParsedCertificateListAsDER({f_by_e})));
@@ -183,7 +213,7 @@
   {
     std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> scoped_matching_items =
         TrustStoreMac::FindMatchingCertificatesForMacNormalizedSubject(
-            normalized_name_d.get());
+            normalized_name_d.get(), trust_domains);
     EXPECT_THAT(
         CryptoBufferVectorAsStringVector(scoped_matching_items),
         UnorderedElementsAreArray(ParsedCertificateListAsDER({d_by_d})));
@@ -192,7 +222,7 @@
   {
     std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> scoped_matching_items =
         TrustStoreMac::FindMatchingCertificatesForMacNormalizedSubject(
-            normalized_name_e.get());
+            normalized_name_e.get(), trust_domains);
     EXPECT_THAT(
         CryptoBufferVectorAsStringVector(scoped_matching_items),
         UnorderedElementsAreArray(ParsedCertificateListAsDER({e_by_e})));
@@ -242,43 +272,31 @@
        "/System/Library/Keychains/SystemRootCertificates.keychain"},
       &find_certificate_system_roots_output));
 
+  std::set<std::string> find_certificate_default_search_list_certs =
+      ParseFindCertificateOutputToDerCerts(
+          find_certificate_default_search_list_output);
+  std::set<std::string> find_certificate_system_roots_certs =
+      ParseFindCertificateOutputToDerCerts(
+          find_certificate_system_roots_output);
+
   const TrustStoreMac::TrustImplType trust_impl = std::get<0>(GetParam());
   const IsKnownRootTestOrder is_known_root_test_order = std::get<1>(GetParam());
+  const TrustStoreMac::TrustDomains trust_domains = std::get<2>(GetParam());
   TrustStoreMac trust_store(kSecPolicyAppleX509Basic, trust_impl,
-                            kDefaultCacheSize);
+                            kDefaultCacheSize, trust_domains);
 
   base::ScopedCFTypeRef<SecPolicyRef> sec_policy(SecPolicyCreateBasicX509());
   ASSERT_TRUE(sec_policy);
-  for (const std::string& hash_and_pem_partial : base::SplitStringUsingSubstr(
-           find_certificate_system_roots_output +
-               find_certificate_default_search_list_output,
-           "-----END CERTIFICATE-----", base::TRIM_WHITESPACE,
-           base::SPLIT_WANT_NONEMPTY)) {
-    // Re-add the PEM ending mark, since SplitStringUsingSubstr eats it.
-    const std::string hash_and_pem =
-        hash_and_pem_partial + "\n-----END CERTIFICATE-----\n";
-
-    // Use the first hash value found in the text. This might be SHA-256 or
-    // SHA-1, but it's only for debugging purposes so it doesn't matter as long
-    // as one exists.
-    std::string::size_type hash_pos = hash_and_pem.find("hash: ");
-    ASSERT_NE(std::string::npos, hash_pos);
-    hash_pos += 6;
-    std::string::size_type eol_pos = hash_and_pem.find_first_of("\r\n");
-    ASSERT_NE(std::string::npos, eol_pos);
-    // Extract the hash of the certificate. This isn't necessary for the
-    // test, but is a convenient identifier to use in any error messages.
-    std::string hash_text = hash_and_pem.substr(hash_pos, eol_pos - hash_pos);
-
+  std::vector<std::string> all_certs;
+  std::set_union(find_certificate_default_search_list_certs.begin(),
+                 find_certificate_default_search_list_certs.end(),
+                 find_certificate_system_roots_certs.begin(),
+                 find_certificate_system_roots_certs.end(),
+                 std::back_inserter(all_certs));
+  for (const std::string& cert_der : all_certs) {
+    std::string hash = crypto::SHA256HashString(cert_der);
+    std::string hash_text = base::HexEncode(hash.data(), hash.size());
     SCOPED_TRACE(hash_text);
-    // TODO(mattm): The same cert might exist in both lists, could de-dupe
-    // before testing?
-
-    // Parse the PEM encoded text to DER bytes.
-    PEMTokenizer pem_tokenizer(hash_and_pem, {kCertificateHeader});
-    ASSERT_TRUE(pem_tokenizer.GetNext());
-    std::string cert_der(pem_tokenizer.data());
-    ASSERT_FALSE(pem_tokenizer.GetNext());
 
     CertErrors errors;
     // Note: don't actually need to make a ParsedCertificate here, just need
@@ -307,9 +325,11 @@
 
     if (is_known_root_test_order == TEST_IS_KNOWN_ROOT_BEFORE) {
       bool trust_store_is_known_root = trust_store.IsKnownRoot(cert.get());
-      {
+      if (trust_domains == TrustStoreMac::TrustDomains::kAll) {
         base::AutoLock lock(crypto::GetMacSecurityServicesLock());
         EXPECT_EQ(net::IsKnownRoot(cert_handle), trust_store_is_known_root);
+      } else {
+        EXPECT_FALSE(trust_store_is_known_root);
       }
     }
 
@@ -334,13 +354,18 @@
                                               kSecTrustOptionAllowExpired |
                                               kSecTrustOptionAllowExpiredRoot));
 
-      SecTrustResultType trust_result;
-      ASSERT_EQ(noErr, SecTrustEvaluate(trust, &trust_result));
-      bool expected_trust_anchor =
-          ((trust_result == kSecTrustResultProceed) ||
-           (trust_result == kSecTrustResultUnspecified)) &&
-          (SecTrustGetCertificateCount(trust) == 1);
-      EXPECT_EQ(expected_trust_anchor, is_trust_anchor);
+      if (trust_domains == TrustStoreMac::TrustDomains::kUserAndAdmin &&
+          !find_certificate_default_search_list_certs.count(cert_der)) {
+        EXPECT_FALSE(is_trust_anchor);
+      } else {
+        SecTrustResultType trust_result;
+        ASSERT_EQ(noErr, SecTrustEvaluate(trust, &trust_result));
+        bool expected_trust_anchor =
+            ((trust_result == kSecTrustResultProceed) ||
+             (trust_result == kSecTrustResultUnspecified)) &&
+            (SecTrustGetCertificateCount(trust) == 1);
+        EXPECT_EQ(expected_trust_anchor, is_trust_anchor);
+      }
       auto* trust_debug_data = TrustStoreMac::ResultDebugData::Get(&debug_data);
       ASSERT_TRUE(trust_debug_data);
       if (is_trust_anchor) {
@@ -355,9 +380,11 @@
 
     if (is_known_root_test_order == TEST_IS_KNOWN_ROOT_AFTER) {
       bool trust_store_is_known_root = trust_store.IsKnownRoot(cert.get());
-      {
+      if (trust_domains == TrustStoreMac::TrustDomains::kAll) {
         base::AutoLock lock(crypto::GetMacSecurityServicesLock());
         EXPECT_EQ(net::IsKnownRoot(cert_handle), trust_store_is_known_root);
+      } else {
+        EXPECT_FALSE(trust_store_is_known_root);
       }
     }
 
@@ -388,6 +415,8 @@
         // values independently, so test with calling IsKnownRoot both before
         // and after GetTrust to try to ensure there is no ordering issue with
         // which one initializes the cache first.
-        testing::Values(TEST_IS_KNOWN_ROOT_BEFORE, TEST_IS_KNOWN_ROOT_AFTER)));
+        testing::Values(TEST_IS_KNOWN_ROOT_BEFORE, TEST_IS_KNOWN_ROOT_AFTER),
+        testing::Values(TrustStoreMac::TrustDomains::kAll,
+                        TrustStoreMac::TrustDomains::kUserAndAdmin)));
 
 }  // namespace net
diff --git a/net/data/ssl/chrome_root_store/README.md b/net/data/ssl/chrome_root_store/README.md
index 040f80e..b8f9423 100644
--- a/net/data/ssl/chrome_root_store/README.md
+++ b/net/data/ssl/chrome_root_store/README.md
@@ -4,11 +4,32 @@
 [Chrome Root Store](https://www.chromium.org/Home/chromium-security/root-ca-policy).
 It is currently not used for trust decisions in Chrome.
 
-The root store is defined by `store/root_store.textproto` file, which is a
-`RootStore` [protobuf](https://developers.google.com/protocol-buffers) message,
-defined in
-[`//net/tools/root_store_tool/root_store.proto`](/net/tools/root_store_tool/root_store.proto).
-It references certificates in the `store/certs` directory. The
-[`root_store_tool`](/net/tools/root_store_tool/root_store_tool.cc) will
-files in this directory to eventually use this data for trust decisions in
-Chrome.
+The root store is defined by two files:
+
+* `root_store.textproto` file, which is a `RootStore`
+  [protobuf](https://developers.google.com/protocol-buffers) message, defined in
+  [`//net/cert/root_store.proto`](/net/cert/root_store.proto).
+
+* `root_store.certs` which stores the certificates referenced by
+  `root_store.textproto`
+
+The [`root_store_tool`](/net/tools/root_store_tool/root_store_tool.cc) uses the
+two files above to generate code that is included in Chrome. This generated code
+will eventually be used for trust decisions in Chrome.
+
+## Testing
+
+To test the Chrome Root store, do the following:
+
+* On M102 or higher on Windows, run Chrome with the following flag:
+
+  `--enable-features=ChromeRootStoreUsed`
+
+As of 2022-06, an example of a web site that is trusted by Windows Root Store
+but not by Chrome Root Store is https://rootcertificateprograms.edicom.es/. This
+can be used to test if Chrome Root Store is turned on or not (for best results
+use a fresh incognito window to avoid any caching issues).
+
+If you're running 104.0.5110.0 or higher, the currently used Chrome Root Store
+version can be seen in a [NetLog
+dump](https://www.chromium.org/for-testers/providing-network-details/).
diff --git a/net/features.gni b/net/features.gni
index a812f6f7..3cf1e4a 100644
--- a/net/features.gni
+++ b/net/features.gni
@@ -47,5 +47,5 @@
 
   # Platforms for which the builtin cert verifier can use the Chrome Root Store.
   # See https://crbug.com/1216547 for status.
-  chrome_root_store_supported = is_win
+  chrome_root_store_supported = is_win || is_mac
 }
diff --git a/net/network_error_logging/network_error_logging_service_unittest.cc b/net/network_error_logging/network_error_logging_service_unittest.cc
index 675f8513..2cd8921 100644
--- a/net/network_error_logging/network_error_logging_service_unittest.cc
+++ b/net/network_error_logging/network_error_logging_service_unittest.cc
@@ -429,27 +429,28 @@
   EXPECT_EQ(0, reports()[0].depth);
 
   const base::Value* body = reports()[0].body.get();
-  const base::Value::Dict* body_dict = body->GetIfDict();
-  ASSERT_TRUE(body_dict);
+  ASSERT_TRUE(body);
+  ASSERT_TRUE(body->is_dict());
+  const base::Value::Dict& body_dict = body->GetDict();
 
-  base::ExpectDictStringValue(kReferrer_.spec(), *body,
+  base::ExpectDictStringValue(kReferrer_.spec(), body_dict,
                               NetworkErrorLoggingService::kReferrerKey);
   // TODO(juliatuttle): Extract these constants.
-  ExpectDictDoubleValue(1.0, *body_dict,
+  ExpectDictDoubleValue(1.0, body_dict,
                         NetworkErrorLoggingService::kSamplingFractionKey);
-  base::ExpectDictStringValue(kServerIP_.ToString(), *body,
+  base::ExpectDictStringValue(kServerIP_.ToString(), body_dict,
                               NetworkErrorLoggingService::kServerIpKey);
-  base::ExpectDictStringValue("", *body,
+  base::ExpectDictStringValue("", body_dict,
                               NetworkErrorLoggingService::kProtocolKey);
-  base::ExpectDictStringValue("GET", *body,
+  base::ExpectDictStringValue("GET", body_dict,
                               NetworkErrorLoggingService::kMethodKey);
-  base::ExpectDictIntegerValue(0, *body,
+  base::ExpectDictIntegerValue(0, body_dict,
                                NetworkErrorLoggingService::kStatusCodeKey);
-  base::ExpectDictIntegerValue(1000, *body,
+  base::ExpectDictIntegerValue(1000, body_dict,
                                NetworkErrorLoggingService::kElapsedTimeKey);
-  base::ExpectDictStringValue("application", *body,
+  base::ExpectDictStringValue("application", body_dict,
                               NetworkErrorLoggingService::kPhaseKey);
-  base::ExpectDictStringValue("ok", *body,
+  base::ExpectDictStringValue("ok", body_dict,
                               NetworkErrorLoggingService::kTypeKey);
 }
 
@@ -473,27 +474,28 @@
   EXPECT_EQ(0, reports()[0].depth);
 
   const base::Value* body = reports()[0].body.get();
-  const base::Value::Dict* body_dict = body->GetIfDict();
-  ASSERT_TRUE(body_dict);
+  ASSERT_TRUE(body);
+  ASSERT_TRUE(body->is_dict());
+  const base::Value::Dict& body_dict = body->GetDict();
 
-  base::ExpectDictStringValue(kReferrer_.spec(), *body,
+  base::ExpectDictStringValue(kReferrer_.spec(), body_dict,
                               NetworkErrorLoggingService::kReferrerKey);
   // TODO(juliatuttle): Extract these constants.
-  ExpectDictDoubleValue(1.0, *body_dict,
+  ExpectDictDoubleValue(1.0, body_dict,
                         NetworkErrorLoggingService::kSamplingFractionKey);
-  base::ExpectDictStringValue(kServerIP_.ToString(), *body,
+  base::ExpectDictStringValue(kServerIP_.ToString(), body_dict,
                               NetworkErrorLoggingService::kServerIpKey);
-  base::ExpectDictStringValue("", *body,
+  base::ExpectDictStringValue("", body_dict,
                               NetworkErrorLoggingService::kProtocolKey);
-  base::ExpectDictStringValue("GET", *body,
+  base::ExpectDictStringValue("GET", body_dict,
                               NetworkErrorLoggingService::kMethodKey);
-  base::ExpectDictIntegerValue(0, *body,
+  base::ExpectDictIntegerValue(0, body_dict,
                                NetworkErrorLoggingService::kStatusCodeKey);
-  base::ExpectDictIntegerValue(1000, *body,
+  base::ExpectDictIntegerValue(1000, body_dict,
                                NetworkErrorLoggingService::kElapsedTimeKey);
-  base::ExpectDictStringValue("connection", *body,
+  base::ExpectDictStringValue("connection", body_dict,
                               NetworkErrorLoggingService::kPhaseKey);
-  base::ExpectDictStringValue("tcp.refused", *body,
+  base::ExpectDictStringValue("tcp.refused", body_dict,
                               NetworkErrorLoggingService::kTypeKey);
 }
 
@@ -511,10 +513,12 @@
 
   ASSERT_EQ(1u, reports().size());
   const base::Value* body = reports()[0].body.get();
+  ASSERT_TRUE(body);
   ASSERT_TRUE(body->is_dict());
-  base::ExpectDictStringValue("application", *body,
+  const base::Value::Dict& body_dict = body->GetDict();
+  base::ExpectDictStringValue("application", body_dict,
                               NetworkErrorLoggingService::kPhaseKey);
-  base::ExpectDictStringValue("unknown", *body,
+  base::ExpectDictStringValue("unknown", body_dict,
                               NetworkErrorLoggingService::kTypeKey);
 }
 
@@ -534,10 +538,12 @@
 
   ASSERT_EQ(1u, reports().size());
   const base::Value* body = reports()[0].body.get();
+  ASSERT_TRUE(body);
   ASSERT_TRUE(body->is_dict());
-  base::ExpectDictStringValue("connection", *body,
+  const base::Value::Dict& body_dict = body->GetDict();
+  base::ExpectDictStringValue("connection", body_dict,
                               NetworkErrorLoggingService::kPhaseKey);
-  base::ExpectDictStringValue("unknown", *body,
+  base::ExpectDictStringValue("unknown", body_dict,
                               NetworkErrorLoggingService::kTypeKey);
 }
 
@@ -560,27 +566,28 @@
   EXPECT_EQ(0, reports()[0].depth);
 
   const base::Value* body = reports()[0].body.get();
-  const base::Value::Dict* body_dict = body->GetIfDict();
-  ASSERT_TRUE(body_dict);
+  ASSERT_TRUE(body);
+  ASSERT_TRUE(body->is_dict());
+  const base::Value::Dict& body_dict = body->GetDict();
 
-  base::ExpectDictStringValue(kReferrer_.spec(), *body,
+  base::ExpectDictStringValue(kReferrer_.spec(), body_dict,
                               NetworkErrorLoggingService::kReferrerKey);
   // TODO(juliatuttle): Extract these constants.
-  ExpectDictDoubleValue(1.0, *body_dict,
+  ExpectDictDoubleValue(1.0, body_dict,
                         NetworkErrorLoggingService::kSamplingFractionKey);
-  base::ExpectDictStringValue(kServerIP_.ToString(), *body,
+  base::ExpectDictStringValue(kServerIP_.ToString(), body_dict,
                               NetworkErrorLoggingService::kServerIpKey);
-  base::ExpectDictStringValue("", *body,
+  base::ExpectDictStringValue("", body_dict,
                               NetworkErrorLoggingService::kProtocolKey);
-  base::ExpectDictStringValue("GET", *body,
+  base::ExpectDictStringValue("GET", body_dict,
                               NetworkErrorLoggingService::kMethodKey);
-  base::ExpectDictIntegerValue(504, *body,
+  base::ExpectDictIntegerValue(504, body_dict,
                                NetworkErrorLoggingService::kStatusCodeKey);
-  base::ExpectDictIntegerValue(1000, *body,
+  base::ExpectDictIntegerValue(1000, body_dict,
                                NetworkErrorLoggingService::kElapsedTimeKey);
-  base::ExpectDictStringValue("application", *body,
+  base::ExpectDictStringValue("application", body_dict,
                               NetworkErrorLoggingService::kPhaseKey);
-  base::ExpectDictStringValue("http.error", *body,
+  base::ExpectDictStringValue("http.error", body_dict,
                               NetworkErrorLoggingService::kTypeKey);
 }
 
@@ -601,26 +608,27 @@
   EXPECT_EQ(0, reports()[0].depth);
 
   const base::Value* body = reports()[0].body.get();
-  const base::Value::Dict* body_dict = body->GetIfDict();
-  ASSERT_TRUE(body_dict);
+  ASSERT_TRUE(body);
+  ASSERT_TRUE(body->is_dict());
+  const base::Value::Dict& body_dict = body->GetDict();
 
-  base::ExpectDictStringValue(kReferrer_.spec(), *body,
+  base::ExpectDictStringValue(kReferrer_.spec(), body_dict,
                               NetworkErrorLoggingService::kReferrerKey);
-  ExpectDictDoubleValue(1.0, *body_dict,
+  ExpectDictDoubleValue(1.0, body_dict,
                         NetworkErrorLoggingService::kSamplingFractionKey);
-  base::ExpectDictStringValue(kOtherServerIP_.ToString(), *body,
+  base::ExpectDictStringValue(kOtherServerIP_.ToString(), body_dict,
                               NetworkErrorLoggingService::kServerIpKey);
-  base::ExpectDictStringValue("", *body,
+  base::ExpectDictStringValue("", body_dict,
                               NetworkErrorLoggingService::kProtocolKey);
-  base::ExpectDictStringValue("GET", *body,
+  base::ExpectDictStringValue("GET", body_dict,
                               NetworkErrorLoggingService::kMethodKey);
-  base::ExpectDictIntegerValue(0, *body,
+  base::ExpectDictIntegerValue(0, body_dict,
                                NetworkErrorLoggingService::kStatusCodeKey);
-  base::ExpectDictIntegerValue(0, *body,
+  base::ExpectDictIntegerValue(0, body_dict,
                                NetworkErrorLoggingService::kElapsedTimeKey);
-  base::ExpectDictStringValue("dns", *body,
+  base::ExpectDictStringValue("dns", body_dict,
                               NetworkErrorLoggingService::kPhaseKey);
-  base::ExpectDictStringValue("dns.address_changed", *body,
+  base::ExpectDictStringValue("dns.address_changed", body_dict,
                               NetworkErrorLoggingService::kTypeKey);
 }
 
@@ -641,26 +649,27 @@
   EXPECT_EQ(0, reports()[0].depth);
 
   const base::Value* body = reports()[0].body.get();
-  const base::Value::Dict* body_dict = body->GetIfDict();
-  ASSERT_TRUE(body_dict);
+  ASSERT_TRUE(body);
+  ASSERT_TRUE(body->is_dict());
+  const base::Value::Dict& body_dict = body->GetDict();
 
-  base::ExpectDictStringValue(kReferrer_.spec(), *body,
+  base::ExpectDictStringValue(kReferrer_.spec(), body_dict,
                               NetworkErrorLoggingService::kReferrerKey);
-  ExpectDictDoubleValue(1.0, *body_dict,
+  ExpectDictDoubleValue(1.0, body_dict,
                         NetworkErrorLoggingService::kSamplingFractionKey);
-  base::ExpectDictStringValue(kOtherServerIP_.ToString(), *body,
+  base::ExpectDictStringValue(kOtherServerIP_.ToString(), body_dict,
                               NetworkErrorLoggingService::kServerIpKey);
-  base::ExpectDictStringValue("", *body,
+  base::ExpectDictStringValue("", body_dict,
                               NetworkErrorLoggingService::kProtocolKey);
-  base::ExpectDictStringValue("GET", *body,
+  base::ExpectDictStringValue("GET", body_dict,
                               NetworkErrorLoggingService::kMethodKey);
-  base::ExpectDictIntegerValue(0, *body,
+  base::ExpectDictIntegerValue(0, body_dict,
                                NetworkErrorLoggingService::kStatusCodeKey);
-  base::ExpectDictIntegerValue(0, *body,
+  base::ExpectDictIntegerValue(0, body_dict,
                                NetworkErrorLoggingService::kElapsedTimeKey);
-  base::ExpectDictStringValue("dns", *body,
+  base::ExpectDictStringValue("dns", body_dict,
                               NetworkErrorLoggingService::kPhaseKey);
-  base::ExpectDictStringValue("dns.address_changed", *body,
+  base::ExpectDictStringValue("dns.address_changed", body_dict,
                               NetworkErrorLoggingService::kTypeKey);
 }
 
@@ -681,26 +690,27 @@
   EXPECT_EQ(0, reports()[0].depth);
 
   const base::Value* body = reports()[0].body.get();
-  const base::Value::Dict* body_dict = body->GetIfDict();
-  ASSERT_TRUE(body_dict);
+  ASSERT_TRUE(body);
+  ASSERT_TRUE(body->is_dict());
+  const base::Value::Dict& body_dict = body->GetDict();
 
-  base::ExpectDictStringValue(kReferrer_.spec(), *body,
+  base::ExpectDictStringValue(kReferrer_.spec(), body_dict,
                               NetworkErrorLoggingService::kReferrerKey);
-  ExpectDictDoubleValue(1.0, *body_dict,
+  ExpectDictDoubleValue(1.0, body_dict,
                         NetworkErrorLoggingService::kSamplingFractionKey);
-  base::ExpectDictStringValue(kOtherServerIP_.ToString(), *body,
+  base::ExpectDictStringValue(kOtherServerIP_.ToString(), body_dict,
                               NetworkErrorLoggingService::kServerIpKey);
-  base::ExpectDictStringValue("", *body,
+  base::ExpectDictStringValue("", body_dict,
                               NetworkErrorLoggingService::kProtocolKey);
-  base::ExpectDictStringValue("GET", *body,
+  base::ExpectDictStringValue("GET", body_dict,
                               NetworkErrorLoggingService::kMethodKey);
-  base::ExpectDictIntegerValue(0, *body,
+  base::ExpectDictIntegerValue(0, body_dict,
                                NetworkErrorLoggingService::kStatusCodeKey);
-  base::ExpectDictIntegerValue(0, *body,
+  base::ExpectDictIntegerValue(0, body_dict,
                                NetworkErrorLoggingService::kElapsedTimeKey);
-  base::ExpectDictStringValue("dns", *body,
+  base::ExpectDictStringValue("dns", body_dict,
                               NetworkErrorLoggingService::kPhaseKey);
-  base::ExpectDictStringValue("dns.address_changed", *body,
+  base::ExpectDictStringValue("dns.address_changed", body_dict,
                               NetworkErrorLoggingService::kTypeKey);
 }
 
@@ -721,26 +731,27 @@
   EXPECT_EQ(0, reports()[0].depth);
 
   const base::Value* body = reports()[0].body.get();
-  const base::Value::Dict* body_dict = body->GetIfDict();
-  ASSERT_TRUE(body_dict);
+  ASSERT_TRUE(body);
+  ASSERT_TRUE(body->is_dict());
+  const base::Value::Dict& body_dict = body->GetDict();
 
-  base::ExpectDictStringValue(kReferrer_.spec(), *body,
+  base::ExpectDictStringValue(kReferrer_.spec(), body_dict,
                               NetworkErrorLoggingService::kReferrerKey);
-  ExpectDictDoubleValue(1.0, *body_dict,
+  ExpectDictDoubleValue(1.0, body_dict,
                         NetworkErrorLoggingService::kSamplingFractionKey);
-  base::ExpectDictStringValue(kOtherServerIP_.ToString(), *body,
+  base::ExpectDictStringValue(kOtherServerIP_.ToString(), body_dict,
                               NetworkErrorLoggingService::kServerIpKey);
-  base::ExpectDictStringValue("", *body,
+  base::ExpectDictStringValue("", body_dict,
                               NetworkErrorLoggingService::kProtocolKey);
-  base::ExpectDictStringValue("GET", *body,
+  base::ExpectDictStringValue("GET", body_dict,
                               NetworkErrorLoggingService::kMethodKey);
-  base::ExpectDictIntegerValue(0, *body,
+  base::ExpectDictIntegerValue(0, body_dict,
                                NetworkErrorLoggingService::kStatusCodeKey);
-  base::ExpectDictIntegerValue(1000, *body,
+  base::ExpectDictIntegerValue(1000, body_dict,
                                NetworkErrorLoggingService::kElapsedTimeKey);
-  base::ExpectDictStringValue("dns", *body,
+  base::ExpectDictStringValue("dns", body_dict,
                               NetworkErrorLoggingService::kPhaseKey);
-  base::ExpectDictStringValue("dns.name_not_resolved", *body,
+  base::ExpectDictStringValue("dns.name_not_resolved", body_dict,
                               NetworkErrorLoggingService::kTypeKey);
 }
 
@@ -760,22 +771,23 @@
   EXPECT_EQ(0, reports()[0].depth);
 
   const base::Value* body = reports()[0].body.get();
-  const base::Value::Dict* body_dict = body->GetIfDict();
-  ASSERT_TRUE(body_dict);
+  ASSERT_TRUE(body);
+  ASSERT_TRUE(body->is_dict());
+  const base::Value::Dict& body_dict = body->GetDict();
 
-  base::ExpectDictStringValue(kReferrer_.spec(), *body,
+  base::ExpectDictStringValue(kReferrer_.spec(), body_dict,
                               NetworkErrorLoggingService::kReferrerKey);
-  ExpectDictDoubleValue(1.0, *body_dict,
+  ExpectDictDoubleValue(1.0, body_dict,
                         NetworkErrorLoggingService::kSamplingFractionKey);
-  base::ExpectDictStringValue(kServerIP_.ToString(), *body,
+  base::ExpectDictStringValue(kServerIP_.ToString(), body_dict,
                               NetworkErrorLoggingService::kServerIpKey);
-  base::ExpectDictStringValue("", *body,
+  base::ExpectDictStringValue("", body_dict,
                               NetworkErrorLoggingService::kProtocolKey);
-  base::ExpectDictStringValue("POST", *body,
+  base::ExpectDictStringValue("POST", body_dict,
                               NetworkErrorLoggingService::kMethodKey);
-  base::ExpectDictStringValue("application", *body,
+  base::ExpectDictStringValue("application", body_dict,
                               NetworkErrorLoggingService::kPhaseKey);
-  base::ExpectDictStringValue("ok", *body,
+  base::ExpectDictStringValue("ok", body_dict,
                               NetworkErrorLoggingService::kTypeKey);
 }
 
@@ -1237,41 +1249,41 @@
   EXPECT_EQ(0, reports()[0].depth);
 
   const base::Value* body = reports()[0].body.get();
-  const base::Value::Dict* body_dict = body->GetIfDict();
-  ASSERT_TRUE(body_dict);
+  ASSERT_TRUE(body);
+  ASSERT_TRUE(body->is_dict());
+  const base::Value::Dict& body_dict = body->GetDict();
 
-  base::ExpectDictStringValue(kReferrer_.spec(), *body,
+  base::ExpectDictStringValue(kReferrer_.spec(), body_dict,
                               NetworkErrorLoggingService::kReferrerKey);
-  ExpectDictDoubleValue(1.0, *body_dict,
+  ExpectDictDoubleValue(1.0, body_dict,
                         NetworkErrorLoggingService::kSamplingFractionKey);
-  base::ExpectDictStringValue(kServerIP_.ToString(), *body,
+  base::ExpectDictStringValue(kServerIP_.ToString(), body_dict,
                               NetworkErrorLoggingService::kServerIpKey);
-  base::ExpectDictStringValue("http/1.1", *body,
+  base::ExpectDictStringValue("http/1.1", body_dict,
                               NetworkErrorLoggingService::kProtocolKey);
-  base::ExpectDictStringValue("GET", *body,
+  base::ExpectDictStringValue("GET", body_dict,
                               NetworkErrorLoggingService::kMethodKey);
-  base::ExpectDictIntegerValue(200, *body,
+  base::ExpectDictIntegerValue(200, body_dict,
                                NetworkErrorLoggingService::kStatusCodeKey);
-  base::ExpectDictIntegerValue(1234, *body,
+  base::ExpectDictIntegerValue(1234, body_dict,
                                NetworkErrorLoggingService::kElapsedTimeKey);
   base::ExpectDictStringValue(
-      NetworkErrorLoggingService::kSignedExchangePhaseValue, *body,
+      NetworkErrorLoggingService::kSignedExchangePhaseValue, body_dict,
       NetworkErrorLoggingService::kPhaseKey);
-  base::ExpectDictStringValue("ok", *body,
+  base::ExpectDictStringValue("ok", body_dict,
                               NetworkErrorLoggingService::kTypeKey);
 
-  const base::Value* sxg_body =
-      body_dict->Find(NetworkErrorLoggingService::kSignedExchangeBodyKey);
-  ASSERT_TRUE(sxg_body && sxg_body->is_dict());
+  const base::Value::Dict* sxg_body =
+      body_dict.FindDict(NetworkErrorLoggingService::kSignedExchangeBodyKey);
+  ASSERT_TRUE(sxg_body);
 
   base::ExpectDictStringValue(kUrl_.spec(), *sxg_body,
                               NetworkErrorLoggingService::kOuterUrlKey);
   base::ExpectDictStringValue(kInnerUrl_.spec(), *sxg_body,
                               NetworkErrorLoggingService::kInnerUrlKey);
-  base::ExpectStringValue(kCertUrl_.spec(),
-                          sxg_body->GetDict()
-                              .Find(NetworkErrorLoggingService::kCertUrlKey)
-                              ->GetList()[0]);
+  base::ExpectStringValue(
+      kCertUrl_.spec(),
+      sxg_body->Find(NetworkErrorLoggingService::kCertUrlKey)->GetList()[0]);
 }
 
 TEST_P(NetworkErrorLoggingServiceTest, FailureReportQueued_SignedExchange) {
@@ -1291,41 +1303,41 @@
   EXPECT_EQ(0, reports()[0].depth);
 
   const base::Value* body = reports()[0].body.get();
-  const base::Value::Dict* body_dict = body->GetIfDict();
-  ASSERT_TRUE(body_dict);
+  ASSERT_TRUE(body);
+  ASSERT_TRUE(body->is_dict());
+  const base::Value::Dict& body_dict = body->GetDict();
 
-  base::ExpectDictStringValue(kReferrer_.spec(), *body,
+  base::ExpectDictStringValue(kReferrer_.spec(), body_dict,
                               NetworkErrorLoggingService::kReferrerKey);
-  ExpectDictDoubleValue(1.0, *body_dict,
+  ExpectDictDoubleValue(1.0, body_dict,
                         NetworkErrorLoggingService::kSamplingFractionKey);
-  base::ExpectDictStringValue(kServerIP_.ToString(), *body,
+  base::ExpectDictStringValue(kServerIP_.ToString(), body_dict,
                               NetworkErrorLoggingService::kServerIpKey);
-  base::ExpectDictStringValue("http/1.1", *body,
+  base::ExpectDictStringValue("http/1.1", body_dict,
                               NetworkErrorLoggingService::kProtocolKey);
-  base::ExpectDictStringValue("GET", *body,
+  base::ExpectDictStringValue("GET", body_dict,
                               NetworkErrorLoggingService::kMethodKey);
-  base::ExpectDictIntegerValue(200, *body,
+  base::ExpectDictIntegerValue(200, body_dict,
                                NetworkErrorLoggingService::kStatusCodeKey);
-  base::ExpectDictIntegerValue(1234, *body,
+  base::ExpectDictIntegerValue(1234, body_dict,
                                NetworkErrorLoggingService::kElapsedTimeKey);
   base::ExpectDictStringValue(
-      NetworkErrorLoggingService::kSignedExchangePhaseValue, *body,
+      NetworkErrorLoggingService::kSignedExchangePhaseValue, body_dict,
       NetworkErrorLoggingService::kPhaseKey);
-  base::ExpectDictStringValue("sxg.failed", *body,
+  base::ExpectDictStringValue("sxg.failed", body_dict,
                               NetworkErrorLoggingService::kTypeKey);
 
-  const base::Value* sxg_body =
-      body_dict->Find(NetworkErrorLoggingService::kSignedExchangeBodyKey);
-  ASSERT_TRUE(sxg_body && sxg_body->is_dict());
+  const base::Value::Dict* sxg_body =
+      body_dict.FindDict(NetworkErrorLoggingService::kSignedExchangeBodyKey);
+  ASSERT_TRUE(sxg_body);
 
   base::ExpectDictStringValue(kUrl_.spec(), *sxg_body,
                               NetworkErrorLoggingService::kOuterUrlKey);
   base::ExpectDictStringValue(kInnerUrl_.spec(), *sxg_body,
                               NetworkErrorLoggingService::kInnerUrlKey);
-  base::ExpectStringValue(kCertUrl_.spec(),
-                          sxg_body->GetDict()
-                              .Find(NetworkErrorLoggingService::kCertUrlKey)
-                              ->GetList()[0]);
+  base::ExpectStringValue(
+      kCertUrl_.spec(),
+      sxg_body->Find(NetworkErrorLoggingService::kCertUrlKey)->GetList()[0]);
 }
 
 TEST_P(NetworkErrorLoggingServiceTest, MismatchingSubdomain_SignedExchange) {
diff --git a/net/reporting/reporting_delivery_agent_unittest.cc b/net/reporting/reporting_delivery_agent_unittest.cc
index 5d38ffe..8096155a 100644
--- a/net/reporting/reporting_delivery_agent_unittest.cc
+++ b/net/reporting/reporting_delivery_agent_unittest.cc
@@ -160,15 +160,16 @@
     ASSERT_TRUE(value->is_list());
     ASSERT_EQ(1u, value->GetList().size());
 
-    base::Value& report = value->GetList()[0];
+    const base::Value& report = value->GetList()[0];
     ASSERT_TRUE(report.is_dict());
-    EXPECT_EQ(5u, report.GetDict().size());
+    const base::Value::Dict& report_dict = report.GetDict();
+    EXPECT_EQ(5u, report_dict.size());
 
-    ExpectDictIntegerValue(0, report, "age");
-    ExpectDictStringValue(kType_, report, "type");
-    ExpectDictStringValue(kUrl_.spec(), report, "url");
-    ExpectDictStringValue(kUserAgent_, report, "user_agent");
-    const base::Value::Dict* body = report.GetDict().FindDict("body");
+    ExpectDictIntegerValue(0, report_dict, "age");
+    ExpectDictStringValue(kType_, report_dict, "type");
+    ExpectDictStringValue(kUrl_.spec(), report_dict, "url");
+    ExpectDictStringValue(kUserAgent_, report_dict, "user_agent");
+    const base::Value::Dict* body = report_dict.FindDict("body");
     EXPECT_EQ("value", *body->FindString("key"));
   }
   pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
@@ -238,12 +239,13 @@
 
     const base::Value& report = value->GetList()[0];
     ASSERT_TRUE(report.is_dict());
+    const base::Value::Dict& report_dict = report.GetDict();
 
-    ExpectDictIntegerValue(0, report, "age");
-    ExpectDictStringValue(kType_, report, "type");
-    ExpectDictStringValue(kUrl_.spec(), report, "url");
-    ExpectDictStringValue(kUserAgent_, report, "user_agent");
-    const base::Value::Dict* body = report.GetDict().FindDict("body");
+    ExpectDictIntegerValue(0, report_dict, "age");
+    ExpectDictStringValue(kType_, report_dict, "type");
+    ExpectDictStringValue(kUrl_.spec(), report_dict, "url");
+    ExpectDictStringValue(kUserAgent_, report_dict, "user_agent");
+    const base::Value::Dict* body = report_dict.FindDict("body");
     EXPECT_EQ("value", *body->FindString("key"));
   }
   pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
@@ -314,15 +316,16 @@
     ASSERT_TRUE(value->is_list());
     ASSERT_EQ(1u, value->GetList().size());
 
-    base::Value& report = value->GetList()[0];
+    const base::Value& report = value->GetList()[0];
     ASSERT_TRUE(report.is_dict());
-    EXPECT_EQ(5u, report.GetDict().size());
+    const base::Value::Dict& report_dict = report.GetDict();
+    EXPECT_EQ(5u, report_dict.size());
 
-    ExpectDictIntegerValue(0, report, "age");
-    ExpectDictStringValue(kType_, report, "type");
-    ExpectDictStringValue(kSubdomainUrl_.spec(), report, "url");
-    ExpectDictStringValue(kUserAgent_, report, "user_agent");
-    const base::Value::Dict* body = report.GetDict().FindDict("body");
+    ExpectDictIntegerValue(0, report_dict, "age");
+    ExpectDictStringValue(kType_, report_dict, "type");
+    ExpectDictStringValue(kSubdomainUrl_.spec(), report_dict, "url");
+    ExpectDictStringValue(kUserAgent_, report_dict, "user_agent");
+    const base::Value::Dict* body = report_dict.FindDict("body");
     EXPECT_EQ("value", *body->FindString("key"));
   }
   pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
@@ -393,15 +396,16 @@
     ASSERT_TRUE(value->is_list());
     ASSERT_EQ(1u, value->GetList().size());
 
-    base::Value& report = value->GetList()[0];
+    const base::Value& report = value->GetList()[0];
     ASSERT_TRUE(report.is_dict());
-    EXPECT_EQ(5u, report.GetDict().size());
+    const base::Value::Dict& report_dict = report.GetDict();
+    EXPECT_EQ(5u, report_dict.size());
 
-    ExpectDictIntegerValue(0, report, "age");
-    ExpectDictStringValue(kType_, report, "type");
-    ExpectDictStringValue(kUrl_.spec(), report, "url");
-    ExpectDictStringValue(kUserAgent_, report, "user_agent");
-    const base::Value::Dict* body = report.GetDict().FindDict("body");
+    ExpectDictIntegerValue(0, report_dict, "age");
+    ExpectDictStringValue(kType_, report_dict, "type");
+    ExpectDictStringValue(kUrl_.spec(), report_dict, "url");
+    ExpectDictStringValue(kUserAgent_, report_dict, "user_agent");
+    const base::Value::Dict* body = report_dict.FindDict("body");
     EXPECT_EQ("value", *body->FindString("key"));
   }
   pending_uploads()[0]->Complete(ReportingUploader::Outcome::SUCCESS);
diff --git a/printing/backend/print_backend.h b/printing/backend/print_backend.h
index 2320c63c..c64365f 100644
--- a/printing/backend/print_backend.h
+++ b/printing/backend/print_backend.h
@@ -210,12 +210,12 @@
  public:
   // Enumerates the list of installed local and network printers.  It will
   // return success when the available installed printers have been enumerated
-  // into `printer_list`.  Note that `printer_list` must not be null and also
-  // should be empty prior to this call.  If there are no printers installed
-  // then it will still return success, and `printer_list` remains empty.  The
-  // result code will return one of the error result codes when there is a
-  // failure in generating the list.
-  virtual mojom::ResultCode EnumeratePrinters(PrinterList* printer_list) = 0;
+  // into `printer_list`.  Note that `printer_list` should be empty prior to
+  // this call.  If there are no printers installed then it will still return
+  // success, and `printer_list` remains empty.  The result code will return
+  // one of the error result codes when there is a failure in generating the
+  // list.
+  virtual mojom::ResultCode EnumeratePrinters(PrinterList& printer_list) = 0;
 
   // Gets the default printer name.  If there is no default printer then it
   // will still return success and `default_printer` will be empty.  The result
diff --git a/printing/backend/print_backend_chromeos.cc b/printing/backend/print_backend_chromeos.cc
index 332ab95..da17144 100644
--- a/printing/backend/print_backend_chromeos.cc
+++ b/printing/backend/print_backend_chromeos.cc
@@ -23,7 +23,7 @@
   PrintBackendChromeOS() = default;
 
   // PrintBackend implementation.
-  mojom::ResultCode EnumeratePrinters(PrinterList* printer_list) override;
+  mojom::ResultCode EnumeratePrinters(PrinterList& printer_list) override;
   mojom::ResultCode GetDefaultPrinterName(
       std::string& default_printer) override;
   mojom::ResultCode GetPrinterBasicInfo(
@@ -43,7 +43,7 @@
 };
 
 mojom::ResultCode PrintBackendChromeOS::EnumeratePrinters(
-    PrinterList* printer_list) {
+    PrinterList& printer_list) {
   return mojom::ResultCode::kSuccess;
 }
 
diff --git a/printing/backend/print_backend_cups.cc b/printing/backend/print_backend_cups.cc
index 0025d77..ac1029b0 100644
--- a/printing/backend/print_backend_cups.cc
+++ b/printing/backend/print_backend_cups.cc
@@ -136,9 +136,8 @@
 }
 
 mojom::ResultCode PrintBackendCUPS::EnumeratePrinters(
-    PrinterList* printer_list) {
-  DCHECK(printer_list);
-  printer_list->clear();
+    PrinterList& printer_list) {
+  DCHECK(printer_list.empty());
 
   // If possible prefer to use cupsEnumDests() over GetDests(), because the
   // latter has been found to filter out some destination values if a device
@@ -191,14 +190,14 @@
     PrinterBasicInfo printer_info;
     if (PrinterBasicInfoFromCUPS(printer, &printer_info) ==
         mojom::ResultCode::kSuccess) {
-      printer_list->push_back(printer_info);
+      printer_list.push_back(printer_info);
     }
   }
 
   cupsFreeDests(dests_data.num_dests, dests_data.dests);
 
   VLOG(1) << "CUPS: Enumerated printers, server: " << print_server_url_
-          << ", # of printers: " << printer_list->size();
+          << ", # of printers: " << printer_list.size();
   return mojom::ResultCode::kSuccess;
 }
 
diff --git a/printing/backend/print_backend_cups.h b/printing/backend/print_backend_cups.h
index 707a556..d57acda07 100644
--- a/printing/backend/print_backend_cups.h
+++ b/printing/backend/print_backend_cups.h
@@ -42,7 +42,7 @@
   ~PrintBackendCUPS() override;
 
   // PrintBackend implementation.
-  mojom::ResultCode EnumeratePrinters(PrinterList* printer_list) override;
+  mojom::ResultCode EnumeratePrinters(PrinterList& printer_list) override;
   mojom::ResultCode GetDefaultPrinterName(
       std::string& default_printer) override;
   mojom::ResultCode GetPrinterBasicInfo(
diff --git a/printing/backend/print_backend_cups_ipp.cc b/printing/backend/print_backend_cups_ipp.cc
index 571f0ee..46b1a928 100644
--- a/printing/backend/print_backend_cups_ipp.cc
+++ b/printing/backend/print_backend_cups_ipp.cc
@@ -29,9 +29,8 @@
 PrintBackendCupsIpp::~PrintBackendCupsIpp() = default;
 
 mojom::ResultCode PrintBackendCupsIpp::EnumeratePrinters(
-    PrinterList* printer_list) {
-  DCHECK(printer_list);
-  printer_list->clear();
+    PrinterList& printer_list) {
+  DCHECK(printer_list.empty());
 
   std::vector<std::unique_ptr<CupsPrinter>> printers;
   if (!cups_connection_->GetDests(printers)) {
@@ -47,7 +46,7 @@
   for (const auto& printer : printers) {
     PrinterBasicInfo basic_info;
     if (printer->ToPrinterInfo(&basic_info)) {
-      printer_list->push_back(basic_info);
+      printer_list.push_back(basic_info);
     }
   }
 
diff --git a/printing/backend/print_backend_cups_ipp.h b/printing/backend/print_backend_cups_ipp.h
index 554601e1..e133cc08 100644
--- a/printing/backend/print_backend_cups_ipp.h
+++ b/printing/backend/print_backend_cups_ipp.h
@@ -22,7 +22,7 @@
   ~PrintBackendCupsIpp() override;
 
   // PrintBackend implementation.
-  mojom::ResultCode EnumeratePrinters(PrinterList* printer_list) override;
+  mojom::ResultCode EnumeratePrinters(PrinterList& printer_list) override;
   mojom::ResultCode GetDefaultPrinterName(
       std::string& default_printer) override;
   mojom::ResultCode GetPrinterBasicInfo(
diff --git a/printing/backend/print_backend_dummy.cc b/printing/backend/print_backend_dummy.cc
index 4ef0ddc..d8bb625 100644
--- a/printing/backend/print_backend_dummy.cc
+++ b/printing/backend/print_backend_dummy.cc
@@ -19,7 +19,7 @@
   DummyPrintBackend(const DummyPrintBackend&) = delete;
   DummyPrintBackend& operator=(const DummyPrintBackend&) = delete;
 
-  mojom::ResultCode EnumeratePrinters(PrinterList* printer_list) override {
+  mojom::ResultCode EnumeratePrinters(PrinterList& printer_list) override {
     return mojom::ResultCode::kFailed;
   }
 
diff --git a/printing/backend/print_backend_unittest.cc b/printing/backend/print_backend_unittest.cc
index 83dfc0e..595b0ea 100644
--- a/printing/backend/print_backend_unittest.cc
+++ b/printing/backend/print_backend_unittest.cc
@@ -39,7 +39,7 @@
 TEST_F(PrintBackendTest, MANUAL_EnumeratePrintersSomeInstalled) {
   PrinterList printer_list;
 
-  EXPECT_EQ(GetPrintBackend()->EnumeratePrinters(&printer_list),
+  EXPECT_EQ(GetPrintBackend()->EnumeratePrinters(printer_list),
             mojom::ResultCode::kSuccess);
   EXPECT_FALSE(printer_list.empty());
 
@@ -52,7 +52,7 @@
 TEST_F(PrintBackendTest, MANUAL_EnumeratePrintersNoneInstalled) {
   PrinterList printer_list;
 
-  EXPECT_EQ(GetPrintBackend()->EnumeratePrinters(&printer_list),
+  EXPECT_EQ(GetPrintBackend()->EnumeratePrinters(printer_list),
             mojom::ResultCode::kSuccess);
   EXPECT_TRUE(printer_list.empty());
 }
@@ -63,7 +63,7 @@
 // specific printer.
 TEST_F(PrintBackendTest, MANUAL_GetXmlPrinterCapabilitiesForXpsDriver) {
   PrinterList printer_list;
-  EXPECT_EQ(GetPrintBackend()->EnumeratePrinters(&printer_list),
+  EXPECT_EQ(GetPrintBackend()->EnumeratePrinters(printer_list),
             mojom::ResultCode::kSuccess);
   for (const auto& printer : printer_list) {
     std::string capabilities;
diff --git a/printing/backend/print_backend_win.cc b/printing/backend/print_backend_win.cc
index 81af33e..a4eb611b 100644
--- a/printing/backend/print_backend_win.cc
+++ b/printing/backend/print_backend_win.cc
@@ -266,7 +266,7 @@
   PrintBackendWin() = default;
 
   // PrintBackend implementation.
-  mojom::ResultCode EnumeratePrinters(PrinterList* printer_list) override;
+  mojom::ResultCode EnumeratePrinters(PrinterList& printer_list) override;
   mojom::ResultCode GetDefaultPrinterName(
       std::string& default_printer) override;
   mojom::ResultCode GetPrinterBasicInfo(
@@ -286,8 +286,8 @@
 };
 
 mojom::ResultCode PrintBackendWin::EnumeratePrinters(
-    PrinterList* printer_list) {
-  DCHECK(printer_list);
+    PrinterList& printer_list) {
+  DCHECK(printer_list.empty());
   DWORD bytes_needed = 0;
   DWORD count_returned = 0;
   constexpr DWORD kFlags = PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS;
@@ -329,7 +329,7 @@
     if (printer.OpenPrinterWithName(printer_info[index].pPrinterName) &&
         InitBasicPrinterInfo(printer.Get(), &info)) {
       info.is_default = (info.printer_name == default_printer);
-      printer_list->push_back(info);
+      printer_list.push_back(info);
     }
   }
 
diff --git a/printing/backend/test_print_backend.cc b/printing/backend/test_print_backend.cc
index 0c17a26..8d3e8336 100644
--- a/printing/backend/test_print_backend.cc
+++ b/printing/backend/test_print_backend.cc
@@ -46,8 +46,8 @@
 TestPrintBackend::~TestPrintBackend() = default;
 
 mojom::ResultCode TestPrintBackend::EnumeratePrinters(
-    PrinterList* printer_list) {
-  DCHECK(printer_list->empty());
+    PrinterList& printer_list) {
+  DCHECK(printer_list.empty());
   if (printer_map_.empty())
     return mojom::ResultCode::kSuccess;
 
@@ -56,7 +56,7 @@
 
     // Can only return basic info for printers which have registered info.
     if (data->info)
-      printer_list->emplace_back(*data->info);
+      printer_list.emplace_back(*data->info);
   }
   return mojom::ResultCode::kSuccess;
 }
diff --git a/printing/backend/test_print_backend.h b/printing/backend/test_print_backend.h
index f9dae87..2d493970d 100644
--- a/printing/backend/test_print_backend.h
+++ b/printing/backend/test_print_backend.h
@@ -21,7 +21,7 @@
   TestPrintBackend();
 
   // PrintBackend overrides
-  mojom::ResultCode EnumeratePrinters(PrinterList* printer_list) override;
+  mojom::ResultCode EnumeratePrinters(PrinterList& printer_list) override;
   mojom::ResultCode GetDefaultPrinterName(
       std::string& default_printer) override;
   mojom::ResultCode GetPrinterBasicInfo(
diff --git a/printing/backend/test_print_backend_unittest.cc b/printing/backend/test_print_backend_unittest.cc
index df18b87..439c081 100644
--- a/printing/backend/test_print_backend_unittest.cc
+++ b/printing/backend/test_print_backend_unittest.cc
@@ -101,7 +101,7 @@
 
   AddPrinters();
 
-  EXPECT_EQ(GetPrintBackend()->EnumeratePrinters(&printer_list),
+  EXPECT_EQ(GetPrintBackend()->EnumeratePrinters(printer_list),
             mojom::ResultCode::kSuccess);
   EXPECT_THAT(printer_list, testing::ContainerEq(kPrinterList));
 }
@@ -111,7 +111,7 @@
   PrinterList printer_list;
 
   // Should return true even when there are no printers in the environment.
-  EXPECT_EQ(GetPrintBackend()->EnumeratePrinters(&printer_list),
+  EXPECT_EQ(GetPrintBackend()->EnumeratePrinters(printer_list),
             mojom::ResultCode::kSuccess);
   EXPECT_TRUE(printer_list.empty());
 }
diff --git a/services/cert_verifier/cert_verifier_creation.cc b/services/cert_verifier/cert_verifier_creation.cc
index 89af309..77047c6a 100644
--- a/services/cert_verifier/cert_verifier_creation.cc
+++ b/services/cert_verifier/cert_verifier_creation.cc
@@ -191,7 +191,17 @@
       primary_proc_factory->CreateCertVerifyProc(cert_net_fetcher,
                                                  root_store_data);
 
-#if BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
+#if BUILDFLAG(BUILTIN_CERT_VERIFIER_FEATURE_SUPPORTED) && \
+    BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
+  scoped_refptr<net::CertVerifyProcFactory> trial_proc_factory;
+  if (net::features::kCertDualVerificationTrialUseCrs.Get()) {
+    trial_proc_factory =
+        base::MakeRefCounted<NewCertVerifyProcChromeRootStoreFactory>();
+  } else {
+    trial_proc_factory =
+        base::MakeRefCounted<NewCertVerifyProcBuiltinFactory>();
+  }
+#elif BUILDFLAG(CHROME_ROOT_STORE_SUPPORTED)
   auto trial_proc_factory =
       base::MakeRefCounted<NewCertVerifyProcChromeRootStoreFactory>();
 #else
diff --git a/services/network/cors/cors_url_loader_factory.cc b/services/network/cors/cors_url_loader_factory.cc
index 8ddf6ba9b..d4f63ca 100644
--- a/services/network/cors/cors_url_loader_factory.cc
+++ b/services/network/cors/cors_url_loader_factory.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/debug/crash_logging.h"
 #include "base/logging.h"
 #include "mojo/public/cpp/bindings/message.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -250,6 +251,9 @@
     mojo::PendingRemote<mojom::URLLoaderClient> client,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
   debug::ScopedResourceRequestCrashKeys request_crash_keys(resource_request);
+  SCOPED_CRASH_KEY_NUMBER("net", "traffic_annotation_hash",
+                          traffic_annotation.unique_id_hash_code);
+  SCOPED_CRASH_KEY_STRING64("network", "factory_debug_tag", debug_tag_);
 
   if (!IsValidRequest(resource_request, options)) {
     mojo::Remote<mojom::URLLoaderClient>(std::move(client))
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 1c8b786..6b5b62d9 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -327,6 +327,22 @@
             ]
         }
     ],
+    "AndroidSearchEnginePromoV2": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "SearchEnginePromo.ExistingDeviceVer2",
+                        "SearchEnginePromo.NewDeviceVer2"
+                    ]
+                }
+            ]
+        }
+    ],
     "AndroidSystemTracing": [
         {
             "platforms": [
@@ -2691,33 +2707,6 @@
             ]
         }
     ],
-    "ContentLanguagesInLanguagePicker": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "EnabledWithoutObservers",
-                    "params": {
-                        "disable_observers": "true"
-                    },
-                    "enable_features": [
-                        "ContentLanguagesInLanguagePicker"
-                    ]
-                },
-                {
-                    "name": "EnabledWithObservers",
-                    "params": {
-                        "disable_observers": "false"
-                    },
-                    "enable_features": [
-                        "ContentLanguagesInLanguagePicker"
-                    ]
-                }
-            ]
-        }
-    ],
     "ContextMenuGoogleLensChip": [
         {
             "platforms": [
@@ -8175,6 +8164,22 @@
             ]
         }
     ],
+    "TranslateMessageUI": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "ContentLanguagesInLanguagePicker",
+                        "TranslateMessageUI"
+                    ]
+                }
+            ]
+        }
+    ],
     "TrustSafetySentimentSurvey": [
         {
             "platforms": [
@@ -8359,6 +8364,25 @@
             ]
         }
     ],
+    "UnifiedPasswordManagerDesktop": [
+        {
+            "platforms": [
+                "chromeos",
+                "chromeos_lacros",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "UnifiedPasswordManagerDesktop"
+                    ]
+                }
+            ]
+        }
+    ],
     "UpdateHistoryEntryPointsInIncognito": [
         {
             "platforms": [
diff --git a/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy b/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
index f0738d7..0a3f4495 100644
--- a/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
+++ b/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
@@ -659,7 +659,7 @@
                 sb.append('  ignore_aidl = true\n')
                 break
             case 'androidx_test_uiautomator_uiautomator':
-                sb.append('  deps = [":androidx_test_runner_java"]\n')
+                sb.append('  deps += [":androidx_test_runner_java"]\n')
                 break
             case 'androidx_mediarouter_mediarouter':
                 sb.append('  # https://crbug.com/1000382\n')
diff --git a/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.cc b/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.cc
index 1d8035b..cbc5a25 100644
--- a/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.cc
+++ b/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.cc
@@ -143,6 +143,10 @@
                          TRACE_EVENT_FLAG_FLOW_OUT, "metadata",
                          metadata->ToString());
 
+  if (last_delegated_ink_metadata_timestamp_ == metadata->timestamp())
+    return;
+
+  last_delegated_ink_metadata_timestamp_ = metadata->timestamp();
   Page* page = local_frame_->GetPage();
   page->GetChromeClient().SetDelegatedInkMetadata(local_frame_,
                                                   std::move(metadata));
diff --git a/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.h b/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.h
index f4ab09c..6c812f6 100644
--- a/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.h
+++ b/third_party/blink/renderer/modules/delegated_ink/delegated_ink_trail_presenter.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_DELEGATED_INK_DELEGATED_INK_TRAIL_PRESENTER_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_DELEGATED_INK_DELEGATED_INK_TRAIL_PRESENTER_H_
 
+#include "base/time/time.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
@@ -45,6 +46,7 @@
   Member<Element> presentation_area_;
   Member<LocalFrame> local_frame_;
   uint32_t expected_improvement_;
+  base::TimeTicks last_delegated_ink_metadata_timestamp_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track.cc b/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track.cc
index 4f0edb2..5fb6a90c 100644
--- a/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track.cc
+++ b/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track.cc
@@ -183,34 +183,54 @@
     return promise;
   }
 
+  MediaStreamComponent* const component = Component();
+  DCHECK(component);
+
+  MediaStreamSource* const source = component->Source();
+  DCHECK(component->Source());
   // We don't currently instantiate BrowserCaptureMediaStreamTrack for audio
   // tracks. If we do in the future, we'll have to raise an exception if
   // cropTo() is called on a non-video track.
-  DCHECK(Component());
-  DCHECK(Component()->Source());
-  MediaStreamSource* const source = Component()->Source();
   DCHECK_EQ(source->GetType(), MediaStreamSource::kTypeVideo);
+
   MediaStreamVideoSource* const native_source =
       MediaStreamVideoSource::GetVideoSource(source);
-  DCHECK(native_source);
+  MediaStreamTrackPlatform* const native_track =
+      MediaStreamTrackPlatform::GetTrack(WebMediaStreamTrack(component));
+  if (!native_source || !native_track) {
+    // TODO(crbug.com/1266378): Use dedicate UMA values.
+    RecordUma(CropToResult::kRejectedWithErrorGeneric);
+    resolver->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kUnknownError, "Native/platform track missing."));
+    return promise;
+  }
 
   // TODO(crbug.com/1332628): Instead of using GetNextCropVersion(), move the
   // ownership of the Promises from this->pending_promises_ into native_source.
-  const absl::optional<uint32_t> crop_version =
+  const absl::optional<uint32_t> optional_crop_version =
       native_source->GetNextCropVersion();
-  if (!crop_version.has_value()) {
+  if (!optional_crop_version.has_value()) {
     resolver->Reject(MakeGarbageCollected<DOMException>(
         DOMExceptionCode::kOperationError,
         "Can't change crop-target while clones exist."));
     return promise;
   }
+  const uint32_t crop_version = optional_crop_version.value();
 
-  pending_promises_.Set(crop_version.value(), resolver);
+  pending_promises_.Set(crop_version,
+                        MakeGarbageCollected<CropPromiseInfo>(resolver));
+
+  // Register for a one-off notification when the first frame cropped
+  // to the new crop-target is observed.
+  native_track->AddCropVersionCallback(
+      crop_version,
+      WTF::Bind(&BrowserCaptureMediaStreamTrack::OnCropVersionObserved,
+                WrapWeakPersistent(this), crop_version));
 
   native_source->Crop(
-      crop_id_token.value(), crop_version.value(),
-      WTF::Bind(&BrowserCaptureMediaStreamTrack::ResolveCropPromise,
-                WrapPersistent(this), crop_version.value()));
+      crop_id_token.value(), crop_version,
+      WTF::Bind(&BrowserCaptureMediaStreamTrack::OnResultFromBrowserProcess,
+                WrapWeakPersistent(this), crop_version));
 
   return promise;
 #endif
@@ -232,15 +252,74 @@
 }
 
 #if !BUILDFLAG(IS_ANDROID)
-void BrowserCaptureMediaStreamTrack::ResolveCropPromise(
+void BrowserCaptureMediaStreamTrack::OnResultFromBrowserProcess(
     uint32_t crop_version,
     media::mojom::CropRequestResult result) {
-  const auto promise_it = pending_promises_.find(crop_version);
-  if (promise_it == pending_promises_.end()) {
+  DCHECK(IsMainThread());
+  DCHECK_GT(crop_version, 0u);
+
+  const auto iter = pending_promises_.find(crop_version);
+  if (iter == pending_promises_.end()) {
     return;
   }
-  ScriptPromiseResolver* const resolver = promise_it->value;
-  pending_promises_.erase(promise_it);
+  CropPromiseInfo* const info = iter->value;
+
+  DCHECK(!info->crop_result.has_value()) << "Invoked twice.";
+  info->crop_result = result;
+
+  MaybeFinalizeCropPromise(iter);
+}
+
+void BrowserCaptureMediaStreamTrack::OnCropVersionObserved(
+    uint32_t crop_version) {
+  DCHECK(IsMainThread());
+  DCHECK_GT(crop_version, 0u);
+
+  const auto iter = pending_promises_.find(crop_version);
+  if (iter == pending_promises_.end()) {
+    return;
+  }
+  CropPromiseInfo* const info = iter->value;
+
+  DCHECK(!info->crop_version_observed) << "Invoked twice.";
+  info->crop_version_observed = true;
+
+  MaybeFinalizeCropPromise(iter);
+}
+
+void BrowserCaptureMediaStreamTrack::MaybeFinalizeCropPromise(
+    BrowserCaptureMediaStreamTrack::PromiseMapIterator iter) {
+  DCHECK(IsMainThread());
+  DCHECK_NE(iter, pending_promises_.end());
+
+  CropPromiseInfo* const info = iter->value;
+
+  if (!info->crop_result.has_value()) {
+    return;
+  }
+
+  const media::mojom::CropRequestResult result = info->crop_result.value();
+
+  // Failure can be reported immediately, but success is only reported once
+  // the new crop-version is observed.
+  if (result == media::mojom::CropRequestResult::kSuccess &&
+      !info->crop_version_observed) {
+    return;
+  }
+
+  // When `result == kSuccess`, the callback will be removed by the track
+  // itself as it invokes it. For failure, we remove the callback immediately,
+  // since there's no need to wait.
+  if (result != media::mojom::CropRequestResult::kSuccess) {
+    MediaStreamTrackPlatform* const native_track =
+        MediaStreamTrackPlatform::GetTrack(WebMediaStreamTrack(Component()));
+    if (native_track) {
+      native_track->RemoveCropVersionCallback(iter->key);
+    }
+  }
+
+  ScriptPromiseResolver* const resolver = info->promise_resolver;
+  pending_promises_.erase(iter);
   ResolveCropPromiseHelper(resolver, result);
 }
 #endif  // !BUILDFLAG(IS_ANDROID)
diff --git a/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track.h b/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track.h
index 05021fa..452d86a 100644
--- a/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track.h
+++ b/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_BROWSER_CAPTURE_MEDIA_STREAM_TRACK_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_BROWSER_CAPTURE_MEDIA_STREAM_TRACK_H_
 
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/modules/mediastream/crop_target.h"
 #include "third_party/blink/renderer/modules/mediastream/focusable_media_stream_track.h"
@@ -31,8 +32,16 @@
                                  const String& descriptor_id,
                                  bool is_clone = false);
 
+  ~BrowserCaptureMediaStreamTrack() override = default;
+
 #if !BUILDFLAG(IS_ANDROID)
   void Trace(Visitor*) const override;
+
+  // Allows tests to invoke OnCropVersionObserved() directly, since triggering
+  // it via mocks would be prohibitively difficult.
+  void OnCropVersionObservedForTesting(uint32_t crop_version) {
+    OnCropVersionObserved(crop_version);
+  }
 #endif
 
   ScriptPromise cropTo(ScriptState*, CropTarget*, ExceptionState&);
@@ -41,9 +50,48 @@
 
  private:
 #if !BUILDFLAG(IS_ANDROID)
-  // Resolves the Promise associated with |crop_version|.
-  void ResolveCropPromise(uint32_t crop_version,
-                          media::mojom::CropRequestResult result);
+  struct CropPromiseInfo : GarbageCollected<CropPromiseInfo> {
+    explicit CropPromiseInfo(ScriptPromiseResolver* promise_resolver)
+        : promise_resolver(promise_resolver) {}
+
+    void Trace(Visitor* visitor) const { visitor->Trace(promise_resolver); }
+
+    const Member<ScriptPromiseResolver> promise_resolver;
+    absl::optional<media::mojom::CropRequestResult> crop_result;
+    bool crop_version_observed = false;
+  };
+
+  using CropVersionToPromiseInfoMap =
+      HeapHashMap<uint32_t,
+                  Member<BrowserCaptureMediaStreamTrack::CropPromiseInfo>>;
+  using PromiseMapIterator = CropVersionToPromiseInfoMap::iterator;
+
+  // Each cropTo() call is associated with a unique |crop_version| which
+  // identifies this specific cropTo() invocation. When the browser process
+  // responds with the result of the cropTo() invocation, it triggers
+  // a call to OnResultFromBrowserProcess() with that |crop_version|.
+  void OnResultFromBrowserProcess(uint32_t crop_version,
+                                  media::mojom::CropRequestResult result);
+
+  // OnCropVersionObserved() is posted as a callback, bound to a unique
+  // |crop_version|. This callback be invoked when the first frame is observed
+  // which is associated with that |crop_version|.
+  // TODO(crbug.com/1266378): The Promise should also be resolved if a
+  // a barrier event is observed. (That is, although no frame is delivered,
+  // there is a guarantee that all future frames will be of this version
+  // or later. This would happen if cropping a muted track, for instance.)
+  void OnCropVersionObserved(uint32_t crop_version);
+
+  // The Promise that cropTo() issued is resolved when both conditions
+  // are fulfulled:
+  // 1. OnResultFromBrowserProcess(kSuccess) called.
+  // 2. OnCropVersionObserved() called for the associated |crop_version|.
+  //
+  // The order of fulfillment does not matter.
+  //
+  // The Promise is rejected if OnResultFromBrowserProcess() is called with
+  // an error value.
+  void MaybeFinalizeCropPromise(PromiseMapIterator iter);
 
   // Each time cropTo() is called on a given track, its crop version increments.
   // Associate each Promise with its crop version, so that Viz can easily stamp
@@ -54,7 +102,7 @@
   //
   // Note that frames before the first call to cropTo() will be associated
   // with a version of 0, both here and in Viz.
-  HeapHashMap<uint32_t, Member<ScriptPromiseResolver>> pending_promises_;
+  HeapHashMap<uint32_t, Member<CropPromiseInfo>> pending_promises_;
 #endif  // !BUILDFLAG(IS_ANDROID)
 };
 
diff --git a/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track_test.cc b/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track_test.cc
index 1d49522..abb11de 100644
--- a/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/browser_capture_media_stream_track_test.cc
@@ -8,16 +8,22 @@
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/web/web_heap.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
 #include "third_party/blink/renderer/modules/mediastream/crop_target.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
 #include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h"
 #include "third_party/blink/renderer/platform/region_capture_crop_id.h"
+#include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
 
 namespace blink {
 
 namespace {
 
 using ::testing::_;
+using ::testing::Args;
+using ::testing::Invoke;
+using ::testing::Mock;
 using ::testing::Return;
 
 std::unique_ptr<MockMediaStreamVideoSource> MakeMockMediaStreamVideoSource() {
@@ -30,12 +36,18 @@
 BrowserCaptureMediaStreamTrack* MakeTrack(
     V8TestingScope& v8_scope,
     std::unique_ptr<MockMediaStreamVideoSource> media_stream_video_source) {
+  auto media_stream_video_track = std::make_unique<MediaStreamVideoTrack>(
+      media_stream_video_source.get(),
+      WebPlatformMediaStreamSource::ConstraintsOnceCallback(),
+      /*enabled=*/true);
+
   MediaStreamSource* const source = MakeGarbageCollected<MediaStreamSource>(
       "id", MediaStreamSource::StreamType::kTypeVideo, "name",
       /*remote=*/false, std::move(media_stream_video_source));
 
   MediaStreamComponent* const component =
-      MakeGarbageCollected<MediaStreamComponent>(source);
+      MakeGarbageCollected<MediaStreamComponent>(
+          "component_id", source, std::move(media_stream_video_track));
 
   return MakeGarbageCollected<BrowserCaptureMediaStreamTrack>(
       v8_scope.GetExecutionContext(), component, /*callback=*/base::DoNothing(),
@@ -46,13 +58,16 @@
 
 class BrowserCaptureMediaStreamTrackTest : public testing::Test {
  public:
-  ~BrowserCaptureMediaStreamTrackTest() override {
-    WebHeap::CollectAllGarbageForTesting();
-  }
+  ~BrowserCaptureMediaStreamTrackTest() override = default;
+
+  void TearDown() override { WebHeap::CollectAllGarbageForTesting(); }
+
+ protected:
+  ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_;
 };
 
 #if !BUILDFLAG(IS_ANDROID)
-TEST_F(BrowserCaptureMediaStreamTrackTest, CropToOnValidId) {
+TEST_F(BrowserCaptureMediaStreamTrackTest, CropToOnValidIdResultFirst) {
   V8TestingScope v8_scope;
 
   const base::GUID valid_id = base::GUID::GenerateRandomV4();
@@ -65,7 +80,11 @@
       .WillOnce(Return(absl::optional<uint32_t>(1)));
 
   EXPECT_CALL(*media_stream_video_source, Crop(GUIDToToken(valid_id), _, _))
-      .Times(1);
+      .Times(1)
+      .WillOnce(::testing::WithArg<2>(::testing::Invoke(
+          [](base::OnceCallback<void(media::mojom::CropRequestResult)> cb) {
+            std::move(cb).Run(media::mojom::CropRequestResult::kSuccess);
+          })));
 
   BrowserCaptureMediaStreamTrack* const track =
       MakeTrack(v8_scope, std::move(media_stream_video_source));
@@ -75,6 +94,78 @@
                     MakeGarbageCollected<CropTarget>(
                         WTF::String(valid_id.AsLowercaseString())),
                     v8_scope.GetExceptionState());
+
+  track->OnCropVersionObservedForTesting(/*crop_version=*/1);
+
+  ScriptPromiseTester script_promise_tester(v8_scope.GetScriptState(), promise);
+  script_promise_tester.WaitUntilSettled();
+  EXPECT_TRUE(script_promise_tester.IsFulfilled());
+}
+
+TEST_F(BrowserCaptureMediaStreamTrackTest,
+       CropToRejectsIfResultFromBrowserProcessIsNotSuccess) {
+  V8TestingScope v8_scope;
+
+  const base::GUID valid_id = base::GUID::GenerateRandomV4();
+
+  std::unique_ptr<MockMediaStreamVideoSource> media_stream_video_source =
+      MakeMockMediaStreamVideoSource();
+
+  EXPECT_CALL(*media_stream_video_source, GetNextCropVersion)
+      .Times(1)
+      .WillOnce(Return(absl::optional<uint32_t>(1)));
+
+  EXPECT_CALL(*media_stream_video_source, Crop(GUIDToToken(valid_id), _, _))
+      .Times(1)
+      .WillOnce(::testing::WithArg<2>(::testing::Invoke(
+          [](base::OnceCallback<void(media::mojom::CropRequestResult)> cb) {
+            std::move(cb).Run(media::mojom::CropRequestResult::kErrorGeneric);
+          })));
+
+  BrowserCaptureMediaStreamTrack* const track =
+      MakeTrack(v8_scope, std::move(media_stream_video_source));
+
+  const ScriptPromise promise =
+      track->cropTo(v8_scope.GetScriptState(),
+                    MakeGarbageCollected<CropTarget>(
+                        WTF::String(valid_id.AsLowercaseString())),
+                    v8_scope.GetExceptionState());
+
+  track->OnCropVersionObservedForTesting(/*crop_version=*/1);
+
+  ScriptPromiseTester script_promise_tester(v8_scope.GetScriptState(), promise);
+  script_promise_tester.WaitUntilSettled();
+  EXPECT_TRUE(script_promise_tester.IsRejected());
+}
+
+TEST_F(BrowserCaptureMediaStreamTrackTest,
+       CropToRejectsIfSourceReturnsNulloptForNextCropVersion) {
+  V8TestingScope v8_scope;
+
+  const base::GUID valid_id = base::GUID::GenerateRandomV4();
+
+  std::unique_ptr<MockMediaStreamVideoSource> media_stream_video_source =
+      MakeMockMediaStreamVideoSource();
+
+  EXPECT_CALL(*media_stream_video_source, GetNextCropVersion)
+      .Times(1)
+      .WillOnce(Return(absl::nullopt));
+
+  EXPECT_CALL(*media_stream_video_source, Crop(GUIDToToken(valid_id), _, _))
+      .Times(0);
+
+  BrowserCaptureMediaStreamTrack* const track =
+      MakeTrack(v8_scope, std::move(media_stream_video_source));
+
+  const ScriptPromise promise =
+      track->cropTo(v8_scope.GetScriptState(),
+                    MakeGarbageCollected<CropTarget>(
+                        WTF::String(valid_id.AsLowercaseString())),
+                    v8_scope.GetExceptionState());
+
+  ScriptPromiseTester script_promise_tester(v8_scope.GetScriptState(), promise);
+  script_promise_tester.WaitUntilSettled();
+  EXPECT_TRUE(script_promise_tester.IsRejected());
 }
 
 #else
@@ -97,7 +188,10 @@
                     MakeGarbageCollected<CropTarget>(
                         WTF::String(valid_id.AsLowercaseString())),
                     v8_scope.GetExceptionState());
-  EXPECT_EQ(promise.V8Promise()->State(), v8::Promise::kRejected);
+
+  ScriptPromiseTester script_promise_tester(v8_scope.GetScriptState(), promise);
+  script_promise_tester.WaitUntilSettled();
+  EXPECT_TRUE(script_promise_tester.IsRejected());
 }
 #endif
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
index a48c2c6..61e5294e 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
@@ -124,6 +124,10 @@
 
   void SetIsRefreshingForMinFrameRate(bool is_refreshing_for_min_frame_rate);
 
+  void AddCropVersionCallback(uint32_t crop_version,
+                              base::OnceClosure callback);
+  void RemoveCropVersionCallback(uint32_t crop_version);
+
  private:
   friend class WTF::ThreadSafeRefCounted<FrameDeliverer>;
   virtual ~FrameDeliverer();
@@ -144,6 +148,12 @@
   void SetIsRefreshingForMinFrameRateOnIO(
       bool is_refreshing_for_min_frame_rate);
 
+  void AddCropVersionCallbackOnIO(uint32_t crop_version,
+                                  WTF::CrossThreadOnceClosure callback);
+  void RemoveCropVersionCallbackOnIO(uint32_t crop_version);
+
+  void MaybeInvokeNewCropVersionCallbacksOnIO(uint32_t crop_version);
+
   // Returns a black frame where the size and time stamp is set to the same as
   // as in |reference_frame|.
   scoped_refptr<media::VideoFrame> GetBlackFrame(
@@ -165,6 +175,13 @@
       std::pair<VideoSinkId, VideoCaptureDeliverFrameInternalCallback>;
   Vector<VideoIdCallbackPair> callbacks_;
   HashMap<VideoSinkId, EncodedVideoFrameInternalCallback> encoded_callbacks_;
+
+  // Callbacks that will be invoked a single time when a crop-version
+  // is observed that is at least equal to the key.
+  // The map itself (crop_version_callbacks_) is bound to the IO thread.
+  // The callbacks are bound to their respective threads (BindPostTask).
+  HashMap<uint32_t, WTF::CrossThreadOnceClosure> crop_version_callbacks_;
+
   bool await_next_key_frame_;
 
   // This should only be accessed on the IO thread.
@@ -312,18 +329,76 @@
                           is_refreshing_for_min_frame_rate));
 }
 
+void MediaStreamVideoTrack::FrameDeliverer::AddCropVersionCallback(
+    uint32_t crop_version,
+    base::OnceClosure callback) {
+  DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
+
+  PostCrossThreadTask(
+      *io_task_runner_, FROM_HERE,
+      CrossThreadBindOnce(&FrameDeliverer::AddCropVersionCallbackOnIO,
+                          WrapRefCounted(this), crop_version,
+                          CrossThreadBindOnce(std::move(callback))));
+}
+
+void MediaStreamVideoTrack::FrameDeliverer::RemoveCropVersionCallback(
+    uint32_t crop_version) {
+  DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
+
+  PostCrossThreadTask(
+      *io_task_runner_, FROM_HERE,
+      CrossThreadBindOnce(&FrameDeliverer::RemoveCropVersionCallbackOnIO,
+                          WrapRefCounted(this), crop_version));
+}
+
 void MediaStreamVideoTrack::FrameDeliverer::SetIsRefreshingForMinFrameRateOnIO(
     bool is_refreshing_for_min_frame_rate) {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
   is_refreshing_for_min_frame_rate_ = is_refreshing_for_min_frame_rate;
 }
 
+void MediaStreamVideoTrack::FrameDeliverer::AddCropVersionCallbackOnIO(
+    uint32_t crop_version,
+    WTF::CrossThreadOnceClosure callback) {
+  DCHECK(io_task_runner_->BelongsToCurrentThread());
+  DCHECK(!base::Contains(crop_version_callbacks_, crop_version));
+
+  crop_version_callbacks_.Set(crop_version, std::move(callback));
+}
+
+void MediaStreamVideoTrack::FrameDeliverer::RemoveCropVersionCallbackOnIO(
+    uint32_t crop_version) {
+  DCHECK(io_task_runner_->BelongsToCurrentThread());
+
+  // Note: Might or might not be here, depending on whether a later crop
+  // version has already been observed or not.
+  crop_version_callbacks_.erase(crop_version);
+}
+
+void MediaStreamVideoTrack::FrameDeliverer::
+    MaybeInvokeNewCropVersionCallbacksOnIO(uint32_t crop_version) {
+  DCHECK(io_task_runner_->BelongsToCurrentThread());
+
+  Vector<uint32_t> to_be_removed_keys;
+  for (auto& iter : crop_version_callbacks_) {
+    if (iter.key > crop_version) {
+      continue;
+    }
+    std::move(iter.value).Run();
+    to_be_removed_keys.push_back(iter.key);
+  }
+  crop_version_callbacks_.RemoveAll(to_be_removed_keys);
+}
+
 void MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnIO(
     scoped_refptr<media::VideoFrame> frame,
     std::vector<scoped_refptr<media::VideoFrame>> scaled_video_frames,
     base::TimeTicks estimated_capture_time) {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
-  if (!enabled_ && emit_frame_drop_events_) {
+
+  const uint32_t crop_version = frame->metadata().crop_version;
+
+  if (!enabled_ && main_render_task_runner_ && emit_frame_drop_events_) {
     emit_frame_drop_events_ = false;
 
     // TODO(crbug.com/964947): A weak ptr instance of MediaStreamVideoTrack is
@@ -359,6 +434,8 @@
         CrossThreadBindOnce(&MediaStreamVideoTrack::ResetRefreshTimer,
                             media_stream_video_track_));
   }
+
+  MaybeInvokeNewCropVersionCallbacksOnIO(crop_version);
 }
 
 void MediaStreamVideoTrack::FrameDeliverer::DeliverEncodedVideoFrameOnIO(
@@ -743,6 +820,21 @@
   return capture_handle;
 }
 
+void MediaStreamVideoTrack::AddCropVersionCallback(uint32_t crop_version,
+                                                   base::OnceClosure callback) {
+  DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
+
+  frame_deliverer_->AddCropVersionCallback(
+      crop_version, base::BindPostTask(base::ThreadTaskRunnerHandle::Get(),
+                                       std::move(callback)));
+}
+
+void MediaStreamVideoTrack::RemoveCropVersionCallback(uint32_t crop_version) {
+  DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
+
+  frame_deliverer_->RemoveCropVersionCallback(crop_version);
+}
+
 void MediaStreamVideoTrack::OnReadyStateChanged(
     WebMediaStreamSource::ReadyState state) {
   DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_track.h b/third_party/blink/renderer/modules/mediastream/media_stream_video_track.h
index 44b96b4..414b90f 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_track.h
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_track.h
@@ -88,6 +88,9 @@
   void StopAndNotify(base::OnceClosure callback) override;
   void GetSettings(MediaStreamTrackPlatform::Settings& settings) override;
   MediaStreamTrackPlatform::CaptureHandle GetCaptureHandle() override;
+  void AddCropVersionCallback(uint32_t crop_version,
+                              base::OnceClosure callback) override;
+  void RemoveCropVersionCallback(uint32_t crop_version) override;
 
   // Add |sink| to receive state changes on the main render thread and video
   // frames in the |callback| method on the IO-thread.
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.cc b/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.cc
index b8987384..f799baa 100644
--- a/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.cc
+++ b/third_party/blink/renderer/modules/webgpu/dawn_enum_conversions.cc
@@ -445,8 +445,8 @@
       return WGPUFeatureName_TimestampQuery;
     case V8GPUFeatureName::Enum::kShaderFloat16:
       return WGPUFeatureName_DawnShaderFloat16;
-    case V8GPUFeatureName::Enum::kDepthClamping:
-      return WGPUFeatureName_DepthClamping;
+    case V8GPUFeatureName::Enum::kDepthClipControl:
+      return WGPUFeatureName_DepthClipControl;
     case V8GPUFeatureName::Enum::kDepth32FloatStencil8:
       return WGPUFeatureName_Depth32FloatStencil8;
     case V8GPUFeatureName::Enum::kIndirectFirstInstance:
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc b/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc
index d0eda40..f2f6de1 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc
@@ -59,8 +59,8 @@
       case WGPUFeatureName_IndirectFirstInstance:
         features->AddFeatureName("indirect-first-instance");
         break;
-      case WGPUFeatureName_DepthClamping:
-        features->AddFeatureName("depth-clamping");
+      case WGPUFeatureName_DepthClipControl:
+        features->AddFeatureName("depth-clip-control");
         break;
       case WGPUFeatureName_DawnShaderFloat16:
         features->AddFeatureName("shader-float16");
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_primitive_state.idl b/third_party/blink/renderer/modules/webgpu/gpu_primitive_state.idl
index 94f3ed2..0ea11b4 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_primitive_state.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_primitive_state.idl
@@ -9,7 +9,7 @@
   GPUIndexFormat stripIndexFormat;
   GPUFrontFace frontFace = "ccw";
   GPUCullMode cullMode = "none";
-  boolean? clampDepth;
+  boolean? unclippedDepth;
 };
 
 enum GPUIndexFormat {
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc
index b192b3bd..0adc01b3 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc
@@ -120,13 +120,14 @@
   dawn_state->dawn_desc.frontFace = AsDawnEnum(webgpu_desc->frontFace());
   dawn_state->dawn_desc.cullMode = AsDawnEnum(webgpu_desc->cullMode());
 
-  if (webgpu_desc->hasClampDepth()) {
-    auto* clamp_state = &dawn_state->depth_clamping_state;
-    clamp_state->chain.sType = WGPUSType_PrimitiveDepthClampingState;
-    clamp_state->clampDepth = webgpu_desc->clampDepth().has_value() &&
-                              webgpu_desc->clampDepth().value();
+  if (webgpu_desc->hasUnclippedDepth()) {
+    auto* depth_clip_control = &dawn_state->depth_clip_control;
+    depth_clip_control->chain.sType = WGPUSType_PrimitiveDepthClipControl;
+    depth_clip_control->unclippedDepth =
+        webgpu_desc->unclippedDepth().has_value() &&
+        webgpu_desc->unclippedDepth().value();
     dawn_state->dawn_desc.nextInChain =
-        reinterpret_cast<WGPUChainedStruct*>(clamp_state);
+        reinterpret_cast<WGPUChainedStruct*>(depth_clip_control);
   }
 }
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.h b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.h
index 77810221..c644cf2 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.h
@@ -44,7 +44,7 @@
   OwnedPrimitiveState& operator=(OwnedPrimitiveState&& desc) = delete;
 
   WGPUPrimitiveState dawn_desc = {};
-  WGPUPrimitiveDepthClampingState depth_clamping_state = {};
+  WGPUPrimitiveDepthClipControl depth_clip_control = {};
 };
 
 struct OwnedRenderPipelineDescriptor {
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_supported_features.idl b/third_party/blink/renderer/modules/webgpu/gpu_supported_features.idl
index 90ec6fe8e..2679c73 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_supported_features.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_supported_features.idl
@@ -11,7 +11,7 @@
     "texture-compression-astc",
     "timestamp-query",
     "shader-float16",
-    "depth-clamping",
+    "depth-clip-control",
     "depth32float-stencil8",
     "indirect-first-instance",
     "chromium-experimental-dp4a",
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.cc b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.cc
index fe6f902e..8b6d4c8 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.cc
@@ -30,6 +30,7 @@
   X(maxVertexAttributes)                       \
   X(maxVertexBufferArrayStride)                \
   X(maxInterStageShaderComponents)             \
+  X(maxColorAttachments)                       \
   X(maxComputeWorkgroupStorageSize)            \
   X(maxComputeInvocationsPerWorkgroup)         \
   X(maxComputeWorkgroupSizeX)                  \
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.h b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.h
index c38550d..b85e795 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.h
@@ -49,6 +49,7 @@
   unsigned maxVertexAttributes() const;
   unsigned maxVertexBufferArrayStride() const;
   unsigned maxInterStageShaderComponents() const;
+  unsigned maxColorAttachments() const;
   unsigned maxComputeWorkgroupStorageSize() const;
   unsigned maxComputeInvocationsPerWorkgroup() const;
   unsigned maxComputeWorkgroupSizeX() const;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.idl b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.idl
index ff64b9a..39d6d6c 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_supported_limits.idl
@@ -28,6 +28,7 @@
     readonly attribute unsigned long maxVertexAttributes;
     readonly attribute unsigned long maxVertexBufferArrayStride;
     readonly attribute unsigned long maxInterStageShaderComponents;
+    readonly attribute unsigned long maxColorAttachments;
     readonly attribute unsigned long maxComputeWorkgroupStorageSize;
     readonly attribute unsigned long maxComputeInvocationsPerWorkgroup;
     readonly attribute unsigned long maxComputeWorkgroupSizeX;
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_track_platform.h b/third_party/blink/renderer/platform/mediastream/media_stream_track_platform.h
index cc9a4ec..36d8156 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_track_platform.h
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_track_platform.h
@@ -84,6 +84,14 @@
   virtual void GetSettings(Settings& settings) {}
   virtual CaptureHandle GetCaptureHandle();
 
+  // Adds a one off callback that will be invoked when observing the first frame
+  // where |metadata.crop_version >= crop_version|.
+  virtual void AddCropVersionCallback(uint32_t crop_version,
+                                      base::OnceClosure callback) {}
+
+  // Removes the callback that was associated with this |crop_version|, if any.
+  virtual void RemoveCropVersionCallback(uint32_t crop_version) {}
+
   bool is_local_track() const { return is_local_track_; }
 
   enum class StreamType { kAudio, kVideo };
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 6ad47e4..93fab66c 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1687,6 +1687,7 @@
 crbug.com/1121942 virtual/layout_ng_printing/printing/named-page-breaks.html [ Failure ]
 crbug.com/1121942 [ Linux ] virtual/layout_ng_printing/printing/overflow-auto.html [ Crash ]
 crbug.com/1121942 [ Mac11 ] virtual/layout_ng_printing/printing/overflow-auto.html [ Crash ]
+crbug.com/1121942 [ Mac12 ] virtual/layout_ng_printing/printing/overflow-auto.html [ Crash ]
 crbug.com/1121942 [ Win ] virtual/layout_ng_printing/printing/overflow-auto.html [ Crash ]
 crbug.com/1121942 virtual/layout_ng_printing/printing/page-break-avoid.html [ Failure ]
 crbug.com/1121942 virtual/layout_ng_printing/printing/page-orientation-propagated.html [ Failure ]
@@ -4237,9 +4238,6 @@
 crbug.com/709227 external/wpt/html/canvas/offscreen/path-objects/2d.path.stroke.prune.curve.worker.html [ Failure ]
 crbug.com/709227 external/wpt/html/canvas/offscreen/path-objects/2d.path.stroke.prune.line.worker.html [ Failure ]
 crbug.com/709227 external/wpt/html/canvas/offscreen/path-objects/2d.path.stroke.prune.rect.worker.html [ Failure ]
-crbug.com/709227 external/wpt/html/canvas/offscreen/pixel-manipulation/2d.imageData.create2.nonfinite.worker.html [ Failure ]
-crbug.com/709227 external/wpt/html/canvas/offscreen/pixel-manipulation/2d.imageData.get.nonfinite.worker.html [ Failure ]
-crbug.com/709227 external/wpt/html/canvas/offscreen/pixel-manipulation/2d.imageData.put.nonfinite.worker.html [ Failure ]
 
 # ====== Tests from enabling .any.js/.worker.js tests end here ========
 
diff --git a/third_party/blink/web_tests/external/Version b/third_party/blink/web_tests/external/Version
index 3d60afd3..04ddc420 100644
--- a/third_party/blink/web_tests/external/Version
+++ b/third_party/blink/web_tests/external/Version
@@ -1 +1 @@
-Version: 2a9034c89e115e5bdb8b6d77bf2ca5551acf9873
+Version: a8393d01f484ff9446568c9d25d986221107c9ec
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index d3de8a4..61cb587f 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -318807,7 +318807,7 @@
      []
     ],
     "META.yml": [
-     "b7e2497681e98960fd00d70ced82aa9e3a48d144",
+     "e11810cc10fa16774924fe8a8080ab5aae161ac7",
      []
     ],
     "OWNERS": [
diff --git a/third_party/blink/web_tests/external/wpt/attribution-reporting/resources/reports.py b/third_party/blink/web_tests/external/wpt/attribution-reporting/resources/reports.py
index 49305354..4af2b6a 100644
--- a/third_party/blink/web_tests/external/wpt/attribution-reporting/resources/reports.py
+++ b/third_party/blink/web_tests/external/wpt/attribution-reporting/resources/reports.py
@@ -16,6 +16,22 @@
 CLEAR_STASH = isomorphic_encode("clear_stash")
 
 
+def decode_headers(headers: dict) -> dict:
+  """Decodes the headers from wptserve.
+
+  wptserve headers are encoded like
+  {
+    encoded(key): [encoded(value1), encoded(value2),...]
+  }
+  This method decodes the above using the wptserve.utils.isomorphic_decode
+  method
+  """
+  return {
+      isomorphic_decode(key): [isomorphic_decode(el) for el in value
+                              ] for key, value in headers.items()
+  }
+
+
 def handle_post_report(request: Request, headers: List[Header]) -> Response:
   """Handles POST request for reports.
 
@@ -28,7 +44,11 @@
         "code": 200,
         "message": "Stash successfully cleared.",
     })
-  store_report(request.server.stash, request.body.decode("utf-8"))
+  store_report(
+      request.server.stash, {
+          "body": request.body.decode("utf-8"),
+          "headers": decode_headers(request.headers)
+      })
   return (201, "OK"), headers, json.dumps({
       "code": 201,
       "message": "Report successfully stored."
diff --git a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/META.yml b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/META.yml
index b7e2497..e11810c 100644
--- a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/META.yml
+++ b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/META.yml
@@ -1,4 +1,4 @@
-spec: https://wicg.github.io/largest-contentful-paint/
+spec: https://w3c.github.io/largest-contentful-paint/
 suggested_reviewers:
         - npm1
         - yoavweiss
diff --git a/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/helpers.js b/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/helpers.js
index ce96c6a..87cd58b 100644
--- a/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/helpers.js
+++ b/third_party/blink/web_tests/wpt_internal/attribution-reporting/resources/helpers.js
@@ -63,3 +63,11 @@
     pollAttributionReports(eventLevelReportsUrl, interval);
 const pollAggregatableReports = interval =>
     pollAttributionReports(aggregatableReportsUrl, interval);
+
+const validateReportHeaders = headers => {
+  assert_array_equals(headers['content-type'], ['application/json']);
+  assert_array_equals(headers['cache-control'], ['no-cache']);
+  assert_own_property(headers, 'user-agent');
+  assert_not_own_property(headers, 'cookie');
+  assert_not_own_property(headers, 'referer');
+}
diff --git a/third_party/blink/web_tests/wpt_internal/attribution-reporting/simple-aggregatable-report-test.sub.https.html b/third_party/blink/web_tests/wpt_internal/attribution-reporting/simple-aggregatable-report-test.sub.https.html
index af4cd12..358d321 100644
--- a/third_party/blink/web_tests/wpt_internal/attribution-reporting/simple-aggregatable-report-test.sub.https.html
+++ b/third_party/blink/web_tests/wpt_internal/attribution-reporting/simple-aggregatable-report-test.sub.https.html
@@ -38,7 +38,8 @@
   registerAttributionSrc('Attribution-Reporting-Register-Trigger', trigger);
   const payload = await pollAggregatableReports(interval);
   assert_equals(payload.reports.length, 1);
-  const report = JSON.parse(payload.reports[0]);
+  const report = JSON.parse(payload.reports[0].body);
+  const headers = payload.reports[0].headers;
   assert_own_property(report, 'shared_info');
   const shared_info = JSON.parse(report.shared_info);
   assert_own_property(shared_info, 'api');
@@ -57,5 +58,6 @@
   assert_own_property(aggregation_service_payload, 'payload');
   assert_own_property(aggregation_service_payload, 'key_id');
   assert_not_own_property(aggregation_service_payload, 'debug_cleartext_payload');
+  validateReportHeaders(headers);
 }, 'Ensure aggregatable attribution report is received.');
 </script>
diff --git a/third_party/blink/web_tests/wpt_internal/attribution-reporting/simple-event-level-report-test.sub.https.html b/third_party/blink/web_tests/wpt_internal/attribution-reporting/simple-event-level-report-test.sub.https.html
index cb9f5485..60052daa 100644
--- a/third_party/blink/web_tests/wpt_internal/attribution-reporting/simple-event-level-report-test.sub.https.html
+++ b/third_party/blink/web_tests/wpt_internal/attribution-reporting/simple-event-level-report-test.sub.https.html
@@ -20,7 +20,8 @@
       'Attribution-Reporting-Register-Trigger', trigger);
   const payload = await pollEventLevelReports(interval);
   assert_equals(payload.reports.length, 1);
-  const report = JSON.parse(payload.reports[0]);
+  const report = JSON.parse(payload.reports[0].body);
+  const headers = payload.reports[0].headers;
   // The trigger data is sanitized to "0" because event sources are limited to 1
   // bit.
   assert_equals(report.trigger_data, '0');
@@ -33,5 +34,6 @@
   assert_equals(typeof report.report_id, 'string');
   assert_not_own_property(report, 'source_debug_key');
   assert_not_own_property(report, 'trigger_debug_key');
+  validateReportHeaders(headers);
 }, 'Ensure attribution report is received.');
 </script>
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader_test.cc b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader_test.cc
index 74a21be..8b7e3ff1 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader_test.cc
@@ -460,19 +460,16 @@
   test_mach_o_image_annotations_reader.Run();
 }
 
-#if defined(ADDRESS_SANITIZER)
-// https://crbug.com/844396
-#define MAYBE_CrashModuleInitialization DISABLED_CrashModuleInitialization
-#else
-#define MAYBE_CrashModuleInitialization CrashModuleInitialization
-#endif
-TEST(MachOImageAnnotationsReader, MAYBE_CrashModuleInitialization) {
+// Flaky on ASAN https://crbug.com/844396
+// Flaky in general https://crbug.com/1334418
+TEST(MachOImageAnnotationsReader, DISABLED_CrashModuleInitialization) {
   TestMachOImageAnnotationsReader test_mach_o_image_annotations_reader(
       TestMachOImageAnnotationsReader::kCrashModuleInitialization);
   test_mach_o_image_annotations_reader.Run();
 }
 
-TEST(MachOImageAnnotationsReader, CrashDyld) {
+// Flaky in general https://crbug.com/1334418
+TEST(MachOImageAnnotationsReader, DISABLED_CrashDyld) {
   TestMachOImageAnnotationsReader test_mach_o_image_annotations_reader(
       TestMachOImageAnnotationsReader::kCrashDyld);
   test_mach_o_image_annotations_reader.Run();
diff --git a/third_party/wayland-protocols/README.chromium b/third_party/wayland-protocols/README.chromium
index 95b22036..67670f6b 100644
--- a/third_party/wayland-protocols/README.chromium
+++ b/third_party/wayland-protocols/README.chromium
@@ -9,6 +9,8 @@
 wayland-protocols/src contains the official library of Wayland protocol
 extensions maintained by the developers of the Wayland project.
 
+unstable/ contains unofficial ChromeOS extensions to wayland.
+
 Repository:
 https://anongit.freedesktop.org/git/wayland/wayland-protocols.git.
 
diff --git a/tools/fuchsia/size_tests/fyi_sizes_warning.json b/tools/fuchsia/size_tests/fyi_sizes_warning.json
index a51f6a3f..ede2e1d 100644
--- a/tools/fuchsia/size_tests/fyi_sizes_warning.json
+++ b/tools/fuchsia/size_tests/fyi_sizes_warning.json
@@ -5,6 +5,6 @@
   ],
   "far_total_name" : "chrome_fuchsia",
   "size_limits" : {
-    "chrome_fuchsia_compressed": 41718752
+    "chrome_fuchsia_compressed": 41906064
   }
 }
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index c660588..f10b0dc 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -24230,6 +24230,12 @@
   <int value="1" label="New key accelerator is used"/>
 </enum>
 
+<enum name="DeprecateStylusFeaturesToastEvent">
+  <int value="0" label="Features not deprecated, toast not shown"/>
+  <int value="1" label="Features deprecated, toast shown (first time)"/>
+  <int value="2" label="Features deprecated, toast not shown (already shown)"/>
+</enum>
+
 <enum name="DeskCloseType">
   <int value="0" label="Combine desks."/>
   <int value="1" label="Close all windows"/>
@@ -56460,6 +56466,7 @@
   <int value="-1092211161" label="BluetoothWbsDogfood:disabled"/>
   <int value="-1089665395" label="HTMLParamElementUrlSupport:enabled"/>
   <int value="-1088804127" label="DuetTabStripIntegrationAndroid:disabled"/>
+  <int value="-1087409065" label="RoundedDisplay:enabled"/>
   <int value="-1086987072" label="NearbySharingSelfShareAutoAccept:enabled"/>
   <int value="-1086728979" label="kids-management-url-classification:enabled"/>
   <int value="-1086656172"
@@ -56703,6 +56710,7 @@
   <int value="-943304570" label="PaintHolding:enabled"/>
   <int value="-943223021"
       label="FeatureNotificationGuideSkipCheckForLowEngagedUsers:disabled"/>
+  <int value="-940390151" label="RoundedDisplay:disabled"/>
   <int value="-939676447" label="CrostiniResetLxdDb:enabled"/>
   <int value="-938178614" label="enable-suggestions-with-substring-match"/>
   <int value="-937430451" label="IntensiveWakeUpThrottling:disabled"/>
@@ -84665,6 +84673,12 @@
   <int value="2" label="Gesture Tap"/>
 </enum>
 
+<enum name="SearchBoxTextMatch">
+  <int value="0" label="No Match"/>
+  <int value="1" label="Prefix Match"/>
+  <int value="2" label="Substring Match"/>
+</enum>
+
 <enum name="SearchEngine">
   <obsolete>
     Deprecated 8/2013. No longer generated.
@@ -84808,6 +84822,26 @@
   <int value="2" label="Network error"/>
 </enum>
 
+<enum name="SecureChannelConnectionAttemptFailureReason">
+  <int value="0" label="Authentication error"/>
+  <int value="1" label="Could not generate advertisement"/>
+  <int value="2" label="GATT connection error"/>
+  <int value="3" label="Nearby Connections error"/>
+  <int value="4" label="Local device has invalid public key"/>
+  <int value="5" label="Local device has invalid psk"/>
+  <int value="6" label="Local device has invalid bluetooth address"/>
+  <int value="7" label="Remote device has invalid public key"/>
+  <int value="8" label="Remote device has invalid psk"/>
+  <int value="9" label="Remote device has invalid bluetooth address"/>
+  <int value="10" label="Timeout discovering remote device"/>
+  <int value="11" label="Bluetoth adapter disabled"/>
+  <int value="12" label="Bluetooth adapter not available"/>
+  <int value="13" label="Unsupported connection medium"/>
+  <int value="14" label="Missing nearby connector"/>
+  <int value="15"
+      label="Connection was intentionally cancelled due to a status change"/>
+</enum>
+
 <enum name="SecureChannelNearbyConnectionMedium">
   <int value="0" label="Connected via Bluetooth"/>
   <int value="1" label="Upgraded bandwidth to WebRTC"/>
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml
index b5aa8a5..41d0675 100644
--- a/tools/metrics/histograms/metadata/apps/histograms.xml
+++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -1607,6 +1607,18 @@
   </summary>
 </histogram>
 
+<histogram name="Apps.AppListSearchAutocomplete" enum="SearchBoxTextMatch"
+    expires_after="2022-12-01">
+  <owner>yulunwu@chromium.org</owner>
+  <owner>tbarzic@chromium.org</owner>
+  <summary>
+    The outcome of app list search attempting to autocomplete queries by
+    matching user entered text with search result text. This metric is split by
+    prefix match, substring match, and no match. This is gathered each time app
+    list attempts to perform an autocomplete.
+  </summary>
+</histogram>
+
 <histogram name="Apps.AppListSearchBoxActivated"
     enum="SearchBoxActivationSource" expires_after="2022-05-01">
 <!-- Name completed by histogram_suffixes name="TabletOrClamshellMode" -->
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index f05442a3b..347efd0 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -3665,6 +3665,18 @@
   </summary>
 </histogram>
 
+<histogram name="Ash.Shelf.Palette.Assistant.DeprecateStylusFeaturesToastEvent"
+    units="dp" expires_after="2022-12-15">
+  <owner>angelaxiao@chromium.org</owner>
+  <owner>assistive-eng@google.com</owner>
+  <summary>
+    Whether or not the user is shown the limitation toast notifying that the
+    Assistant stylus features (i.e. what's on my screen) have been deprecated.
+    Also considers whether or not the deprecation flag has been set. Recorded
+    upon every stylus long press action.
+  </summary>
+</histogram>
+
 <histogram name="Ash.Shelf.Palette.Assistant.GestureDuration" units="ms"
     expires_after="2021-12-12">
   <owner>amehfooz@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 8db3d42..fd651cb 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -5204,7 +5204,7 @@
 <histogram name="Eche.Connection.Duration" units="ms"
     expires_after="2022-10-04">
   <owner>samchiu@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
   <summary>
     The duration of time the phone is in the state connected to eche signaling
     service, and becomes disconnected.
@@ -5212,19 +5212,33 @@
 </histogram>
 
 <histogram name="Eche.Connection.Result" enum="BooleanSuccess"
-    expires_after="2022-12-04">
+    expires_after="2023-06-06">
   <owner>samchiu@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
   <summary>
-    Measures Eche connection success rate, considering attempts where the phone
-    is not nearby as failures.
+    Measures Eche connection success rate. This is recorded at the end of each
+    connection attempt whether it fails or succeeds and the failure bucket is
+    broken down to more specific segments in
+    Eche.Connection.Result.FailureReason
+  </summary>
+</histogram>
+
+<histogram name="Eche.Connection.Result.FailureReason"
+    enum="SecureChannelConnectionAttemptFailureReason"
+    expires_after="2023-06-06">
+  <owner>jonmann@chromium.org</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
+  <summary>
+    The reason for which the connection attempt to the phone has failed. This is
+    a breakdown of the failure bucket of Eche.Connection.Result and is recorded
+    at the time a connection attempt fails.
   </summary>
 </histogram>
 
 <histogram name="Eche.Connectivity.Latency" units="ms"
     expires_after="2022-12-04">
   <owner>samchiu@chromium.org</owner>
-  <owner>better-together-dev@google.com</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
   <summary>
     The duration of time the phone is in the state connecting to eche signaling
     service, and becomes connected.
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml
index 3d15cf4..dbe9b0cd 100644
--- a/tools/metrics/histograms/metadata/password/histograms.xml
+++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -161,7 +161,7 @@
 </histogram>
 
 <histogram name="KeyboardAccessory.DisabledSavingAccessoryImpressions"
-    enum="BooleanShown" expires_after="M105">
+    enum="BooleanShown" expires_after="M108">
   <owner>ioanap@chromium.org</owner>
   <owner>fhorschig@chromium.org</owner>
   <summary>
@@ -174,7 +174,7 @@
 </histogram>
 
 <histogram name="KeyboardAccessory.GenerationDialogChoice.{GenerationType}"
-    enum="GenerationDialogChoice" expires_after="M105">
+    enum="GenerationDialogChoice" expires_after="M108">
   <owner>ioanap@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/phonehub/histograms.xml b/tools/metrics/histograms/metadata/phonehub/histograms.xml
index 315b1c3..c4be584 100644
--- a/tools/metrics/histograms/metadata/phonehub/histograms.xml
+++ b/tools/metrics/histograms/metadata/phonehub/histograms.xml
@@ -189,7 +189,22 @@
   <owner>chromeos-cross-device-eng@google.com</owner>
   <summary>
     Measures PhoneHub connection success rate, considering attempts where the
-    phone is not nearby as failures.
+    phone is not nearby as failures. This is recorded at the end of each
+    connection attempt, whether it fails or succeeds and the failures are broken
+    down into more specific categories in
+    PhoneHub.Connection.Result.FailureReason
+  </summary>
+</histogram>
+
+<histogram name="PhoneHub.Connection.Result.FailureReason"
+    enum="SecureChannelConnectionAttemptFailureReason"
+    expires_after="2023-02-01">
+  <owner>jonmann@chromium.org</owner>
+  <owner>chromeos-cross-device-eng@google.com</owner>
+  <summary>
+    The reason for which a connection attempt to the phone has failed. This is a
+    breakdown of the failure bucket of PhoneHub.Connection.Result and is
+    recorded on each connection failure.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/sharing/histograms.xml b/tools/metrics/histograms/metadata/sharing/histograms.xml
index 9455f39..24ad5477 100644
--- a/tools/metrics/histograms/metadata/sharing/histograms.xml
+++ b/tools/metrics/histograms/metadata/sharing/histograms.xml
@@ -168,7 +168,7 @@
 </histogram>
 
 <histogram name="Sharing.LongScreenshots.BitmapGenerationStatus"
-    enum="SharingLongScreenshotsEvent" expires_after="M105">
+    enum="SharingLongScreenshotsEvent" expires_after="M107">
   <owner>skare@chromium.org</owner>
   <owner>src/chrome/browser/share/OWNERS</owner>
   <summary>
@@ -179,7 +179,7 @@
 </histogram>
 
 <histogram name="Sharing.LongScreenshots.BitmapSelectedHeight" units="pixels"
-    expires_after="M105">
+    expires_after="M107">
   <owner>skare@chromium.org</owner>
   <owner>src/chrome/browser/share/OWNERS</owner>
   <summary>
@@ -189,7 +189,7 @@
 </histogram>
 
 <histogram name="Sharing.LongScreenshots.Event"
-    enum="SharingLongScreenshotsEvent" expires_after="M105">
+    enum="SharingLongScreenshotsEvent" expires_after="M107">
   <owner>skare@chromium.org</owner>
   <owner>src/chrome/browser/share/OWNERS</owner>
   <summary>
@@ -532,7 +532,7 @@
 
 <histogram
     name="Sharing.SharingHubAndroid.TimeToSaveScreenshotImageBeforeShare"
-    units="ms" expires_after="M105">
+    units="ms" expires_after="M107">
   <owner>skare@chromium.org</owner>
   <owner>src/chrome/browser/share/OWNERS</owner>
   <summary>
diff --git a/tools/perf/OWNERS b/tools/perf/OWNERS
index 1bba60e1..f8c8f72 100644
--- a/tools/perf/OWNERS
+++ b/tools/perf/OWNERS
@@ -23,7 +23,6 @@
 # Perf bot sheriffs can disable stories.
 per-file expectations.config=skyostil@chromium.org
 per-file expectations.config=nuskos@chromium.org
-per-file expectations.config=sadrul@chromium.org
 per-file expectations.config=eseckler@chromium.org
 
 # emeritus:
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index d1f9e00..a0d6c2a 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,7 +6,7 @@
         },
         "win": {
             "hash": "3df88cdecaaaad7bc0b58d8f90a813352b11f024",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/5fb67c4d2c82a17bf682d715662b4ab3e37116c9/trace_processor_shell.exe"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/f533ef185cb9157bf0046a50b7b23bea3382e5e0/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "58893933be305d3bfe0a72ebebcacde2ac3ca893",
@@ -21,8 +21,8 @@
             "full_remote_path": "perfetto-luci-artifacts/v25.0/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "d9d4b43a64ed378a237b72ad67c86913f0bce7c7",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/f533ef185cb9157bf0046a50b7b23bea3382e5e0/trace_processor_shell"
+            "hash": "9a7e89dd21b196a0486e1f1a0e4fb5a028f0e75e",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/aee702e883cb0fd9a087a71b467746f54d68ca53/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/perf/experimental/story_clustering/OWNERS b/tools/perf/experimental/story_clustering/OWNERS
index 2b84d944..29a8320 100644
--- a/tools/perf/experimental/story_clustering/OWNERS
+++ b/tools/perf/experimental/story_clustering/OWNERS
@@ -1,2 +1 @@
 behdadb@chromium.org
-sadrul@chromium.org
diff --git a/tools/perf/page_sets/rendering/OWNERS b/tools/perf/page_sets/rendering/OWNERS
index e4fed44..a8ec03e 100644
--- a/tools/perf/page_sets/rendering/OWNERS
+++ b/tools/perf/page_sets/rendering/OWNERS
@@ -1,2 +1 @@
-sadrul@chromium.org
 vmiura@chromium.org
diff --git a/ui/aura/test/aura_test_utils.cc b/ui/aura/test/aura_test_utils.cc
index cec696d5..4661cb26 100644
--- a/ui/aura/test/aura_test_utils.cc
+++ b/ui/aura/test/aura_test_utils.cc
@@ -31,6 +31,10 @@
 
   void disable_ime() { host_->dispatcher_->set_skip_ime(true); }
 
+  void OnHostResizedInPixels(const gfx::Size& size_in_pixels) {
+    host_->OnHostResizedInPixels(size_in_pixels);
+  }
+
   static const base::flat_set<WindowTreeHost*>& GetThrottledHosts() {
     return WindowTreeHost::GetThrottledHostsForTesting();
   }
@@ -62,5 +66,11 @@
   return WindowTreeHostTestApi::GetThrottledHosts();
 }
 
+void CallOnHostResizedInPixels(WindowTreeHost* host,
+                               const gfx::Size& size_in_pixels) {
+  WindowTreeHostTestApi host_test_api(host);
+  host_test_api.OnHostResizedInPixels(size_in_pixels);
+}
+
 }  // namespace test
 }  // namespace aura
diff --git a/ui/aura/test/aura_test_utils.h b/ui/aura/test/aura_test_utils.h
index 0ee880c..1ba81f06 100644
--- a/ui/aura/test/aura_test_utils.h
+++ b/ui/aura/test/aura_test_utils.h
@@ -11,6 +11,7 @@
 
 namespace gfx {
 class Point;
+class Size;
 }
 
 namespace aura {
@@ -25,6 +26,8 @@
 void DisableIME(WindowTreeHost* host);
 void DisableNativeWindowOcclusionTracking(WindowTreeHost* host);
 const base::flat_set<WindowTreeHost*>& GetThrottledHosts();
+void CallOnHostResizedInPixels(WindowTreeHost* host,
+                               const gfx::Size& size_in_pixels);
 
 }  // namespace test
 }  // namespace aura
diff --git a/ui/aura/window_tree_host.cc b/ui/aura/window_tree_host.cc
index 19f0865..aa600c7 100644
--- a/ui/aura/window_tree_host.cc
+++ b/ui/aura/window_tree_host.cc
@@ -256,7 +256,7 @@
   return invert;
 }
 
-void WindowTreeHost::UpdateCompositorScaleAndSize(
+bool WindowTreeHost::UpdateCompositorScaleAndSize(
     const gfx::Size& new_size_in_pixels) {
   gfx::Rect new_bounds(new_size_in_pixels);
   if (compositor_->display_transform_hint() ==
@@ -265,12 +265,16 @@
           gfx::OVERLAY_TRANSFORM_ROTATE_270) {
     new_bounds.Transpose();
   }
+  bool changed = compositor_->device_scale_factor() != device_scale_factor_ ||
+                 compositor_->size() != new_bounds.size();
+  // TODO(crbug.com/1329481): Skip updating the compositor if not changed.
 
   // Allocate a new LocalSurfaceId for the new size or scale factor.
   window_->AllocateLocalSurfaceId();
   ScopedLocalSurfaceIdValidator lsi_validator(window());
   compositor_->SetScaleAndSize(device_scale_factor_, new_bounds.size(),
                                window_->GetLocalSurfaceId());
+  return changed;
 }
 
 void WindowTreeHost::ConvertDIPToScreenInPixels(gfx::Point* point) const {
@@ -690,10 +694,10 @@
   // from GetBoundsInPixels() on Windows to contain extra space for window
   // transition animations and should be used to set compositor size instead of
   // GetBoundsInPixels() in such case.
-  UpdateCompositorScaleAndSize(new_size_in_pixels);
-
-  for (WindowTreeHostObserver& observer : observers_)
-    observer.OnHostResized(this);
+  if (UpdateCompositorScaleAndSize(new_size_in_pixels)) {
+    for (WindowTreeHostObserver& observer : observers_)
+      observer.OnHostResized(this);
+  }
 }
 
 void WindowTreeHost::OnHostWorkspaceChanged() {
diff --git a/ui/aura/window_tree_host.h b/ui/aura/window_tree_host.h
index e89deeb3..d926669 100644
--- a/ui/aura/window_tree_host.h
+++ b/ui/aura/window_tree_host.h
@@ -133,7 +133,8 @@
 
   // Updates the compositor's size and scale from |new_size_in_pixels|,
   // |device_scale_factor_| and the compositor's transform hint.
-  void UpdateCompositorScaleAndSize(const gfx::Size& new_size_in_pixels);
+  // Return false if the compositor already has the same scale factor and size.
+  bool UpdateCompositorScaleAndSize(const gfx::Size& new_size_in_pixels);
 
   // Converts |point| from the root window's coordinate system to native
   // screen's.
diff --git a/ui/aura/window_tree_host_unittest.cc b/ui/aura/window_tree_host_unittest.cc
index 82fddad..ed17825 100644
--- a/ui/aura/window_tree_host_unittest.cc
+++ b/ui/aura/window_tree_host_unittest.cc
@@ -15,6 +15,7 @@
 #include "ui/aura/test/test_screen.h"
 #include "ui/aura/test/window_event_dispatcher_test_api.h"
 #include "ui/aura/window.h"
+#include "ui/aura/window_tree_host_observer.h"
 #include "ui/aura/window_tree_host_platform.h"
 #include "ui/base/ime/input_method.h"
 #include "ui/base/ui_base_features.h"
@@ -295,6 +296,45 @@
             gfx::PointF(5.3f, 0));
 }
 
+namespace {
+
+class TestWindowTreeHostObserver : public WindowTreeHostObserver {
+ public:
+  TestWindowTreeHostObserver() = default;
+  TestWindowTreeHostObserver(const TestWindowTreeHostObserver&) = delete;
+  TestWindowTreeHostObserver& operator=(const TestWindowTreeHostObserver&) =
+      delete;
+  // WndowTreeHostObserver:
+  ~TestWindowTreeHostObserver() override = default;
+  void OnHostResized(WindowTreeHost* host) override { resize_notified_ = true; }
+
+  bool resize_notified_and_reset() {
+    bool r = resize_notified_;
+    resize_notified_ = false;
+    return r;
+  }
+
+ private:
+  bool resize_notified_ = false;
+};
+
+}  // namespace
+
+TEST_F(WindowTreeHostTest, DontNotifyWhenNoChange) {
+  // make sure we're on the same size.
+  gfx::Size size_px = host()->compositor()->size();
+  TestWindowTreeHostObserver observer;
+  host()->AddObserver(&observer);
+  test::CallOnHostResizedInPixels(host(), size_px);
+  EXPECT_FALSE(observer.resize_notified_and_reset());
+  test_screen()->SetDeviceScaleFactor(2.0f, /*notify resize=*/true);
+  EXPECT_TRUE(observer.resize_notified_and_reset());
+  // Updating with same scale factor shouldn't notify observers.
+  test_screen()->SetDeviceScaleFactor(2.0f, /*notify resize=*/true);
+  EXPECT_FALSE(observer.resize_notified_and_reset());
+  host()->RemoveObserver(&observer);
+}
+
 class TestWindow : public ui::StubWindow {
  public:
   explicit TestWindow(ui::PlatformWindowDelegate* delegate)
diff --git a/ui/chromeos/strings/network_element_localized_strings_provider.cc b/ui/chromeos/strings/network_element_localized_strings_provider.cc
index 593e218..8d0f68f 100644
--- a/ui/chromeos/strings/network_element_localized_strings_provider.cc
+++ b/ui/chromeos/strings/network_element_localized_strings_provider.cc
@@ -428,6 +428,8 @@
                           chromeos::features::ShouldUseAttachApn());
   html_source->AddBoolean("esimPolicyEnabled",
                           chromeos::features::IsESimPolicyEnabled());
+  html_source->AddBoolean("isSimLockPolicyEnabled",
+                          chromeos::features::IsSimLockPolicyEnabled());
 }
 
 void AddConfigLocalizedStrings(content::WebUIDataSource* html_source) {
diff --git a/ui/gl/direct_composition_surface_win.cc b/ui/gl/direct_composition_surface_win.cc
index 480c380..cab0de03 100644
--- a/ui/gl/direct_composition_surface_win.cc
+++ b/ui/gl/direct_composition_surface_win.cc
@@ -431,7 +431,7 @@
 
   // EGL_KHR_no_config_context surface compatibility is required to be able to
   // MakeCurrent with the default pbuffer surface.
-  if (!display->IsEGLNoConfigContextSupported()) {
+  if (!display->ext->b_EGL_KHR_no_config_context) {
     DLOG(ERROR) << "EGL_KHR_no_config_context not supported";
     return;
   }
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index dfd2196..9970647 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -2814,18 +2814,23 @@
   'EGL_ANGLE_display_semaphore_share_group',
   'EGL_ANGLE_display_texture_share_group',
   'EGL_ANGLE_context_virtualization',
+  'EGL_ANGLE_create_context_backwards_compatible',
   'EGL_ANGLE_create_context_client_arrays',
   'EGL_ANGLE_create_context_webgl_compatibility',
   'EGL_ANGLE_external_context_and_surface',
   'EGL_ANGLE_keyed_mutex',
+  'EGL_ANGLE_robust_resource_initialization',
   'EGL_ANGLE_surface_orientation',
   'EGL_ANGLE_window_fixed_size',
+  'EGL_ARM_implicit_external_sync',
   'EGL_CHROMIUM_create_context_bind_generates_resource',
   'EGL_EXT_create_context_robustness',
   'EGL_EXT_gl_colorspace_display_p3',
   'EGL_EXT_gl_colorspace_display_p3_passthrough',
+  'EGL_EXT_image_dma_buf_import',
   'EGL_EXT_pixel_format_float',
   'EGL_IMG_context_priority',
+  'EGL_KHR_create_context',
   'EGL_KHR_gl_colorspace',
   'EGL_KHR_no_config_context',
   'EGL_KHR_surfaceless_context',
diff --git a/ui/gl/gl_angle_util_vulkan.cc b/ui/gl/gl_angle_util_vulkan.cc
index c0099aa..847e477 100644
--- a/ui/gl/gl_angle_util_vulkan.cc
+++ b/ui/gl/gl_angle_util_vulkan.cc
@@ -19,7 +19,7 @@
     return nullptr;
   }
 
-  if (!gl::GLSurfaceEGL::GetGLDisplayEGL()->IsEGLQueryDeviceSupported()) {
+  if (!gl::g_driver_egl.client_ext.b_EGL_EXT_device_query) {
     LOG(ERROR) << "EGL_EXT_device_query not supported";
     return nullptr;
   }
diff --git a/ui/gl/gl_angle_util_win.cc b/ui/gl/gl_angle_util_win.cc
index 3427df23..69f460e 100644
--- a/ui/gl/gl_angle_util_win.cc
+++ b/ui/gl/gl_angle_util_win.cc
@@ -24,7 +24,7 @@
     return nullptr;
   }
 
-  if (!gl::GLSurfaceEGL::GetGLDisplayEGL()->IsEGLQueryDeviceSupported()) {
+  if (!gl::g_driver_egl.client_ext.b_EGL_EXT_device_query) {
     DVLOG(1) << "EGL_EXT_device_query not supported";
     return nullptr;
   }
diff --git a/ui/gl/gl_bindings_autogen_egl.cc b/ui/gl/gl_bindings_autogen_egl.cc
index 8cbbadd..33bb5b2 100644
--- a/ui/gl/gl_bindings_autogen_egl.cc
+++ b/ui/gl/gl_bindings_autogen_egl.cc
@@ -285,6 +285,8 @@
       gfx::HasExtension(extensions, "EGL_ANDROID_native_fence_sync");
   b_EGL_ANGLE_context_virtualization =
       gfx::HasExtension(extensions, "EGL_ANGLE_context_virtualization");
+  b_EGL_ANGLE_create_context_backwards_compatible = gfx::HasExtension(
+      extensions, "EGL_ANGLE_create_context_backwards_compatible");
   b_EGL_ANGLE_create_context_client_arrays =
       gfx::HasExtension(extensions, "EGL_ANGLE_create_context_client_arrays");
   b_EGL_ANGLE_create_context_webgl_compatibility = gfx::HasExtension(
@@ -303,6 +305,8 @@
       gfx::HasExtension(extensions, "EGL_ANGLE_power_preference");
   b_EGL_ANGLE_query_surface_pointer =
       gfx::HasExtension(extensions, "EGL_ANGLE_query_surface_pointer");
+  b_EGL_ANGLE_robust_resource_initialization =
+      gfx::HasExtension(extensions, "EGL_ANGLE_robust_resource_initialization");
   b_EGL_ANGLE_stream_producer_d3d_texture =
       gfx::HasExtension(extensions, "EGL_ANGLE_stream_producer_d3d_texture");
   b_EGL_ANGLE_surface_d3d_texture_2d_share_handle = gfx::HasExtension(
@@ -315,6 +319,8 @@
       gfx::HasExtension(extensions, "EGL_ANGLE_vulkan_image");
   b_EGL_ANGLE_window_fixed_size =
       gfx::HasExtension(extensions, "EGL_ANGLE_window_fixed_size");
+  b_EGL_ARM_implicit_external_sync =
+      gfx::HasExtension(extensions, "EGL_ARM_implicit_external_sync");
   b_EGL_CHROMIUM_create_context_bind_generates_resource = gfx::HasExtension(
       extensions, "EGL_CHROMIUM_create_context_bind_generates_resource");
   b_EGL_CHROMIUM_sync_control =
@@ -325,6 +331,8 @@
       gfx::HasExtension(extensions, "EGL_EXT_gl_colorspace_display_p3");
   b_EGL_EXT_gl_colorspace_display_p3_passthrough = gfx::HasExtension(
       extensions, "EGL_EXT_gl_colorspace_display_p3_passthrough");
+  b_EGL_EXT_image_dma_buf_import =
+      gfx::HasExtension(extensions, "EGL_EXT_image_dma_buf_import");
   b_EGL_EXT_image_dma_buf_import_modifiers =
       gfx::HasExtension(extensions, "EGL_EXT_image_dma_buf_import_modifiers");
   b_EGL_EXT_image_flush_external =
@@ -333,6 +341,8 @@
       gfx::HasExtension(extensions, "EGL_EXT_pixel_format_float");
   b_EGL_IMG_context_priority =
       gfx::HasExtension(extensions, "EGL_IMG_context_priority");
+  b_EGL_KHR_create_context =
+      gfx::HasExtension(extensions, "EGL_KHR_create_context");
   b_EGL_KHR_fence_sync = gfx::HasExtension(extensions, "EGL_KHR_fence_sync");
   b_EGL_KHR_gl_colorspace =
       gfx::HasExtension(extensions, "EGL_KHR_gl_colorspace");
diff --git a/ui/gl/gl_bindings_autogen_egl.h b/ui/gl/gl_bindings_autogen_egl.h
index 5819b20..985e75a 100644
--- a/ui/gl/gl_bindings_autogen_egl.h
+++ b/ui/gl/gl_bindings_autogen_egl.h
@@ -347,6 +347,7 @@
   bool b_EGL_ANDROID_get_native_client_buffer;
   bool b_EGL_ANDROID_native_fence_sync;
   bool b_EGL_ANGLE_context_virtualization;
+  bool b_EGL_ANGLE_create_context_backwards_compatible;
   bool b_EGL_ANGLE_create_context_client_arrays;
   bool b_EGL_ANGLE_create_context_webgl_compatibility;
   bool b_EGL_ANGLE_d3d_share_handle_client_buffer;
@@ -356,21 +357,25 @@
   bool b_EGL_ANGLE_keyed_mutex;
   bool b_EGL_ANGLE_power_preference;
   bool b_EGL_ANGLE_query_surface_pointer;
+  bool b_EGL_ANGLE_robust_resource_initialization;
   bool b_EGL_ANGLE_stream_producer_d3d_texture;
   bool b_EGL_ANGLE_surface_d3d_texture_2d_share_handle;
   bool b_EGL_ANGLE_surface_orientation;
   bool b_EGL_ANGLE_sync_control_rate;
   bool b_EGL_ANGLE_vulkan_image;
   bool b_EGL_ANGLE_window_fixed_size;
+  bool b_EGL_ARM_implicit_external_sync;
   bool b_EGL_CHROMIUM_create_context_bind_generates_resource;
   bool b_EGL_CHROMIUM_sync_control;
   bool b_EGL_EXT_create_context_robustness;
   bool b_EGL_EXT_gl_colorspace_display_p3;
   bool b_EGL_EXT_gl_colorspace_display_p3_passthrough;
+  bool b_EGL_EXT_image_dma_buf_import;
   bool b_EGL_EXT_image_dma_buf_import_modifiers;
   bool b_EGL_EXT_image_flush_external;
   bool b_EGL_EXT_pixel_format_float;
   bool b_EGL_IMG_context_priority;
+  bool b_EGL_KHR_create_context;
   bool b_EGL_KHR_fence_sync;
   bool b_EGL_KHR_gl_colorspace;
   bool b_EGL_KHR_gl_texture_2D_image;
diff --git a/ui/gl/gl_context_egl.cc b/ui/gl/gl_context_egl.cc
index ef7207b..d210618 100644
--- a/ui/gl/gl_context_egl.cc
+++ b/ui/gl/gl_context_egl.cc
@@ -130,7 +130,7 @@
 
   // Always prefer to use EGL_KHR_no_config_context so that all surfaces and
   // contexts are compatible
-  if (!gl_display_->IsEGLNoConfigContextSupported()) {
+  if (!gl_display_->ext->b_EGL_KHR_no_config_context) {
     config_ = compatible_surface->GetConfig();
     EGLint config_renderable_type = 0;
     if (!eglGetConfigAttrib(gl_display_->GetDisplay(), config_,
@@ -158,7 +158,7 @@
 
   // EGL_KHR_create_context allows requesting both a major and minor context
   // version
-  if (gl_display_->HasEGLExtension("EGL_KHR_create_context")) {
+  if (gl_display_->ext->b_EGL_KHR_create_context) {
     context_attributes.push_back(EGL_CONTEXT_MAJOR_VERSION);
     context_attributes.push_back(context_client_major_version);
 
@@ -176,7 +176,7 @@
 
   bool is_swangle = IsSoftwareGLImplementation(GetGLImplementationParts());
 
-  if (gl_display_->IsCreateContextRobustnessSupported() || is_swangle) {
+  if (gl_display_->ext->b_EGL_EXT_create_context_robustness || is_swangle) {
     DVLOG(1) << "EGL_EXT_create_context_robustness supported.";
     context_attributes.push_back(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
     context_attributes.push_back(
@@ -186,7 +186,7 @@
           EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
       context_attributes.push_back(EGL_LOSE_CONTEXT_ON_RESET_EXT);
 
-      if (gl_display_->IsRobustnessVideoMemoryPurgeSupported()) {
+      if (gl_display_->ext->b_EGL_NV_robustness_video_memory_purge) {
         context_attributes.push_back(
             EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV);
         context_attributes.push_back(EGL_TRUE);
@@ -204,7 +204,7 @@
     return false;
   }
 
-  if (gl_display_->IsCreateContextBindGeneratesResourceSupported()) {
+  if (gl_display_->ext->b_EGL_CHROMIUM_create_context_bind_generates_resource) {
     context_attributes.push_back(EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM);
     context_attributes.push_back(attribs.bind_generates_resource ? EGL_TRUE
                                                                  : EGL_FALSE);
@@ -212,7 +212,7 @@
     DCHECK(attribs.bind_generates_resource);
   }
 
-  if (gl_display_->IsCreateContextWebGLCompatabilitySupported()) {
+  if (gl_display_->ext->b_EGL_ANGLE_create_context_webgl_compatibility) {
     context_attributes.push_back(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE);
     context_attributes.push_back(
         attribs.webgl_compatibility_context ? EGL_TRUE : EGL_FALSE);
@@ -234,7 +234,7 @@
     }
   }
 
-  if (gl_display_->IsDisplayTextureShareGroupSupported()) {
+  if (gl_display_->ext->b_EGL_ANGLE_display_texture_share_group) {
     context_attributes.push_back(EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE);
     context_attributes.push_back(
         attribs.global_texture_share_group ? EGL_TRUE : EGL_FALSE);
@@ -242,7 +242,7 @@
     DCHECK(!attribs.global_texture_share_group);
   }
 
-  if (gl_display_->IsDisplaySemaphoreShareGroupSupported()) {
+  if (gl_display_->ext->b_EGL_ANGLE_display_semaphore_share_group) {
     context_attributes.push_back(EGL_DISPLAY_SEMAPHORE_SHARE_GROUP_ANGLE);
     context_attributes.push_back(
         attribs.global_semaphore_share_group ? EGL_TRUE : EGL_FALSE);
@@ -250,13 +250,14 @@
     DCHECK(!attribs.global_semaphore_share_group);
   }
 
-  if (gl_display_->IsCreateContextClientArraysSupported()) {
+  if (gl_display_->ext->b_EGL_ANGLE_create_context_client_arrays) {
     // Disable client arrays if the context supports it
     context_attributes.push_back(EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE);
     context_attributes.push_back(EGL_FALSE);
   }
 
-  if (gl_display_->IsRobustResourceInitSupported() || is_swangle) {
+  if (gl_display_->ext->b_EGL_ANGLE_robust_resource_initialization ||
+      is_swangle) {
     context_attributes.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE);
     context_attributes.push_back(
         (attribs.robust_resource_initialization || is_swangle) ? EGL_TRUE
@@ -265,15 +266,14 @@
     DCHECK(!attribs.robust_resource_initialization);
   }
 
-  if (gl_display_->HasEGLExtension(
-          "EGL_ANGLE_create_context_backwards_compatible")) {
+  if (gl_display_->ext->b_EGL_ANGLE_create_context_backwards_compatible) {
     // Request a specific context version. The Passthrough command decoder
     // relies on the returned context being the exact version it requested.
     context_attributes.push_back(EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE);
     context_attributes.push_back(EGL_FALSE);
   }
 
-  if (gl_display_->IsANGLEPowerPreferenceSupported()) {
+  if (gl_display_->ext->b_EGL_ANGLE_power_preference) {
     GpuPreference pref = attribs.gpu_preference;
     pref = GLSurface::AdjustGpuPreference(pref);
     switch (pref) {
@@ -293,7 +293,7 @@
     }
   }
 
-  if (gl_display_->IsANGLEExternalContextAndSurfaceSupported()) {
+  if (gl_display_->ext->b_EGL_ANGLE_external_context_and_surface) {
     if (attribs.angle_create_from_external_context) {
       context_attributes.push_back(EGL_EXTERNAL_CONTEXT_ANGLE);
       context_attributes.push_back(EGL_TRUE);
@@ -304,7 +304,7 @@
     }
   }
 
-  if (gl_display_->IsANGLEContextVirtualizationSupported()) {
+  if (gl_display_->ext->b_EGL_ANGLE_context_virtualization) {
     context_attributes.push_back(EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE);
     context_attributes.push_back(
         static_cast<EGLint>(attribs.angle_context_virtualization_group_number));
@@ -322,7 +322,7 @@
   // If EGL_KHR_no_config_context is in use and context creation failed,
   // it might indicate that an unsupported ES version was requested. Try
   // falling back to a lower version.
-  if (!context_ && gl_display_->IsEGLNoConfigContextSupported() &&
+  if (!context_ && gl_display_->ext->b_EGL_KHR_no_config_context &&
       eglGetError() == EGL_BAD_MATCH) {
     // Set up the list of versions to try: 3.1 -> 3.0 -> 2.0
     std::vector<std::pair<EGLint, EGLint>> candidate_versions;
@@ -395,7 +395,7 @@
 }
 
 void GLContextEGL::SetVisibility(bool visibility) {
-  if (gl_display_->IsANGLEPowerPreferenceSupported()) {
+  if (gl_display_->ext->b_EGL_ANGLE_power_preference) {
     // It doesn't matter whether this context was explicitly allocated
     // with a power preference - ANGLE will take care of any default behavior.
     if (visibility) {
@@ -555,7 +555,7 @@
   DCHECK(g_current_gl_driver);
   const ExtensionsGL& ext = g_current_gl_driver->ext;
   if ((graphics_reset_status_ == GL_NO_ERROR) &&
-      gl_display_->IsCreateContextRobustnessSupported() &&
+      gl_display_->ext->b_EGL_EXT_create_context_robustness &&
       (ext.b_GL_KHR_robustness || ext.b_GL_EXT_robustness ||
        ext.b_GL_ARB_robustness)) {
     graphics_reset_status_ = glGetGraphicsResetStatusARB();
diff --git a/ui/gl/gl_display.cc b/ui/gl/gl_display.cc
index 7ee36c2..92dfb47 100644
--- a/ui/gl/gl_display.cc
+++ b/ui/gl/gl_display.cc
@@ -55,32 +55,6 @@
   return context ? context->GetGLDisplayEGL() : nullptr;
 }
 
-bool GLDisplayEGL::HasEGLClientExtension(const char* name) {
-  if (!egl_client_extensions)
-    return false;
-  return GLSurface::ExtensionsContain(egl_client_extensions, name);
-}
-
-bool GLDisplayEGL::HasEGLExtension(const char* name) {
-  return GLSurface::ExtensionsContain(egl_extensions, name);
-}
-
-bool GLDisplayEGL::IsCreateContextRobustnessSupported() {
-  return egl_create_context_robustness_supported;
-}
-
-bool GLDisplayEGL::IsRobustnessVideoMemoryPurgeSupported() {
-  return egl_robustness_video_memory_purge_supported;
-}
-
-bool GLDisplayEGL::IsCreateContextBindGeneratesResourceSupported() {
-  return egl_create_context_bind_generates_resource_supported;
-}
-
-bool GLDisplayEGL::IsCreateContextWebGLCompatabilitySupported() {
-  return egl_create_context_webgl_compatability_supported;
-}
-
 bool GLDisplayEGL::IsEGLSurfacelessContextSupported() {
   return egl_surfaceless_context_supported;
 }
@@ -89,66 +63,13 @@
   return egl_context_priority_supported;
 }
 
-bool GLDisplayEGL::IsEGLNoConfigContextSupported() {
-  return egl_no_config_context_supported;
-}
-
-bool GLDisplayEGL::IsRobustResourceInitSupported() {
-  return egl_robust_resource_init_supported;
-}
-
-bool GLDisplayEGL::IsDisplayTextureShareGroupSupported() {
-  return egl_display_texture_share_group_supported;
-}
-
-bool GLDisplayEGL::IsDisplaySemaphoreShareGroupSupported() {
-  return egl_display_semaphore_share_group_supported;
-}
-
-bool GLDisplayEGL::IsCreateContextClientArraysSupported() {
-  return egl_create_context_client_arrays_supported;
-}
-
 bool GLDisplayEGL::IsAndroidNativeFenceSyncSupported() {
   return egl_android_native_fence_sync_supported;
 }
 
-bool GLDisplayEGL::IsPixelFormatFloatSupported() {
-  return egl_ext_pixel_format_float_supported;
-}
-
-bool GLDisplayEGL::IsANGLEFeatureControlSupported() {
-  return egl_angle_feature_control_supported;
-}
-
-bool GLDisplayEGL::IsANGLEPowerPreferenceSupported() {
-  return egl_angle_power_preference_supported;
-}
-
-bool GLDisplayEGL::IsANGLEDisplayPowerPreferenceSupported() {
-  return egl_angle_display_power_preference_supported;
-}
-
-bool GLDisplayEGL::IsANGLEPlatformANGLEDeviceIdSupported() {
-  return egl_angle_platform_angle_device_id_supported;
-}
-
 bool GLDisplayEGL::IsANGLEExternalContextAndSurfaceSupported() {
-  return egl_angle_external_context_and_surface_supported;
+  return this->ext->b_EGL_ANGLE_external_context_and_surface;
 }
-
-bool GLDisplayEGL::IsANGLEContextVirtualizationSupported() {
-  return egl_angle_context_virtualization_supported;
-}
-
-bool GLDisplayEGL::IsANGLEVulkanImageSupported() {
-  return egl_angle_vulkan_image_supported;
-}
-
-bool GLDisplayEGL::IsEGLQueryDeviceSupported() {
-  return egl_ext_query_device_supported;
-}
-
 #endif  // defined(USE_EGL)
 
 #if defined(USE_GLX)
diff --git a/ui/gl/gl_display.h b/ui/gl/gl_display.h
index 7ce5bec..ef4f069 100644
--- a/ui/gl/gl_display.h
+++ b/ui/gl/gl_display.h
@@ -99,64 +99,18 @@
   EGLNativeDisplayType GetNativeDisplay();
   DisplayType GetDisplayType();
 
-  bool HasEGLClientExtension(const char* name);
-  bool HasEGLExtension(const char* name);
-  bool IsCreateContextRobustnessSupported();
-  bool IsRobustnessVideoMemoryPurgeSupported();
-  bool IsCreateContextBindGeneratesResourceSupported();
-  bool IsCreateContextWebGLCompatabilitySupported();
   bool IsEGLSurfacelessContextSupported();
   bool IsEGLContextPrioritySupported();
-  bool IsEGLNoConfigContextSupported();
-  bool IsRobustResourceInitSupported();
-  bool IsDisplayTextureShareGroupSupported();
-  bool IsDisplaySemaphoreShareGroupSupported();
-  bool IsCreateContextClientArraysSupported();
   bool IsAndroidNativeFenceSyncSupported();
-  bool IsPixelFormatFloatSupported();
-  bool IsANGLEFeatureControlSupported();
-  bool IsANGLEPowerPreferenceSupported();
-  bool IsANGLEDisplayPowerPreferenceSupported();
-  bool IsANGLEPlatformANGLEDeviceIdSupported();
   bool IsANGLEExternalContextAndSurfaceSupported();
-  bool IsANGLEContextVirtualizationSupported();
-  bool IsANGLEVulkanImageSupported();
-  bool IsEGLQueryDeviceSupported();
 
   EGLDisplayPlatform native_display = EGLDisplayPlatform(EGL_DEFAULT_DISPLAY);
 
   DisplayType display_type = DisplayType::DEFAULT;
 
-  const char* egl_client_extensions = nullptr;
-  const char* egl_extensions = nullptr;
-  bool egl_create_context_robustness_supported = false;
-  bool egl_robustness_video_memory_purge_supported = false;
-  bool egl_create_context_bind_generates_resource_supported = false;
-  bool egl_create_context_webgl_compatability_supported = false;
-  bool egl_sync_control_supported = false;
-  bool egl_sync_control_rate_supported = false;
-  bool egl_window_fixed_size_supported = false;
   bool egl_surfaceless_context_supported = false;
-  bool egl_surface_orientation_supported = false;
   bool egl_context_priority_supported = false;
-  bool egl_khr_colorspace = false;
-  bool egl_ext_colorspace_display_p3 = false;
-  bool egl_ext_colorspace_display_p3_passthrough = false;
-  bool egl_no_config_context_supported = false;
-  bool egl_robust_resource_init_supported = false;
-  bool egl_display_texture_share_group_supported = false;
-  bool egl_display_semaphore_share_group_supported = false;
-  bool egl_create_context_client_arrays_supported = false;
   bool egl_android_native_fence_sync_supported = false;
-  bool egl_ext_pixel_format_float_supported = false;
-  bool egl_angle_feature_control_supported = false;
-  bool egl_angle_power_preference_supported = false;
-  bool egl_angle_display_power_preference_supported = false;
-  bool egl_angle_platform_angle_device_id_supported = false;
-  bool egl_angle_external_context_and_surface_supported = false;
-  bool egl_ext_query_device_supported = false;
-  bool egl_angle_context_virtualization_supported = false;
-  bool egl_angle_vulkan_image_supported = false;
 
   std::unique_ptr<DisplayExtensionsEGL> ext;
 
diff --git a/ui/gl/gl_image_native_pixmap.cc b/ui/gl/gl_image_native_pixmap.cc
index effe6136..299eb9e3 100644
--- a/ui/gl/gl_image_native_pixmap.cc
+++ b/ui/gl/gl_image_native_pixmap.cc
@@ -131,12 +131,10 @@
     : GLImageEGL(size),
       format_(format),
       plane_(plane),
-      has_image_flush_external_(
-          gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension(
-              "EGL_EXT_image_flush_external")),
-      has_image_dma_buf_export_(
-          gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension(
-              "EGL_MESA_image_dma_buf_export")) {}
+      has_image_flush_external_(gl::GLSurfaceEGL::GetGLDisplayEGL()
+                                    ->ext->b_EGL_EXT_image_flush_external),
+      has_image_dma_buf_export_(gl::GLSurfaceEGL::GetGLDisplayEGL()
+                                    ->ext->b_EGL_MESA_image_dma_buf_export) {}
 
 GLImageNativePixmap::~GLImageNativePixmap() {}
 
@@ -174,8 +172,8 @@
                                            EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
                                            EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT};
       bool has_dma_buf_import_modifier =
-          gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension(
-              "EGL_EXT_image_dma_buf_import_modifiers");
+          gl::GLSurfaceEGL::GetGLDisplayEGL()
+              ->ext->b_EGL_EXT_image_dma_buf_import_modifiers;
 
       for (size_t attrs_plane = 0; attrs_plane < pixmap->GetNumberOfPlanes();
            ++attrs_plane) {
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc
index 9906e709..7a8f3ee 100644
--- a/ui/gl/gl_surface_egl.cc
+++ b/ui/gl/gl_surface_egl.cc
@@ -228,7 +228,7 @@
   static bool IsSupported(GLDisplayEGL* display) {
     DCHECK(display);
     return SyncControlVSyncProvider::IsSupported() &&
-           display->egl_sync_control_supported;
+           display->ext->b_EGL_CHROMIUM_sync_control;
   }
 
  protected:
@@ -249,7 +249,7 @@
   }
 
   bool GetMscRate(int32_t* numerator, int32_t* denominator) override {
-    if (!display_->egl_sync_control_rate_supported) {
+    if (!display_->ext->b_EGL_ANGLE_sync_control_rate) {
       return false;
     }
 
@@ -272,7 +272,7 @@
   }
 
   void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) override {
-    DCHECK(display_->IsANGLEPowerPreferenceSupported());
+    DCHECK(display_->ext->b_EGL_ANGLE_power_preference);
     eglHandleGPUSwitchANGLE(display_->GetDisplay());
   }
 
@@ -340,7 +340,7 @@
       GetAttribArrayFromStringVector(enabled_features);
   std::vector<const char*> disabled_features_attribs =
       GetAttribArrayFromStringVector(disabled_features);
-  if (gl_display->egl_angle_feature_control_supported) {
+  if (g_driver_egl.client_ext.b_EGL_ANGLE_feature_control) {
     if (!enabled_features_attribs.empty()) {
       display_attribs.push_back(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE);
       display_attribs.push_back(
@@ -354,7 +354,7 @@
   }
   // TODO(dbehr) Add an attrib to Angle to pass EGL platform.
 
-  if (gl_display->IsANGLEDisplayPowerPreferenceSupported()) {
+  if (g_driver_egl.client_ext.b_EGL_ANGLE_display_power_preference) {
     GpuPreference pref =
         GLSurface::AdjustGpuPreference(GpuPreference::kDefault);
     switch (pref) {
@@ -398,7 +398,7 @@
     extra_display_attribs.push_back(EGL_TRUE);
   }
   if (system_device_id != 0 &&
-      gl_display->IsANGLEPlatformANGLEDeviceIdSupported()) {
+      g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_device_id) {
     uint32_t low_part = system_device_id & 0xffffffff;
     extra_display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE);
     extra_display_attribs.push_back(low_part);
@@ -1030,34 +1030,6 @@
 
 // static
 void GLSurfaceEGL::InitializeOneOffCommon(GLDisplayEGL* display) {
-  display->egl_client_extensions =
-      eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
-  display->egl_extensions =
-      eglQueryString(display->GetDisplay(), EGL_EXTENSIONS);
-
-  display->egl_create_context_robustness_supported =
-      display->HasEGLExtension("EGL_EXT_create_context_robustness");
-  display->egl_robustness_video_memory_purge_supported =
-      display->HasEGLExtension("EGL_NV_robustness_video_memory_purge");
-  display->egl_create_context_bind_generates_resource_supported =
-      display->HasEGLExtension(
-          "EGL_CHROMIUM_create_context_bind_generates_resource");
-  display->egl_create_context_webgl_compatability_supported =
-      display->HasEGLExtension("EGL_ANGLE_create_context_webgl_compatibility");
-  display->egl_sync_control_supported =
-      display->HasEGLExtension("EGL_CHROMIUM_sync_control");
-  display->egl_sync_control_rate_supported =
-      display->HasEGLExtension("EGL_ANGLE_sync_control_rate");
-  display->egl_window_fixed_size_supported =
-      display->HasEGLExtension("EGL_ANGLE_window_fixed_size");
-  display->egl_surface_orientation_supported =
-      display->HasEGLExtension("EGL_ANGLE_surface_orientation");
-  display->egl_khr_colorspace =
-      display->HasEGLExtension("EGL_KHR_gl_colorspace");
-  display->egl_ext_colorspace_display_p3 =
-      display->HasEGLExtension("EGL_EXT_gl_colorspace_display_p3");
-  display->egl_ext_colorspace_display_p3_passthrough =
-      display->HasEGLExtension("EGL_EXT_gl_colorspace_display_p3_passthrough");
   // According to https://source.android.com/compatibility/android-cdd.html the
   // EGL_IMG_context_priority extension is mandatory for Virtual Reality High
   // Performance support, but due to a bug in Android Nougat the extension
@@ -1066,27 +1038,13 @@
   // that this implies context priority is also supported. See also:
   // https://github.com/googlevr/gvr-android-sdk/issues/330
   display->egl_context_priority_supported =
-      display->HasEGLExtension("EGL_IMG_context_priority") ||
-      (display->HasEGLExtension("EGL_ANDROID_front_buffer_auto_refresh") &&
-       display->HasEGLExtension("EGL_ANDROID_create_native_client_buffer"));
-
-  // Need EGL_KHR_no_config_context to allow surfaces with and without alpha to
-  // be bound to the same context.
-  display->egl_no_config_context_supported =
-      display->HasEGLExtension("EGL_KHR_no_config_context");
-
-  display->egl_display_texture_share_group_supported =
-      display->HasEGLExtension("EGL_ANGLE_display_texture_share_group");
-  display->egl_display_semaphore_share_group_supported =
-      display->HasEGLExtension("EGL_ANGLE_display_semaphore_share_group");
-  display->egl_create_context_client_arrays_supported =
-      display->HasEGLExtension("EGL_ANGLE_create_context_client_arrays");
-  display->egl_robust_resource_init_supported =
-      display->HasEGLExtension("EGL_ANGLE_robust_resource_initialization");
+      display->ext->b_EGL_IMG_context_priority ||
+      (display->ext->b_EGL_ANDROID_front_buffer_auto_refresh &&
+       display->ext->b_EGL_ANDROID_create_native_client_buffer);
 
   // Check if SurfacelessEGL is supported.
   display->egl_surfaceless_context_supported =
-      display->HasEGLExtension("EGL_KHR_surfaceless_context");
+      display->ext->b_EGL_KHR_surfaceless_context;
 
   // TODO(oetuaho@nvidia.com): Surfaceless is disabled on Android as a temporary
   // workaround, since code written for Android WebView takes different paths
@@ -1098,7 +1056,7 @@
 #if BUILDFLAG(IS_ANDROID)
   // Use the WebGL compatibility extension for detecting ANGLE. ANGLE always
   // exposes it.
-  bool is_angle = display->egl_create_context_webgl_compatability_supported;
+  bool is_angle = display->ext->b_EGL_ANGLE_create_context_webgl_compatibility;
   if (!is_angle) {
     display->egl_surfaceless_context_supported = false;
   }
@@ -1133,7 +1091,7 @@
   // Android level, update the heuristic to trust the reported extension from
   // that version onward.
   display->egl_android_native_fence_sync_supported =
-      display->HasEGLExtension("EGL_ANDROID_native_fence_sync");
+      display->ext->b_EGL_ANDROID_native_fence_sync;
 #if BUILDFLAG(IS_ANDROID)
   if (!display->egl_android_native_fence_sync_supported &&
       base::android::BuildInfo::GetInstance()->sdk_int() >=
@@ -1145,25 +1103,7 @@
   }
 #endif
 
-  display->egl_ext_pixel_format_float_supported =
-      display->HasEGLExtension("EGL_EXT_pixel_format_float");
-
-  display->egl_angle_power_preference_supported =
-      display->HasEGLExtension("EGL_ANGLE_power_preference");
-
-  display->egl_angle_external_context_and_surface_supported =
-      display->HasEGLExtension("EGL_ANGLE_external_context_and_surface");
-
-  display->egl_ext_query_device_supported =
-      display->HasEGLClientExtension("EGL_EXT_device_query");
-
-  display->egl_angle_context_virtualization_supported =
-      display->HasEGLExtension("EGL_ANGLE_context_virtualization");
-
-  display->egl_angle_vulkan_image_supported =
-      display->HasEGLExtension("EGL_ANGLE_vulkan_image");
-
-  if (display->egl_angle_power_preference_supported) {
+  if (display->ext->b_EGL_ANGLE_power_preference) {
     g_egl_gpu_switching_observer = new EGLGpuSwitchingObserver(display);
     ui::GpuSwitchingManager::GetInstance()->AddObserver(
         g_egl_gpu_switching_observer);
@@ -1176,11 +1116,6 @@
   if (display->GetDisplay() == EGL_NO_DISPLAY)
     return false;
   display->ext->UpdateConditionalExtensionSettings(display);
-  display->egl_client_extensions =
-      eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
-  display->egl_extensions =
-      eglQueryString(display->GetDisplay(), EGL_EXTENSIONS);
-
   return true;
 }
 
@@ -1201,21 +1136,9 @@
   eglTerminate(display->GetDisplay());
   display->SetDisplay(EGL_NO_DISPLAY);
 
-  display->egl_client_extensions = nullptr;
-  display->egl_extensions = nullptr;
-  display->egl_create_context_robustness_supported = false;
-  display->egl_robustness_video_memory_purge_supported = false;
-  display->egl_create_context_bind_generates_resource_supported = false;
-  display->egl_create_context_webgl_compatability_supported = false;
-  display->egl_sync_control_supported = false;
-  display->egl_sync_control_rate_supported = false;
-  display->egl_window_fixed_size_supported = false;
-  display->egl_surface_orientation_supported = false;
   display->egl_surfaceless_context_supported = false;
-  display->egl_robust_resource_init_supported = false;
-  display->egl_display_texture_share_group_supported = false;
-  display->egl_create_context_client_arrays_supported = false;
-  display->egl_angle_feature_control_supported = false;
+  display->egl_context_priority_supported = false;
+  display->egl_android_native_fence_sync_supported = false;
 }
 
 GLSurfaceEGL::~GLSurfaceEGL() = default;
@@ -1233,12 +1156,7 @@
 
   gl_display->native_display = native_display;
 
-  // If EGL_EXT_client_extensions not supported this call to eglQueryString
-  // will return nullptr.
-  gl_display->egl_client_extensions =
-      eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
-
-  bool supports_egl_debug = gl_display->HasEGLClientExtension("EGL_KHR_debug");
+  bool supports_egl_debug = g_driver_egl.client_ext.b_EGL_KHR_debug;
   if (supports_egl_debug) {
     EGLAttrib controls[] = {
         EGL_DEBUG_MSG_CRITICAL_KHR,
@@ -1264,36 +1182,27 @@
   bool supports_angle_egl = false;
   bool supports_angle_metal = false;
   // Check for availability of ANGLE extensions.
-  if (gl_display->HasEGLClientExtension("EGL_ANGLE_platform_angle")) {
-    supports_angle_d3d =
-        gl_display->HasEGLClientExtension("EGL_ANGLE_platform_angle_d3d");
+  if (g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle) {
+    supports_angle_d3d = g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_d3d;
     supports_angle_opengl =
-        gl_display->HasEGLClientExtension("EGL_ANGLE_platform_angle_opengl");
+        g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_opengl;
     supports_angle_null =
-        gl_display->HasEGLClientExtension("EGL_ANGLE_platform_angle_null");
+        g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_null;
     supports_angle_vulkan =
-        gl_display->HasEGLClientExtension("EGL_ANGLE_platform_angle_vulkan");
-    supports_angle_swiftshader = gl_display->HasEGLClientExtension(
-        "EGL_ANGLE_platform_angle_device_type_swiftshader");
-    supports_angle_egl = gl_display->HasEGLClientExtension(
-        "EGL_ANGLE_platform_angle_device_type_egl_angle");
+        g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_vulkan;
+    supports_angle_swiftshader =
+        g_driver_egl.client_ext
+            .b_EGL_ANGLE_platform_angle_device_type_swiftshader;
+    supports_angle_egl = g_driver_egl.client_ext
+                             .b_EGL_ANGLE_platform_angle_device_type_egl_angle;
     supports_angle_metal =
-        gl_display->HasEGLClientExtension("EGL_ANGLE_platform_angle_metal");
+        g_driver_egl.client_ext.b_EGL_ANGLE_platform_angle_metal;
   }
 
   bool supports_angle = supports_angle_d3d || supports_angle_opengl ||
                         supports_angle_null || supports_angle_vulkan ||
                         supports_angle_swiftshader || supports_angle_metal;
 
-  gl_display->egl_angle_feature_control_supported =
-      gl_display->HasEGLClientExtension("EGL_ANGLE_feature_control");
-
-  gl_display->egl_angle_display_power_preference_supported =
-      gl_display->HasEGLClientExtension("EGL_ANGLE_display_power_preference");
-
-  gl_display->egl_angle_platform_angle_device_id_supported =
-      gl_display->HasEGLClientExtension("EGL_ANGLE_platform_angle_device_id");
-
   std::vector<DisplayType> init_displays;
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   GetEGLInitDisplays(supports_angle_d3d, supports_angle_opengl,
@@ -1408,7 +1317,8 @@
 
   std::vector<EGLint> egl_window_attributes;
 
-  if (display_->egl_window_fixed_size_supported && enable_fixed_size_angle_) {
+  if (display_->ext->b_EGL_ANGLE_window_fixed_size &&
+      enable_fixed_size_angle_) {
     egl_window_attributes.push_back(EGL_FIXED_SIZE_ANGLE);
     egl_window_attributes.push_back(EGL_TRUE);
     egl_window_attributes.push_back(EGL_WIDTH);
@@ -1422,7 +1332,7 @@
     egl_window_attributes.push_back(EGL_TRUE);
   }
 
-  if (display_->egl_surface_orientation_supported) {
+  if (display_->ext->b_EGL_ANGLE_surface_orientation) {
     EGLint attrib;
     eglGetConfigAttrib(display_->GetDisplay(), GetConfig(),
                        EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE, &attrib);
@@ -1443,7 +1353,7 @@
       // Note that COLORSPACE_LINEAR refers to the sRGB color space, but
       // without opting into sRGB blending. It is equivalent to
       // COLORSPACE_SRGB with Disable(FRAMEBUFFER_SRGB).
-      if (display_->egl_khr_colorspace) {
+      if (display_->ext->b_EGL_KHR_gl_colorspace) {
         egl_window_attributes.push_back(EGL_GL_COLORSPACE_KHR);
         egl_window_attributes.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
       }
@@ -1457,15 +1367,16 @@
       // with the P3 gamut instead of the the sRGB gamut.
       // COLORSPACE_DISPLAY_P3_LINEAR has a linear transfer function, and is
       // intended for use with 16-bit formats.
-      bool p3_supported = display_->egl_ext_colorspace_display_p3 ||
-                          display_->egl_ext_colorspace_display_p3_passthrough;
-      if (display_->egl_khr_colorspace && p3_supported) {
+      bool p3_supported =
+          display_->ext->b_EGL_EXT_gl_colorspace_display_p3 ||
+          display_->ext->b_EGL_EXT_gl_colorspace_display_p3_passthrough;
+      if (display_->ext->b_EGL_KHR_gl_colorspace && p3_supported) {
         egl_window_attributes.push_back(EGL_GL_COLORSPACE_KHR);
         // Chrome relied on incorrect Android behavior when dealing with P3 /
         // framebuffer_srgb interactions. This behavior was fixed in Q, which
         // causes invalid Chrome rendering. To achieve Android-P behavior in Q+,
         // use EGL_GL_COLORSPACE_P3_PASSTHROUGH_EXT where possible.
-        if (display_->egl_ext_colorspace_display_p3_passthrough) {
+        if (display_->ext->b_EGL_EXT_gl_colorspace_display_p3_passthrough) {
           egl_window_attributes.push_back(
               EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT);
         } else {
@@ -2091,7 +2002,7 @@
 
   // Enable robust resource init when using SwANGLE
   if (IsSoftwareGLImplementation(GetGLImplementationParts()) &&
-      display_->IsRobustResourceInitSupported()) {
+      display_->ext->b_EGL_ANGLE_robust_resource_initialization) {
     pbuffer_attribs.push_back(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE);
     pbuffer_attribs.push_back(EGL_TRUE);
   }
diff --git a/ui/gl/gl_utils.cc b/ui/gl/gl_utils.cc
index c98a7cd..dffa2e5 100644
--- a/ui/gl/gl_utils.cc
+++ b/ui/gl/gl_utils.cc
@@ -104,11 +104,11 @@
   GLDisplayEGL* display = gl::GLSurfaceEGL::GetGLDisplayEGL();
   // Using the passthrough command buffer requires that specific ANGLE
   // extensions are exposed
-  return display->IsCreateContextBindGeneratesResourceSupported() &&
-         display->IsCreateContextWebGLCompatabilitySupported() &&
-         display->IsRobustResourceInitSupported() &&
-         display->IsDisplayTextureShareGroupSupported() &&
-         display->IsCreateContextClientArraysSupported();
+  return display->ext->b_EGL_CHROMIUM_create_context_bind_generates_resource &&
+         display->ext->b_EGL_ANGLE_create_context_webgl_compatibility &&
+         display->ext->b_EGL_ANGLE_robust_resource_initialization &&
+         display->ext->b_EGL_ANGLE_display_texture_share_group &&
+         display->ext->b_EGL_ANGLE_create_context_client_arrays;
 #else
   // The passthrough command buffer is only supported on top of ANGLE/EGL
   return false;
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
index 43cb0c2..60b3bfa 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -45,9 +45,9 @@
       window_(std::move(window)),
       widget_(widget),
       has_implicit_external_sync_(
-          GetGLDisplayEGL()->HasEGLExtension("EGL_ARM_implicit_external_sync")),
+          GetGLDisplayEGL()->ext->b_EGL_ARM_implicit_external_sync),
       has_image_flush_external_(
-          GetGLDisplayEGL()->HasEGLExtension("EGL_EXT_image_flush_external")) {
+          GetGLDisplayEGL()->ext->b_EGL_EXT_image_flush_external) {
   surface_factory_->RegisterSurface(window_->widget(), this);
   supports_plane_gpu_fences_ = window_->SupportsGpuFences();
   unsubmitted_frames_.push_back(std::make_unique<PendingFrame>());
diff --git a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
index ebaf402..ae16deb 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
@@ -16,6 +16,7 @@
 #include "ui/gfx/geometry/rrect_f.h"
 #include "ui/gfx/linux/drm_util_linux.h"
 #include "ui/gfx/overlay_priority_hint.h"
+#include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_surface_egl.h"
 #include "ui/ozone/platform/wayland/common/wayland_overlay_config.h"
 #include "ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h"
@@ -297,10 +298,9 @@
 #if defined(WAYLAND_GBM)
 GbmDevice* WaylandBufferManagerGpu::GetGbmDevice() {
   // Wayland won't support wl_drm or zwp_linux_dmabuf without this extension.
-  if (!supports_dmabuf_ ||
-      (!gl::GLSurfaceEGL::GetGLDisplayEGL()->HasEGLExtension(
-           "EGL_EXT_image_dma_buf_import") &&
-       !use_fake_gbm_device_for_test_)) {
+  if (!supports_dmabuf_ || (!gl::GLSurfaceEGL::GetGLDisplayEGL()
+                                 ->ext->b_EGL_EXT_image_dma_buf_import &&
+                            !use_fake_gbm_device_for_test_)) {
     supports_dmabuf_ = false;
     return nullptr;
   }
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html b/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html
index eb6bfd8..34c7abb 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html
+++ b/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html
@@ -67,7 +67,8 @@
           </div>
         </div>
         <cr-button id="changePinButton" on-click="onChangePinTap_"
-            hidden$="[[!showChangePinButton_(deviceState, isActiveSim_)]]"
+            hidden$="[[!showChangePinButton_(deviceState, isActiveSim_,
+                isSimPinLockRestricted_)]]"
             disabled="[[disabled]]">
           [[i18n('networkSimChangePin')]]
         </cr-button>
@@ -82,7 +83,8 @@
           <div class="separator"></div>
         </template>
         <cr-toggle id="simLockButton"
-            disabled="[[isSimLockButtonDisabled_(disabled, isActiveSim_)]]"
+            disabled="[[isSimLockButtonDisabled_(disabled, isActiveSim_,
+                isSimPinLockRestricted_, lockEnabled_)]]"
             on-change="onSimLockEnabledChange_" checked="{{lockEnabled_}}"
             aria-labelledby="pinRequiredLabel pinRequiredSublabel">
         </cr-toggle>
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_siminfo.js b/ui/webui/resources/cr_components/chromeos/network/network_siminfo.js
index 88c34eb..76bcb6e 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_siminfo.js
+++ b/ui/webui/resources/cr_components/chromeos/network/network_siminfo.js
@@ -42,6 +42,9 @@
       value: null,
     },
 
+    /** @type {!chromeos.networkConfig.mojom.GlobalPolicy|undefined} */
+    globalPolicy: Object,
+
     disabled: {
       type: Boolean,
       value: false,
@@ -96,6 +99,23 @@
       computed: 'computeState_(networkState, deviceState, deviceState.*,' +
           'isActiveSim_)',
     },
+
+    /** @private {boolean} */
+    isSimLockPolicyEnabled_: {
+      type: Boolean,
+      value() {
+        return loadTimeData.valueExists('isSimLockPolicyEnabled') &&
+            loadTimeData.getBoolean('isSimLockPolicyEnabled');
+      }
+    },
+
+    /** @private {boolean} */
+    isSimPinLockRestricted_: {
+      type: Boolean,
+      value: false,
+      computed: 'computeIsSimPinLockRestricted_(isSimLockPolicyEnabled_,' +
+          'globalPolicy, globalPolicy.*, lockEnabled_)',
+    },
   },
 
   /** @private {boolean|undefined} */
@@ -250,6 +270,10 @@
    * @private
    */
   showChangePinButton_() {
+    if (this.isSimPinLockRestricted_) {
+      return false;
+    }
+
     if (!this.deviceState || !this.deviceState.simLockStatus) {
       return false;
     }
@@ -262,6 +286,12 @@
    * @private
    */
   isSimLockButtonDisabled_() {
+    // If SIM PIN locking is restricted by admin, and the SIM does not have SIM
+    // PIN lock enabled, users should not be able to enable PIN locking.
+    if (this.isSimPinLockRestricted_ && !this.lockEnabled_) {
+      return true;
+    }
+
     return this.disabled || !this.isActiveSim_;
   },
 
@@ -286,6 +316,15 @@
   },
 
   /**
+   * @return {boolean}
+   * @private
+   */
+  computeIsSimPinLockRestricted_() {
+    return this.isSimLockPolicyEnabled_ && !!this.globalPolicy &&
+        !this.globalPolicy.allowCellularSimLock;
+  },
+
+  /**
    * @param {!State} state1
    * @param {!State} state2
    * @return {boolean} Whether state1 is the same as state2.