diff --git a/DEPS b/DEPS
index b60c0d73..c7dd75f 100644
--- a/DEPS
+++ b/DEPS
@@ -304,7 +304,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'src_internal_revision': '4d87df689432aab83f5fad3a0b3230fe78dd7a4e',
+  'src_internal_revision': 'e635ef2a5ee69af88e8d02569f2505fe336271a8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
@@ -383,7 +383,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling chromium_variations
   # and whatever else without interference from each other.
-  'chromium_variations_revision': '2647e3fafdacf32cd37e23e40a42ffa5618cb2f6',
+  'chromium_variations_revision': '3097b9057e203656efcd2f6f04eb24198d0c5ec7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
@@ -1003,7 +1003,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '6812543ef91ca93164dcce5ff24ef746ae4467fd',
+    'cdaa3f151a155c0c0a3e907ea53fc968343d7c98',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -2172,7 +2172,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '44bcaa233f372acd2ef70736b602f5364a9fa378',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'b0fe794d7d9867c67625b573b1f9afd24bb38a19',
+    Var('webrtc_git') + '/src.git' + '@' + '76c02aff4c76cc2d47c0a975333789978986e2b9',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -2295,7 +2295,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'sIzLmrsNMFPqFQxmo16fU3Lv9nHDwNMYv32SwnKxgDAC',
+        'version': 'R5-H0mLHg9PRM1UJZbnfXBUWr1IfqXGDF2g5v5tV9zQC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -2306,7 +2306,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'fyVmjp4iRWzSL3BV0MB8VukyYMM1USK9Do9lkxtYOpQC',
+        'version': 'N3y9eNOWy_Nb27FfOEfenROiIbDL_q1LlijnR2SqhOQC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -2339,7 +2339,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'Y684ZpPCy_DEFR-_W53iDztjCLmzjj3eqrAx71O4BwQC',
+        'version': 'Wr9MyBLNETTVeHzXpazFoF81V7nKatHC7TKKlvc6TXQC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -4409,7 +4409,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        'de983f7b4091b42ba405f8d75909e47d4bf7c0d8',
+        'a4bca5f99ed1d6460e444e82d9359ef57826fa0b',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/ash/strings/ash_strings_ur.xtb b/ash/strings/ash_strings_ur.xtb
index 2388136..8fa5b39f 100644
--- a/ash/strings/ash_strings_ur.xtb
+++ b/ash/strings/ash_strings_ur.xtb
@@ -199,7 +199,7 @@
 <translation id="1736898441010944794">"<ph name="NAME" />" بلوٹوتھ آلات کے لیے مرئی ہے۔</translation>
 <translation id="1737078180382804488">اپنے فون کی اطلاعات دیکھنے کے سیٹ اپ کو برخاست کریں</translation>
 <translation id="174102739345480129">مارکر آف ہے۔</translation>
-<translation id="1743570585616704562">تسلیم شدہ نہیں ہے</translation>
+<translation id="1743570585616704562">شناخت نہیں ہو سکی</translation>
 <translation id="1743927604032653654"><ph name="NOTIFICATION_TITLE" /> اطلاع کو سُکیڑیں</translation>
 <translation id="1746730358044914197">ان پٹ کے طریقے آپ کے منتظم کے ذریعے کنفیگر کئے جاتے ہیں۔</translation>
 <translation id="1747336645387973286">آخری تاریخ <ph name="DUE_DATE" /></translation>
diff --git a/ash/webui/camera_app_ui/document_scanner_service_host.cc b/ash/webui/camera_app_ui/document_scanner_service_host.cc
index f8d2761..eb5b130e 100644
--- a/ash/webui/camera_app_ui/document_scanner_service_host.cc
+++ b/ash/webui/camera_app_ui/document_scanner_service_host.cc
@@ -5,6 +5,7 @@
 #include "ash/webui/camera_app_ui/document_scanner_service_host.h"
 
 #include "chromeos/ash/components/mojo_service_manager/connection.h"
+#include "third_party/cros_system_api/mojo/service_constants.h"
 
 namespace ash {
 
@@ -30,8 +31,7 @@
   if (ash::mojo_service_manager::IsServiceManagerBound()) {
     auto* proxy = ash::mojo_service_manager::GetServiceManagerProxy();
     proxy->Register(
-        // TODO(b/333927344): Add service name to chromeos::mojo_services.
-        /*service_name=*/"CrosDocumentScanner",
+        /*service_name=*/chromeos::mojo_services::kCrosDocumentScanner,
         provider_receiver_.BindNewPipeAndPassRemote());
   }
 }
diff --git a/ash/webui/diagnostics_ui/resources/realtime_cpu_chart.ts b/ash/webui/diagnostics_ui/resources/realtime_cpu_chart.ts
index 03ff010..80ec7e5 100644
--- a/ash/webui/diagnostics_ui/resources/realtime_cpu_chart.ts
+++ b/ash/webui/diagnostics_ui/resources/realtime_cpu_chart.ts
@@ -14,6 +14,14 @@
 
 import {getTemplate} from './realtime_cpu_chart.html.js';
 
+export interface ChartPadding {
+  top: number;
+  right: number;
+  bottom: number;
+  left: number;
+  tick: number;
+}
+
 const RealtimeCpuChartElementBase = I18nMixin(PolymerElement);
 
 /**
@@ -110,8 +118,7 @@
   private frameDuration: number;
   private width: number;
   private height: number;
-  private padding:
-      {top: number, right: number, bottom: number, left: number, tick: number};
+  private padding: ChartPadding;
   private graphWidth: number;
   private graphHeight: number;
   // Helper function to map range of x coordinates to graph width.
@@ -321,6 +328,14 @@
   private getPercentageLabel(value: number): string {
     return loadTimeData.getStringF('percentageLabel', value);
   }
+
+  getPaddingForTesting(): ChartPadding {
+    return this.padding;
+  }
+
+  getFrameDurationForTesting(): number {
+    return this.frameDuration;
+  }
 }
 
 declare global {
diff --git a/ash/webui/diagnostics_ui/resources/routine_section.ts b/ash/webui/diagnostics_ui/resources/routine_section.ts
index 9a8aa99..3f2b7db 100644
--- a/ash/webui/diagnostics_ui/resources/routine_section.ts
+++ b/ash/webui/diagnostics_ui/resources/routine_section.ts
@@ -210,10 +210,10 @@
   hideVerticalLines: boolean;
   usingRoutineGroups: boolean;
   ignoreRoutineStatusUpdates: boolean;
-  private announcedText: string;
+  announcedText: string;
+  currentTestName: string;
   private routineStartTimeMs: number;
   private executionStatus: ExecutionProgress;
-  private currentTestName: string;
   private powerRoutineResult: PowerRoutineResult;
   private badgeType: BadgeType;
   private badgeText: string;
@@ -458,7 +458,7 @@
   /**
    * Sets status texts for remaining runtime while the routine runs.
    */
-  private setRunningStatusBadgeText(): void {
+  setRunningStatusBadgeText(): void {
     // Routines that are longer than 5 minutes are considered large
     const largeRoutine = this.routineRuntime >= 5;
 
diff --git a/chrome/VERSION b/chrome/VERSION
index 093ace4e..fed3b04 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=126
 MINOR=0
-BUILD=6474
+BUILD=6476
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
index 4581982..e8072a3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
@@ -198,8 +198,7 @@
     // Desktop windowing mode constants.
     /**
      * Whether the current activity is the top resumed activity. This is only relevant for use in
-     * the desktop windowing mode, and will typically always be true unless the current activity is
-     * in an unfocused desktop window.
+     * the desktop windowing mode, to determine the tab strip background color.
      */
     private boolean mIsTopResumedActivity;
 
@@ -836,8 +835,7 @@
     @Override
     public void onTopResumedActivityChanged(boolean isTopResumedActivity) {
         // TODO (crbug/328055199): Check if losing focus to a non-Chrome task.
-        if (!mIsLayoutOptimizationsEnabled
-                || !AppHeaderUtils.isAppInDesktopWindow(mDesktopWindowStateProvider)) return;
+        if (!mIsLayoutOptimizationsEnabled) return;
         mIsTopResumedActivity = isTopResumedActivity;
         mUpdateHost.requestUpdate();
     }
@@ -1261,8 +1259,10 @@
     }
 
     public @ColorInt int getBackgroundColor() {
-        return TabUiThemeUtil.getTabStripBackgroundColorForActivityState(
-                mContext, mIsIncognito, mIsTopResumedActivity);
+        return AppHeaderUtils.isAppInDesktopWindow(mDesktopWindowStateProvider)
+                ? TabUiThemeUtil.getTabStripBackgroundColorForActivityState(
+                        mContext, mIsIncognito, mIsTopResumedActivity)
+                : TabUiThemeUtil.getTabStripBackgroundColor(mContext, mIsIncognito);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/AppThemeColorProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/AppThemeColorProvider.java
index 04f38f50..7a2a84e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/AppThemeColorProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/AppThemeColorProvider.java
@@ -54,8 +54,7 @@
 
     /**
      * Whether the current activity is the top resumed activity. This is only relevant for use in
-     * the desktop windowing mode, and will typically always be true unless the current activity is
-     * in an unfocused desktop window.
+     * the desktop windowing mode, to determine the tint for the toolbar icons.
      */
     private boolean mIsTopResumedActivity;
 
@@ -156,7 +155,6 @@
     @Override
     public void onTopResumedActivityChanged(boolean isTopResumedActivity) {
         // TODO (crbug/328055199): Check if losing focus to a non-Chrome task.
-        if (!AppHeaderUtils.isAppInDesktopWindow(mDesktopWindowStateProvider)) return;
         mIsTopResumedActivity = isTopResumedActivity;
         updateTheme();
     }
@@ -165,6 +163,7 @@
             Context context, @BrandedColorScheme int brandedColorScheme) {
         var iconTint = ThemeUtils.getThemedToolbarIconTint(context, brandedColorScheme);
         return mActivityLifecycleDispatcher == null
+                        || !AppHeaderUtils.isAppInDesktopWindow(mDesktopWindowStateProvider)
                 ? iconTint
                 : ThemeUtils.getThemedToolbarIconTintForActivityState(
                         context, brandedColorScheme, mIsTopResumedActivity);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/desktop_windowing/AppHeaderCoordinatorBrowserTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/desktop_windowing/AppHeaderCoordinatorBrowserTest.java
index 4506756..12e7576 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/desktop_windowing/AppHeaderCoordinatorBrowserTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/desktop_windowing/AppHeaderCoordinatorBrowserTest.java
@@ -10,6 +10,7 @@
 
 import static org.chromium.chrome.browser.desktop_windowing.AppHeaderCoordinator.INSTANCE_STATE_KEY_IS_APP_IN_UNFOCUSED_DW;
 
+import android.content.Intent;
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.os.Build;
@@ -19,6 +20,7 @@
 import androidx.annotation.RequiresApi;
 import androidx.core.view.WindowInsetsCompat;
 import androidx.test.filters.MediumTest;
+import androidx.test.runner.lifecycle.Stage;
 
 import org.hamcrest.Matchers;
 import org.junit.Before;
@@ -29,6 +31,7 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.test.util.ApplicationTestUtils;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
@@ -43,12 +46,14 @@
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.hub.HubLayout;
+import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.tasks.tab_management.TabSwitcherLayout;
 import org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper;
 import org.chromium.chrome.browser.theme.ThemeUtils;
 import org.chromium.chrome.browser.toolbar.ToolbarFeatures;
 import org.chromium.chrome.browser.toolbar.top.ToolbarTablet;
 import org.chromium.chrome.browser.ui.desktop_windowing.AppHeaderState;
+import org.chromium.chrome.browser.ui.desktop_windowing.AppHeaderUtils;
 import org.chromium.chrome.browser.ui.theme.BrandedColorScheme;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
@@ -105,7 +110,7 @@
     @MediumTest
     public void testTabStripHeightChangeForTabStripLayoutOptimization() {
         ChromeTabbedActivity activity = mActivityTestRule.getActivity();
-        triggerDesktopWindowingModeChange(true);
+        triggerDesktopWindowingModeChange(activity, true);
 
         CriteriaHelper.pollUiThread(
                 () -> {
@@ -143,7 +148,7 @@
         ChromeTabbedActivity activity = mActivityTestRule.getActivity();
 
         // Enter desktop windowing mode.
-        triggerDesktopWindowingModeChange(true);
+        triggerDesktopWindowingModeChange(activity, true);
         // Enter the tab switcher.
         TabUiTestHelper.enterTabSwitcher(activity);
 
@@ -166,7 +171,7 @@
                 0f);
 
         // Exit desktop windowing mode.
-        triggerDesktopWindowingModeChange(false);
+        triggerDesktopWindowingModeChange(activity, false);
         assertEquals(
                 "Tab switcher container view y-offset should be zero.",
                 0,
@@ -200,7 +205,7 @@
                 0.0);
 
         // Enter desktop windowing mode while the tab switcher is visible.
-        triggerDesktopWindowingModeChange(true);
+        triggerDesktopWindowingModeChange(activity, true);
 
         assertTrue(
                 "Tab switcher container view y-offset should be non-zero.",
@@ -212,7 +217,7 @@
                 0f);
 
         // Exit desktop windowing mode.
-        triggerDesktopWindowingModeChange(false);
+        triggerDesktopWindowingModeChange(activity, false);
         assertEquals(
                 "Tab switcher container view y-offset should be zero.",
                 0,
@@ -229,7 +234,7 @@
         ChromeTabbedActivity activity = mActivityTestRule.getActivity();
 
         // Enter desktop windowing mode.
-        triggerDesktopWindowingModeChange(true);
+        triggerDesktopWindowingModeChange(activity, true);
         // Enter the tab switcher.
         TabUiTestHelper.enterTabSwitcher(activity);
 
@@ -253,7 +258,7 @@
                 });
 
         // Exit desktop windowing mode.
-        triggerDesktopWindowingModeChange(false);
+        triggerDesktopWindowingModeChange(activity, false);
         CriteriaHelper.pollUiThread(
                 () -> {
                     Criteria.checkThat(
@@ -286,7 +291,7 @@
         assertEquals("Tab switcher container view top margin should be zero.", 0, params.topMargin);
 
         // Enter desktop windowing mode while the tab switcher is visible.
-        triggerDesktopWindowingModeChange(true);
+        triggerDesktopWindowingModeChange(activity, true);
 
         CriteriaHelper.pollUiThread(
                 () -> {
@@ -303,7 +308,7 @@
                 });
 
         // Exit desktop windowing mode.
-        triggerDesktopWindowingModeChange(false);
+        triggerDesktopWindowingModeChange(activity, false);
         CriteriaHelper.pollUiThread(
                 () -> {
                     Criteria.checkThat(
@@ -316,28 +321,62 @@
 
     @Test
     @MediumTest
-    public void testRecreateActivityInUnfocusedWindow() {
-        ChromeTabbedActivity activity = mActivityTestRule.getActivity();
+    public void testRecreateActivitiesInDesktopWindow() {
+        // Assume that the current activity enters desktop windowing mode.
+        ChromeTabbedActivity firstActivity = mActivityTestRule.getActivity();
+        AppHeaderUtils.setAppInDesktopWindowForTesting(true);
+        firstActivity = ApplicationTestUtils.recreateActivity(firstActivity);
+        triggerDesktopWindowingModeChange(firstActivity, true);
 
-        // Assume that the current activity lost focus in desktop windowing mode.
-        triggerDesktopWindowingModeChange(true);
-        TestThreadUtils.runOnUiThreadBlocking(() -> activity.onTopResumedActivityChanged(false));
+        // Create a new (desktop) window, that should gain focus and cause the first activity to
+        // lose focus.
+        Intent intent =
+                MultiWindowUtils.createNewWindowIntent(
+                        firstActivity.getApplicationContext(),
+                        MultiWindowUtils.INVALID_INSTANCE_ID,
+                        true,
+                        false,
+                        true);
+        ChromeTabbedActivity secondActivity =
+                ApplicationTestUtils.waitForActivityWithClass(
+                        ChromeTabbedActivity.class,
+                        Stage.RESUMED,
+                        () -> ContextUtils.getApplicationContext().startActivity(intent));
+        triggerDesktopWindowingModeChange(secondActivity, true);
 
-        // Trigger activity recreation.
-        ChromeTabbedActivity recreatedActivity = ApplicationTestUtils.recreateActivity(activity);
+        // Trigger activity recreation in desktop windowing mode (an app theme change for eg. would
+        // trigger this).
+        firstActivity = ApplicationTestUtils.recreateActivity(firstActivity);
+        secondActivity = ApplicationTestUtils.recreateActivity(secondActivity);
 
+        // Activity recreation will send an #onTopResumedActivityChanged(false) signal as the
+        // activity is stopping, so both activities will be considered unfocused.
         assertTrue(
                 "Saved instance state bundle should hold correct desktop window focus state.",
-                recreatedActivity
+                firstActivity
+                        .getSavedInstanceState()
+                        .getBoolean(INSTANCE_STATE_KEY_IS_APP_IN_UNFOCUSED_DW));
+        assertTrue(
+                "Saved instance state bundle should hold correct desktop window focus state.",
+                secondActivity
                         .getSavedInstanceState()
                         .getBoolean(INSTANCE_STATE_KEY_IS_APP_IN_UNFOCUSED_DW));
 
-        // This verification relies on the assumption that the saved instance state value is
-        // injected into and used by the ThemeColorProvider at startup before the call to
-        // Activity#onTopResumedActivityChanged(true) in the instrumentation, that would update the
-        // value of DesktopWindowStateProvider#mIsInUnfocusedDesktopWindow. This can be removed if
-        // it causes test breakage since we have unit test coverage for the implementation.
-        verifyToolbarIconTints(recreatedActivity, false, true);
+        // As |secondActivity| regains focus after recreation, it will receive an
+        // #onTopResumedActivityChanged(true) signal, that should re-apply the correct top Chrome
+        // colors. |firstActivity| should start with the unfocused window colors, based on the saved
+        // instance state value.
+        verifyToolbarIconTints(
+                firstActivity, /* isActivityFocused= */ false, /* isInDesktopWindow= */ true);
+        verifyToolbarIconTints(
+                secondActivity, /* isActivityFocused= */ true, /* isInDesktopWindow= */ true);
+
+        // TODO(aishwaryarj): Verify tab strip background color too. This is currently failing on
+        // the CQ bot.
+
+        // Exit desktop windowing mode and finish the second activity.
+        AppHeaderUtils.setAppInDesktopWindowForTesting(false);
+        secondActivity.finish();
     }
 
     private void doTestOnTopResumedActivityChanged(
@@ -354,7 +393,7 @@
                 });
 
         // Assume that the current activity lost focus in desktop windowing mode.
-        triggerDesktopWindowingModeChange(true);
+        triggerDesktopWindowingModeChange(activity, true);
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> activity.onTopResumedActivityChanged(isActivityFocused));
 
@@ -362,14 +401,16 @@
         verifyToolbarIconTints(activity, isActivityFocused, isInDesktopWindow);
     }
 
-    public void verifyToolbarIconTints(
+    private void verifyToolbarIconTints(
             ChromeTabbedActivity activity, boolean isActivityFocused, boolean isInDesktopWindow) {
         var omniboxIconTint =
-                ThemeUtils.getThemedToolbarIconTint(activity, BrandedColorScheme.APP_DEFAULT);
+                ThemeUtils.getThemedToolbarIconTint(activity, BrandedColorScheme.APP_DEFAULT)
+                        .getDefaultColor();
         var nonOmniboxIconTint =
                 isInDesktopWindow
                         ? ThemeUtils.getThemedToolbarIconTintForActivityState(
-                                activity, BrandedColorScheme.APP_DEFAULT, isActivityFocused)
+                                        activity, BrandedColorScheme.APP_DEFAULT, isActivityFocused)
+                                .getDefaultColor()
                         : omniboxIconTint;
 
         CriteriaHelper.pollUiThread(
@@ -379,31 +420,37 @@
                                     activity.getToolbarManager().getToolbarLayoutForTesting();
                     Criteria.checkThat(
                             "Home button tint is incorrect",
-                            toolbarTablet.getHomeButton().getImageTintList(),
+                            toolbarTablet.getHomeButton().getImageTintList().getDefaultColor(),
                             Matchers.is(nonOmniboxIconTint));
                     Criteria.checkThat(
                             "Tab switcher icon tint is incorrect.",
-                            toolbarTablet.getTabSwitcherButton().getImageTintList(),
+                            toolbarTablet
+                                    .getTabSwitcherButton()
+                                    .getImageTintList()
+                                    .getDefaultColor(),
                             Matchers.is(nonOmniboxIconTint));
                     Criteria.checkThat(
                             "App menu button tint is incorrect.",
                             ((ImageButton) activity.getToolbarManager().getMenuButtonView())
-                                    .getImageTintList(),
+                                    .getImageTintList()
+                                    .getDefaultColor(),
                             Matchers.is(nonOmniboxIconTint));
                     Criteria.checkThat(
                             "Bookmark button tint is incorrect.",
-                            toolbarTablet.getBookmarkButtonForTesting().getImageTintList(),
+                            toolbarTablet
+                                    .getBookmarkButtonForTesting()
+                                    .getImageTintList()
+                                    .getDefaultColor(),
                             Matchers.is(omniboxIconTint));
                 });
     }
 
-    private void triggerDesktopWindowingModeChange(boolean isInDesktopWindow) {
+    private void triggerDesktopWindowingModeChange(
+            ChromeTabbedActivity activity, boolean isInDesktopWindow) {
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> {
                     var appHeaderStateProvider =
-                            mActivityTestRule
-                                    .getActivity()
-                                    .getRootUiCoordinatorForTesting()
+                            activity.getRootUiCoordinatorForTesting()
                                     .getDesktopWindowStateProvider();
                     setupAppHeaderRects(isInDesktopWindow);
                     var appHeaderState =
@@ -411,6 +458,7 @@
                                     mWindowRect, mWidestUnoccludedRect, isInDesktopWindow);
                     ((AppHeaderCoordinator) appHeaderStateProvider)
                             .setStateForTesting(isInDesktopWindow, appHeaderState);
+                    AppHeaderUtils.setAppInDesktopWindowForTesting(isInDesktopWindow);
                 });
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManagerTest.java
index 9b42d7c..18b792f 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManagerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManagerTest.java
@@ -301,6 +301,9 @@
     @Test
     public void testGetBackgroundColor_ActivityStartsInUnfocusedDesktopWindow() {
         // Assume that the app starts in an unfocused desktop window.
+        var appHeaderState =
+                new AppHeaderState(new Rect(), new Rect(), /* isInDesktopWindow= */ true);
+        when(mDesktopWindowStateProvider.getAppHeaderState()).thenReturn(appHeaderState);
         when(mDesktopWindowStateProvider.isInUnfocusedDesktopWindow()).thenReturn(true);
         initializeTest();
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/AppThemeColorProviderUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/AppThemeColorProviderUnitTest.java
index a4957239..4c31eafd 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/AppThemeColorProviderUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/AppThemeColorProviderUnitTest.java
@@ -6,9 +6,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -71,6 +68,7 @@
     @Test
     public void appStartsInUnfocusedDesktopWindow() {
         // Initialize.
+        when(mAppHeaderState.isInDesktopWindow()).thenReturn(true);
         when(mDesktopWindowStateProvider.isInUnfocusedDesktopWindow()).thenReturn(true);
         initThemeColorProvider();
 
@@ -106,8 +104,9 @@
         var tint = ThemeUtils.getThemedToolbarIconTint(mContext, brandedColorScheme);
 
         assertEquals("Default tint is not correct.", tint, mAppThemeColorProvider.getTint());
-        assertNull(
-                "Activity focus tint should not be set.",
+        assertEquals(
+                "Activity focus tint is not correct.",
+                tint,
                 mAppThemeColorProvider.getActivityFocusTint());
 
         // Assume that the activity gained focus.
@@ -115,11 +114,12 @@
 
         // Verify.
         assertEquals("Default tint is not correct.", tint, mAppThemeColorProvider.getTint());
-        assertNull(
-                "Activity focus tint should not be set.",
+        assertEquals(
+                "Activity focus tint is not correct.",
+                tint,
                 mAppThemeColorProvider.getActivityFocusTint());
 
-        verify(mTintObserver, never()).onTintChanged(any(), any(), anyInt());
+        verify(mTintObserver).onTintChanged(tint, tint, brandedColorScheme);
     }
 
     @Test
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt
index efbb2f83..404161c 100644
--- a/chrome/android/profiles/arm.newest.txt
+++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-126.0.6472.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-arm-126.0.6475.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 59cbf113..981059b 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-126.0.6472.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-126.0.6474.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/password_manager_ui_strings.grdp b/chrome/app/password_manager_ui_strings.grdp
index 8bf245b..5ed0d8ec 100644
--- a/chrome/app/password_manager_ui_strings.grdp
+++ b/chrome/app/password_manager_ui_strings.grdp
@@ -675,11 +675,8 @@
   <message name="IDS_PASSWORD_MANAGER_UI_DELETE_PASSKEY_CONFIRMATION_DESCRIPTION" desc="Description of a dialog shown when the user clicks a button to delete a passkey. For consistency, the word 'passkey' is in the glossary with translations already suggested.">
     Your <ph name="DOMAIN_LINK">$1<ex>&lt;a href="https://google.ca" target="_blank"&gt;google.ca&lt;/a&gt;</ex></ph> account won't be deleted
   </message>
-  <message name="IDS_PASSWORD_MANAGER_UI_PASSKEY_MANAGEMENT_INFO_LABEL" desc="Information label shown when viewing a passkey on Chrome's password manager. This label serves two purposes: to identify the credential as a passkey (as opposed to a password), and to educate the user that they'll need their mobile device to sign in with it. For consistency, the word 'passkey' is in the glossary with translations already suggested.">
-    You created a passkey for this site. You need your mobile device to sign in.
-  </message>
-  <message name="IDS_PASSWORD_MANAGER_UI_PASSKEY_MANAGEMENT_WITH_PIN_INFO_LABEL" desc="Information label shown when viewing a passkey on Chrome's password manager. This label identifies the credential as a passkey (as opposed to a password). For consistency, the word 'passkey' is in the glossary with translations already suggested.">
-    You created a passkey for this site
+  <message name="IDS_PASSWORD_MANAGER_UI_PASSKEY_MANAGEMENT_INFO_LABEL" desc="Information label shown when viewing a passkey on Chrome's password manager. For consistency, the word 'passkey' is in the glossary with translations already suggested.">
+    You created this passkey on <ph name="DATE">$1<ex>2024-02-01</ex></ph>
   </message>
   <message name="IDS_PASSKEYS_MANAGER_UI_UNENROLL_TITLE" desc="This string appears within Google Password Manager settings. It means the user can remove the device’s access to a sign-in method called passkeys. “Your passkeys” refers to passkeys the user saved on a different device.">
     Remove access to your passkeys on this device
diff --git a/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSKEY_MANAGEMENT_INFO_LABEL.png.sha1 b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSKEY_MANAGEMENT_INFO_LABEL.png.sha1
index 368b3f4..4a5b57e 100644
--- a/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSKEY_MANAGEMENT_INFO_LABEL.png.sha1
+++ b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSKEY_MANAGEMENT_INFO_LABEL.png.sha1
@@ -1 +1 @@
-6ecd65cd81c74c71571ffd5537140dbfd329382a
\ No newline at end of file
+8644b2078297d80ec07dfa58d10b95dfd69ee576
\ No newline at end of file
diff --git a/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSKEY_MANAGEMENT_WITH_PIN_INFO_LABEL.png.sha1 b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSKEY_MANAGEMENT_WITH_PIN_INFO_LABEL.png.sha1
deleted file mode 100644
index a748ecc..0000000
--- a/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSKEY_MANAGEMENT_WITH_PIN_INFO_LABEL.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-31bf19220773c8f5af9a125fd4caf487a8ea563b
\ No newline at end of file
diff --git a/chrome/browser/apps/app_service/publishers/arc_apps.cc b/chrome/browser/apps/app_service/publishers/arc_apps.cc
index 96053f80..b3e22f3 100644
--- a/chrome/browser/apps/app_service/publishers/arc_apps.cc
+++ b/chrome/browser/apps/app_service/publishers/arc_apps.cc
@@ -477,8 +477,13 @@
 apps::InstallReason GetInstallReason(const ArcAppListPrefs* prefs,
                                      const std::string& app_id,
                                      const ArcAppListPrefs::AppInfo& app_info) {
+  if (prefs->IsControlledByPolicy(app_info.package_name)) {
+    return apps::InstallReason::kPolicy;
+  }
+
   // Sticky represents apps that cannot be uninstalled and are installed by the
-  // system.
+  // system. Policy installed apps are also considered sticky, so kPolicy must
+  // be first.
   if (app_info.sticky) {
     return apps::InstallReason::kSystem;
   }
@@ -491,10 +496,6 @@
     return apps::InstallReason::kDefault;
   }
 
-  if (prefs->IsControlledByPolicy(app_info.package_name)) {
-    return apps::InstallReason::kPolicy;
-  }
-
   return apps::InstallReason::kUser;
 }
 
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index 74ed07aa..ebda0531 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -1293,8 +1293,8 @@
     "file_system_provider/content_cache/content_lru_cache.h",
     "file_system_provider/content_cache/context_database.cc",
     "file_system_provider/content_cache/context_database.h",
-    "file_system_provider/content_cache/local_file.cc",
-    "file_system_provider/content_cache/local_file.h",
+    "file_system_provider/content_cache/local_fd.cc",
+    "file_system_provider/content_cache/local_fd.h",
     "file_system_provider/extension_provider.cc",
     "file_system_provider/extension_provider.h",
     "file_system_provider/fileapi/backend_delegate.cc",
@@ -5717,7 +5717,7 @@
     "file_system_provider/content_cache/content_cache_impl_unittest.cc",
     "file_system_provider/content_cache/content_lru_cache_unittest.cc",
     "file_system_provider/content_cache/context_database_unittest.cc",
-    "file_system_provider/content_cache/local_file_unittest.cc",
+    "file_system_provider/content_cache/local_fd_unittest.cc",
     "file_system_provider/fake_registry.cc",
     "file_system_provider/fake_registry.h",
     "file_system_provider/fileapi/buffering_file_stream_reader_unittest.cc",
diff --git a/chrome/browser/ash/file_manager/indexing/file_index_service_unittest.cc b/chrome/browser/ash/file_manager/indexing/file_index_service_unittest.cc
index 4a69052..b0b658c 100644
--- a/chrome/browser/ash/file_manager/indexing/file_index_service_unittest.cc
+++ b/chrome/browser/ash/file_manager/indexing/file_index_service_unittest.cc
@@ -8,9 +8,9 @@
 #include <string_view>
 #include <vector>
 
-#include "base/run_loop.h"
 #include "base/strings/strcat.h"
 #include "base/test/bind.h"
+#include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 #include "chrome/browser/ash/file_manager/indexing/file_info.h"
 #include "chrome/browser/ash/file_manager/indexing/query.h"
@@ -58,14 +58,17 @@
         bar_url_(MakeLocalURL("bar.txt")),
         task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
 
-  void SetUp() override {
+  void SetUp() override { CreateIndex(); }
+
+  void TearDown() override { DestroyIndex(); }
+
+  // Convenience methods that convert asynchronous results to synchronous.
+  void CreateIndex() {
     index_service_ = std::make_unique<FileIndexService>(&profile_);
     ASSERT_EQ(Init(), OpResults::kSuccess);
   }
 
-  void TearDown() override { index_service_.reset(); }
-
-  // Convenience methods that convert asynchronous results to synchronous.
+  void DestroyIndex() { index_service_.reset(); }
 
   OpResults Init() {
     base::RunLoop run_loop;
@@ -163,6 +166,19 @@
 
 typedef std::vector<FileInfo> FileInfoList;
 
+TEST_F(FileIndexServiceTest, InitializeTwice) {
+  ASSERT_EQ(Init(), OpResults::kSuccess);
+}
+
+TEST_F(FileIndexServiceTest, CreateDestroyCreate) {
+  // Index is already created by SetUp(). Thus just destroy it and create.
+  // it again.
+  DestroyIndex();
+  // TODO(b:327534824): Remove the sleep statement.
+  base::PlatformThread::Sleep(base::Milliseconds(250));
+  CreateIndex();
+}
+
 TEST_F(FileIndexServiceTest, EmptySearch) {
   // Empty query on an empty index.
   EXPECT_THAT(Search(Query({})), ContainsFiles(FileInfoList{}));
diff --git a/chrome/browser/ash/file_manager/indexing/posting_list_table.cc b/chrome/browser/ash/file_manager/indexing/posting_list_table.cc
index b52d00b..bfc591b 100644
--- a/chrome/browser/ash/file_manager/indexing/posting_list_table.cc
+++ b/chrome/browser/ash/file_manager/indexing/posting_list_table.cc
@@ -32,8 +32,8 @@
 // term.
 static constexpr char kCreatePostingIndexQuery[] =
     // clang-format off
-    "CREATE INDEX " POSTING_LIST_INDEX " ON " POSTING_LIST_TABLE "("
-    TERM_ID ")";
+    "CREATE INDEX IF NOT EXISTS " POSTING_LIST_INDEX " ON "
+    POSTING_LIST_TABLE "(" TERM_ID ")";
 // clang-format on
 
 // The statement that creates an plain index from URL IDs to term IDs.
@@ -41,7 +41,8 @@
 // given URL ID (and thus, a file).
 static constexpr char kCreateUrlIndexQuery[] =
     // clang-format off
-    "CREATE INDEX " URL_ID_INDEX " ON posting_list_table(" URL_ID ")";
+    "CREATE INDEX IF NOT EXISTS " URL_ID_INDEX " ON "
+    POSTING_LIST_TABLE "(" URL_ID ")";
 // clang-format on
 
 // The statement used to insert a new association between the term ID
diff --git a/chrome/browser/ash/file_manager/indexing/sql_storage.cc b/chrome/browser/ash/file_manager/indexing/sql_storage.cc
index 3433ba8..27e66e0 100644
--- a/chrome/browser/ash/file_manager/indexing/sql_storage.cc
+++ b/chrome/browser/ash/file_manager/indexing/sql_storage.cc
@@ -35,6 +35,7 @@
 }
 
 SqlStorage::~SqlStorage() {
+  db_.Close();
   db_.reset_error_callback();
 }
 
diff --git a/chrome/browser/ash/file_system_provider/cloud_file_system.cc b/chrome/browser/ash/file_system_provider/cloud_file_system.cc
index 0f50675..b44144d2c 100644
--- a/chrome/browser/ash/file_system_provider/cloud_file_system.cc
+++ b/chrome/browser/ash/file_system_provider/cloud_file_system.cc
@@ -11,6 +11,7 @@
 #include "base/files/file_path.h"
 #include "base/functional/bind.h"
 #include "base/logging.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/notreached.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
@@ -19,6 +20,7 @@
 #include "chrome/browser/ash/file_system_provider/cloud_file_info.h"
 #include "chrome/browser/ash/file_system_provider/provided_file_system_interface.h"
 #include "chrome/browser/ash/file_system_provider/queue.h"
+#include "net/base/io_buffer.h"
 #include "url/origin.h"
 
 namespace ash::file_system_provider {
@@ -246,17 +248,18 @@
   // `StartReadBytes` succeeds, an actual read of the underlying FD will be
   // kicked off, for the purposes of this method it has finished successfully.
   const OpenedCloudFile& opened_cloud_file = it->second;
+  scoped_refptr<net::IOBuffer> buffer_ref = base::WrapRefCounted(buffer);
   content_cache_->ReadBytes(
-      opened_cloud_file, buffer, offset, length,
+      opened_cloud_file, buffer_ref, offset, length,
       base::BindRepeating(&CloudFileSystem::OnReadFileFromCacheCompleted,
-                          weak_ptr_factory_.GetWeakPtr(), file_handle, buffer,
-                          offset, length, callback));
+                          weak_ptr_factory_.GetWeakPtr(), file_handle,
+                          buffer_ref, offset, length, callback));
   return AbortCallback();
 }
 
 void CloudFileSystem::OnReadFileFromCacheCompleted(
     int file_handle,
-    net::IOBuffer* buffer,
+    scoped_refptr<net::IOBuffer> buffer,
     int64_t offset,
     int length,
     ReadChunkReceivedCallback callback,
@@ -274,7 +277,7 @@
     // The file doesn't exist in the cache, we need to make a cloud request
     // first and write the result into the cache upon successful return.
     file_system_->ReadFile(
-        file_handle, buffer, offset, length,
+        file_handle, buffer.get(), offset, length,
         base::BindRepeating(&CloudFileSystem::OnReadFileCompleted,
                             weak_ptr_factory_.GetWeakPtr(), file_handle, buffer,
                             offset, length, callback));
@@ -282,12 +285,12 @@
   }
 
   LOG(ERROR) << "Couldn't read the file from cache";
-  file_system_->ReadFile(file_handle, buffer, offset, length,
+  file_system_->ReadFile(file_handle, buffer.get(), offset, length,
                          std::move(callback));
 }
 
 void CloudFileSystem::OnReadFileCompleted(int file_handle,
-                                          net::IOBuffer* buffer,
+                                          scoped_refptr<net::IOBuffer> buffer,
                                           int64_t offset,
                                           int length,
                                           ReadChunkReceivedCallback callback,
diff --git a/chrome/browser/ash/file_system_provider/cloud_file_system.h b/chrome/browser/ash/file_system_provider/cloud_file_system.h
index f224f38..79be4ef 100644
--- a/chrome/browser/ash/file_system_provider/cloud_file_system.h
+++ b/chrome/browser/ash/file_system_provider/cloud_file_system.h
@@ -164,7 +164,7 @@
   // When an attempt to read the file from disk completes, in the event it fails
   // ensure it gets delegated to the underlying FSP.
   void OnReadFileFromCacheCompleted(int file_handle,
-                                    net::IOBuffer* buffer,
+                                    scoped_refptr<net::IOBuffer> buffer,
                                     int64_t offset,
                                     int length,
                                     ReadChunkReceivedCallback callback,
@@ -174,7 +174,7 @@
 
   // When a `ReadFile` completes, attempt to cache the bytes on disk.
   void OnReadFileCompleted(int file_handle,
-                           net::IOBuffer* buffer,
+                           scoped_refptr<net::IOBuffer> buffer,
                            int64_t offset,
                            int length,
                            ReadChunkReceivedCallback callback,
diff --git a/chrome/browser/ash/file_system_provider/cloud_file_system_unittest.cc b/chrome/browser/ash/file_system_provider/cloud_file_system_unittest.cc
index fedc5f7..02bf9dd2 100644
--- a/chrome/browser/ash/file_system_provider/cloud_file_system_unittest.cc
+++ b/chrome/browser/ash/file_system_provider/cloud_file_system_unittest.cc
@@ -74,7 +74,7 @@
   MOCK_METHOD(void,
               ReadBytes,
               (const OpenedCloudFile& file,
-               net::IOBuffer* buffer,
+               scoped_refptr<net::IOBuffer> buffer,
                int64_t offset,
                int length,
                ProvidedFileSystemInterface::ReadChunkReceivedCallback callback),
@@ -82,7 +82,7 @@
   MOCK_METHOD(void,
               WriteBytes,
               (const OpenedCloudFile& file,
-               net::IOBuffer* buffer,
+               scoped_refptr<net::IOBuffer> buffer,
                int64_t offset,
                int length,
                FileErrorCallback callback),
@@ -256,7 +256,7 @@
 
   // Set the first read bytes to return `base::File::FILE_ERROR_NOT_FOUND`, this
   // indicates that the data is not cached in the content cache.
-  EXPECT_CALL(*mock_content_cache, ReadBytes(_, buffer.get(), /*offset=*/0,
+  EXPECT_CALL(*mock_content_cache, ReadBytes(_, buffer, /*offset=*/0,
                                              /*length=*/1, IsNotNullCallback()))
       .WillOnce(RunOnceCallback<4>(/*bytes_read=*/-1, /*has_more=*/false,
                                    base::File::FILE_ERROR_NOT_FOUND));
@@ -264,7 +264,7 @@
   // Set the first write bytes to return successfully, this indicates the post
   // FSP stream to disk succeeded.
   EXPECT_CALL(*mock_content_cache,
-              WriteBytes(_, buffer.get(), /*offset=*/0,
+              WriteBytes(_, buffer, /*offset=*/0,
                          /*length=*/1, IsNotNullCallback()))
       .WillOnce(RunOnceCallback<4>(base::File::FILE_OK));
 
@@ -280,12 +280,12 @@
                    Field(&Watcher::recursive, IsFalse()))))));
 
   // Read the next chunk.
-  EXPECT_CALL(*mock_content_cache, ReadBytes(_, buffer.get(), /*offset=*/1,
+  EXPECT_CALL(*mock_content_cache, ReadBytes(_, buffer, /*offset=*/1,
                                              /*length=*/1, IsNotNullCallback()))
       .WillOnce(RunOnceCallback<4>(/*bytes_read=*/-1, /*has_more=*/false,
                                    base::File::FILE_ERROR_NOT_FOUND));
   EXPECT_CALL(*mock_content_cache,
-              WriteBytes(_, buffer.get(), /*offset=*/1,
+              WriteBytes(_, buffer, /*offset=*/1,
                          /*length=*/1, IsNotNullCallback()))
       .WillOnce(RunOnceCallback<4>(base::File::FILE_OK));
   ReadFileSuccessfully(*cloud_file_system, file_handle, buffer, /*offset=*/1,
@@ -315,7 +315,7 @@
 
   // Set the first read bytes to return `base::File::FILE_OK`, this indicates
   // that the data is fresh and available in the cache.
-  EXPECT_CALL(*mock_content_cache, ReadBytes(_, buffer.get(), /*offset=*/0,
+  EXPECT_CALL(*mock_content_cache, ReadBytes(_, buffer, /*offset=*/0,
                                              /*length=*/1, IsNotNullCallback()))
       .WillOnce(RunOnceCallback<4>(/*bytes_read=*/1, /*has_more=*/false,
                                    base::File::FILE_OK));
@@ -341,7 +341,7 @@
 
   // Make the inner callback to return `base::File::FILE_ERROR_FAILED` to
   // indicate that the actual underlying read of the cached file failed.
-  EXPECT_CALL(*mock_content_cache, ReadBytes(_, buffer.get(), /*offset=*/0,
+  EXPECT_CALL(*mock_content_cache, ReadBytes(_, buffer, /*offset=*/0,
                                              /*length=*/1, IsNotNullCallback()))
       .WillOnce(RunOnceCallback<4>(/*bytes_read=*/-1, /*has_more=*/false,
                                    base::File::FILE_ERROR_FAILED));
@@ -367,7 +367,7 @@
 
   // Set the first read bytes to return `base::File::FILE_ERROR_NOT_FOUND`, this
   // indicates that the data is not cached in the content cache.
-  EXPECT_CALL(*mock_content_cache, ReadBytes(_, buffer.get(), /*offset=*/0,
+  EXPECT_CALL(*mock_content_cache, ReadBytes(_, buffer, /*offset=*/0,
                                              /*length=*/1, IsNotNullCallback()))
       .WillOnce(RunOnceCallback<4>(/*bytes_read=*/-1, /*has_more=*/false,
                                    base::File::FILE_ERROR_NOT_FOUND));
@@ -377,7 +377,7 @@
   // should succeed back to the caller and follow up requests will defer
   // straight to the FSP.
   EXPECT_CALL(*mock_content_cache,
-              WriteBytes(_, buffer.get(), /*offset=*/0,
+              WriteBytes(_, buffer, /*offset=*/0,
                          /*length=*/1, IsNotNullCallback()))
       .WillOnce(RunOnceCallback<4>(base::File::FILE_ERROR_FAILED));
 
diff --git a/chrome/browser/ash/file_system_provider/content_cache/cache_file_context.cc b/chrome/browser/ash/file_system_provider/content_cache/cache_file_context.cc
index 73e34e0..dd568c2 100644
--- a/chrome/browser/ash/file_system_provider/content_cache/cache_file_context.cc
+++ b/chrome/browser/ash/file_system_provider/content_cache/cache_file_context.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ash/file_system_provider/content_cache/cache_file_context.h"
 
+#include "base/logging.h"
+
 namespace ash::file_system_provider {
 
 CacheFileContext::CacheFileContext(const std::string& version_tag,
@@ -15,4 +17,15 @@
 
 CacheFileContext::~CacheFileContext() = default;
 
+LocalFD& CacheFileContext::GetOrCreateLocalFD(
+    int request_id,
+    base::FilePath path_on_disk,
+    scoped_refptr<base::SequencedTaskRunner> io_task_runner) {
+  auto [it, inserted] =
+      open_fds_.try_emplace(request_id, path_on_disk, io_task_runner);
+  VLOG_IF(1, !inserted) << "Re-using cached file descriptor {request_id = '"
+                        << request_id << "', path = '" << path_on_disk << "'}";
+  return it->second;
+}
+
 }  // namespace ash::file_system_provider
diff --git a/chrome/browser/ash/file_system_provider/content_cache/cache_file_context.h b/chrome/browser/ash/file_system_provider/content_cache/cache_file_context.h
index 0526c509..b7092e8 100644
--- a/chrome/browser/ash/file_system_provider/content_cache/cache_file_context.h
+++ b/chrome/browser/ash/file_system_provider/content_cache/cache_file_context.h
@@ -6,10 +6,12 @@
 #define CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_CONTENT_CACHE_CACHE_FILE_CONTEXT_H_
 
 #include <functional>
+#include <map>
 #include <utility>
 
 #include "base/files/file_path.h"
 #include "base/time/time.h"
+#include "chrome/browser/ash/file_system_provider/content_cache/local_fd.h"
 
 namespace ash::file_system_provider {
 
@@ -34,6 +36,13 @@
 
   ~CacheFileContext();
 
+  bool HasLocalFD(int request_id) { return open_fds_.contains(request_id); }
+  LocalFD& GetOrCreateLocalFD(
+      int request_id,
+      base::FilePath path_on_disk,
+      scoped_refptr<base::SequencedTaskRunner> io_task_runner);
+  bool CloseLocalFD(int request_id) { return open_fds_.erase(request_id) == 1; }
+
   int64_t bytes_on_disk() const { return bytes_on_disk_; }
   void set_bytes_on_disk(int64_t bytes_on_disk) {
     bytes_on_disk_ = bytes_on_disk;
@@ -83,6 +92,10 @@
   // Evicted items are scheduled to be removed from disk and the database, so
   // any further use should be disallowed.
   bool pending_removal_ = false;
+
+  // A map (keyed by request ID) that represents any open file descriptors for
+  // this specific file.
+  std::map<int, LocalFD> open_fds_;
 };
 
 using PathContextPair = std::pair<base::FilePath, CacheFileContext>;
diff --git a/chrome/browser/ash/file_system_provider/content_cache/content_cache.h b/chrome/browser/ash/file_system_provider/content_cache/content_cache.h
index dd79fdcd..e7ec1c0 100644
--- a/chrome/browser/ash/file_system_provider/content_cache/content_cache.h
+++ b/chrome/browser/ash/file_system_provider/content_cache/content_cache.h
@@ -48,7 +48,7 @@
   // if the bytes don't exist.
   virtual void ReadBytes(
       const OpenedCloudFile& file,
-      net::IOBuffer* buffer,
+      scoped_refptr<net::IOBuffer> buffer,
       int64_t offset,
       int length,
       ProvidedFileSystemInterface::ReadChunkReceivedCallback callback) = 0;
@@ -61,7 +61,7 @@
   //   - No other writer must be writing to the file at the moment
   // If any conditions are not satisfied, return false.
   virtual void WriteBytes(const OpenedCloudFile& file,
-                          net::IOBuffer* buffer,
+                          scoped_refptr<net::IOBuffer> buffer,
                           int64_t offset,
                           int length,
                           FileErrorCallback callback) = 0;
diff --git a/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl.cc b/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl.cc
index a4ff152..d6f4324 100644
--- a/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl.cc
+++ b/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl.cc
@@ -19,7 +19,7 @@
 #include "chrome/browser/ash/file_system_provider/content_cache/content_cache.h"
 #include "chrome/browser/ash/file_system_provider/content_cache/content_lru_cache.h"
 #include "chrome/browser/ash/file_system_provider/content_cache/context_database.h"
-#include "chrome/browser/ash/file_system_provider/content_cache/local_file.h"
+#include "chrome/browser/ash/file_system_provider/content_cache/local_fd.h"
 #include "chrome/browser/ash/file_system_provider/provided_file_system_interface.h"
 #include "net/base/io_buffer.h"
 
@@ -254,7 +254,7 @@
 
 void ContentCacheImpl::ReadBytes(
     const OpenedCloudFile& file,
-    net::IOBuffer* buffer,
+    scoped_refptr<net::IOBuffer> buffer,
     int64_t offset,
     int length,
     ProvidedFileSystemInterface::ReadChunkReceivedCallback callback) {
@@ -272,9 +272,8 @@
     return;
   }
 
-  auto local_file_it = local_files_.find(file.request_id);
-  bool already_opened = local_file_it != local_files_.end();
-  const CacheFileContext& ctx = it->second;
+  CacheFileContext& ctx = it->second;
+  bool already_opened = ctx.HasLocalFD(file.request_id);
   if (!already_opened && ctx.pending_removal()) {
     VLOG(1) << "Cache miss: file evicted";
     callback.Run(/*bytes_read=*/-1, /*has_more=*/false,
@@ -316,12 +315,12 @@
           << length << "', bytes_on_disk = '" << ctx.bytes_on_disk()
           << "'} is available";
 
-  LocalFile& local_file =
-      GetOrCreateLocalFile(file.request_id, GetPathOnDiskFromId(ctx.id()));
-  local_file.ReadBytes(base::WrapRefCounted(buffer), offset, length,
-                       base::BindOnce(&ContentCacheImpl::OnBytesRead,
-                                      weak_ptr_factory_.GetWeakPtr(),
-                                      file.file_path, std::move(callback)));
+  LocalFD& local_fd = ctx.GetOrCreateLocalFD(
+      file.request_id, GetPathOnDiskFromId(ctx.id()), io_task_runner_);
+  local_fd.ReadBytes(
+      buffer, offset, length,
+      base::BindOnce(&ContentCacheImpl::OnBytesRead,
+                     weak_ptr_factory_.GetWeakPtr(), file.file_path, callback));
 }
 
 void ContentCacheImpl::OnBytesRead(
@@ -356,7 +355,7 @@
 }
 
 void ContentCacheImpl::WriteBytes(const OpenedCloudFile& file,
-                                  net::IOBuffer* buffer,
+                                  scoped_refptr<net::IOBuffer> buffer,
                                   int64_t offset,
                                   int length,
                                   FileErrorCallback callback) {
@@ -410,26 +409,25 @@
     context_db_.AsyncCall(&ContextDatabase::AddItem)
         .WithArgs(file.file_path, file.version_tag, ctx.accessed_time(),
                   inserted_id.get())
-        .Then(base::BindOnce(&ContentCacheImpl::OnFileIdGenerated,
-                             weak_ptr_factory_.GetWeakPtr(), file,
-                             base::WrapRefCounted(buffer), offset, length,
-                             std::move(on_bytes_written_callback),
-                             std::move(inserted_id)));
+        .Then(base::BindOnce(
+            &ContentCacheImpl::OnFileIdGenerated,
+            weak_ptr_factory_.GetWeakPtr(), file, buffer, offset, length,
+            std::move(on_bytes_written_callback), std::move(inserted_id)));
   } else {
     // The ID has already been created and is known on disk, bypass generating
     // the ID and simply start writing to the file.
-    LocalFile& local_file =
-        GetOrCreateLocalFile(file.request_id, GetPathOnDiskFromId(ctx.id()));
-    local_file.WriteBytes(base::WrapRefCounted(buffer), offset, length,
-                          std::move(on_bytes_written_callback));
+    LocalFD& local_fd = ctx.GetOrCreateLocalFD(
+        file.request_id, GetPathOnDiskFromId(ctx.id()), io_task_runner_);
+    local_fd.WriteBytes(buffer, offset, length,
+                        std::move(on_bytes_written_callback));
   }
 }
 
 void ContentCacheImpl::CloseFile(const OpenedCloudFile& file) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  if (auto it = local_files_.find(file.request_id); it != local_files_.end()) {
-    it->second.Close(base::DoNothing());
+  if (auto it = lru_cache_.Peek(file.file_path); it != lru_cache_.end()) {
+    it->second.CloseLocalFD(file.request_id);
   }
 }
 
@@ -453,11 +451,13 @@
   DCHECK(it != lru_cache_.end());
   DCHECK(inserted_id);
   DCHECK_GT(*inserted_id, 0);
-  it->second.set_id(*inserted_id);
-  LocalFile& local_file =
-      GetOrCreateLocalFile(file.request_id, GetPathOnDiskFromId(*inserted_id));
-  local_file.WriteBytes(buffer, offset, length,
-                        std::move(on_bytes_written_callback));
+  CacheFileContext& ctx = it->second;
+  ctx.set_id(*inserted_id);
+
+  LocalFD& local_fd = ctx.GetOrCreateLocalFD(
+      file.request_id, GetPathOnDiskFromId(*inserted_id), io_task_runner_);
+  local_fd.WriteBytes(buffer, offset, length,
+                      std::move(on_bytes_written_callback));
 }
 
 void ContentCacheImpl::OnBytesWritten(const base::FilePath& file_path,
@@ -599,14 +599,4 @@
   return cached_file_paths;
 }
 
-LocalFile& ContentCacheImpl::GetOrCreateLocalFile(int request_id,
-                                                  const base::FilePath& path) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  auto [cached_file, inserted] =
-      local_files_.try_emplace(request_id, path, io_task_runner_);
-  VLOG_IF(1, !inserted) << "Re-using cached file descriptor {request_id = '"
-                        << request_id << "', path = '" << path << "'}";
-  return cached_file->second;
-}
-
 }  // namespace ash::file_system_provider
diff --git a/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl.h b/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl.h
index b6f8fe2..73753085 100644
--- a/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl.h
+++ b/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl.h
@@ -13,7 +13,7 @@
 #include "chrome/browser/ash/file_system_provider/content_cache/content_cache.h"
 #include "chrome/browser/ash/file_system_provider/content_cache/content_lru_cache.h"
 #include "chrome/browser/ash/file_system_provider/content_cache/context_database.h"
-#include "chrome/browser/ash/file_system_provider/content_cache/local_file.h"
+#include "chrome/browser/ash/file_system_provider/content_cache/local_fd.h"
 #include "chrome/browser/ash/file_system_provider/opened_cloud_file.h"
 #include "chrome/browser/ash/file_system_provider/provided_file_system_interface.h"
 
@@ -41,13 +41,13 @@
 
   void ReadBytes(
       const OpenedCloudFile& file,
-      net::IOBuffer* buffer,
+      scoped_refptr<net::IOBuffer> buffer,
       int64_t offset,
       int length,
       ProvidedFileSystemInterface::ReadChunkReceivedCallback callback) override;
 
   void WriteBytes(const OpenedCloudFile& file,
-                  net::IOBuffer* buffer,
+                  scoped_refptr<net::IOBuffer> buffer,
                   int64_t offset,
                   int length,
                   FileErrorCallback callback) override;
@@ -134,20 +134,11 @@
   // Generates the absolute path on disk from the supplied `item_id`.
   const base::FilePath GetPathOnDiskFromId(int64_t item_id);
 
-  // A `LocalFile` represents a wrapper around an open FD. We either create a
-  // new `LocalFile` or get the existing one to avoid opening up a new FD for
-  // every chunked read request.
-  LocalFile& GetOrCreateLocalFile(int request_id, const base::FilePath& path);
-
   SEQUENCE_CHECKER(sequence_checker_);
 
   const base::FilePath root_dir_;
   ContentLRUCache lru_cache_ GUARDED_BY_CONTEXT(sequence_checker_);
 
-  // A map of `LocalFile`s that are keyed by the incoming request ID. This is
-  // analogous to a 1:1 mapping of request ID <-> file handle.
-  std::map<int, LocalFile> local_files_ GUARDED_BY_CONTEXT(sequence_checker_);
-
   scoped_refptr<base::SequencedTaskRunner> io_task_runner_;
   BoundContextDatabase context_db_;
 
diff --git a/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl_unittest.cc b/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl_unittest.cc
index a295591..0d5db29 100644
--- a/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl_unittest.cc
+++ b/chrome/browser/ash/file_system_provider/content_cache/content_cache_impl_unittest.cc
@@ -87,9 +87,8 @@
     // to disk.
     scoped_refptr<net::IOBufferWithSize> buffer =
         InitializeBufferWithRandBytes(chunk_size);
-    EXPECT_EQ(
-        WriteBytesToContentCache(file, buffer.get(), /*offset=*/0, chunk_size),
-        base::File::FILE_OK);
+    EXPECT_EQ(WriteBytesToContentCache(file, buffer, /*offset=*/0, chunk_size),
+              base::File::FILE_OK);
 
     return file;
   }
@@ -131,10 +130,11 @@
         base::RandBytesAsString(kDefaultChunkSize)));
   }
 
-  base::File::Error WriteBytesToContentCache(const OpenedCloudFile& file,
-                                             net::IOBuffer* buffer,
-                                             int64_t offset,
-                                             int length) {
+  base::File::Error WriteBytesToContentCache(
+      const OpenedCloudFile& file,
+      scoped_refptr<net::IOBuffer> buffer,
+      int64_t offset,
+      int length) {
     TestFuture<base::File::Error> future;
     content_cache_->WriteBytes(file, buffer, offset, length,
                                future.GetCallback());
@@ -143,7 +143,7 @@
 
   std::pair<int, base::File::Error> ReadBytesFromContentCache(
       const OpenedCloudFile& file,
-      net::IOBuffer* buffer,
+      scoped_refptr<net::IOBuffer> buffer,
       int64_t offset,
       int length) {
     TestFuture<int, bool, base::File::Error> future;
@@ -177,7 +177,7 @@
   // Contiguous writes should be allowed if re-using the same request ID (which
   // is stored in the `OpenedCloudFile` returned from above).
   scoped_refptr<net::IOBuffer> buffer = InitializeBufferWithRandBytes(64);
-  EXPECT_EQ(WriteBytesToContentCache(file, buffer.get(),
+  EXPECT_EQ(WriteBytesToContentCache(file, buffer,
                                      /*offset=*/kDefaultChunkSize, 64),
             base::File::FILE_OK);
 
@@ -279,8 +279,8 @@
   TestFuture<base::File::Error> future;
   scoped_refptr<net::IOBufferWithSize> buffer =
       InitializeBufferWithRandBytes(kDefaultChunkSize * 2);
-  content_cache_->WriteBytes(file, buffer.get(), /*offset=*/0,
-                             kDefaultChunkSize, future.GetCallback());
+  content_cache_->WriteBytes(file, buffer, /*offset=*/0, kDefaultChunkSize,
+                             future.GetCallback());
 
   // This attempt will be attempted before the `WriteBytesBlocking` call that is
   // made above, so this should fail as the first 512 byte chunk has not been
@@ -315,7 +315,7 @@
                         /*version_tag=*/"versionA", kDefaultChunkSize * 3);
   scoped_refptr<net::IOBufferWithSize> buffer =
       InitializeBufferWithRandBytes(kDefaultChunkSize * 3);
-  EXPECT_EQ(WriteBytesToContentCache(file3, /*buffer=*/buffer.get(),
+  EXPECT_EQ(WriteBytesToContentCache(file3, /*buffer=*/buffer,
                                      /*offset=*/0, kDefaultChunkSize),
             base::File::FILE_OK);
 
@@ -378,7 +378,7 @@
   // The file in the cloud has 512 bytes, however, the reader is attempting to
   // get another 512 bytes starting from 512. Readers expect the `bytes_read` to
   // return with 0 to indicate EOF, follow up requests should honor this.
-  EXPECT_THAT(ReadBytesFromContentCache(file, buffer.get(),
+  EXPECT_THAT(ReadBytesFromContentCache(file, buffer,
                                         /*offset=*/512, kDefaultChunkSize),
               Pair(0, base::File::FILE_OK));
 }
@@ -393,7 +393,7 @@
                        ++request_id_, version_tag, kDefaultChunkSize);
   scoped_refptr<net::IOBufferWithSize> buffer =
       base::MakeRefCounted<net::IOBufferWithSize>(kDefaultChunkSize);
-  EXPECT_THAT(ReadBytesFromContentCache(file, buffer.get(),
+  EXPECT_THAT(ReadBytesFromContentCache(file, buffer,
                                         /*offset=*/0, kDefaultChunkSize),
               Pair(kDefaultChunkSize, base::File::FILE_OK));
 }
@@ -412,13 +412,13 @@
 
   // First request is made for a file that is 49 bytes big but the request is
   // for `kDefaultChunkSize` instead.
-  EXPECT_THAT(ReadBytesFromContentCache(file, buffer.get(),
+  EXPECT_THAT(ReadBytesFromContentCache(file, buffer,
                                         /*offset=*/0, kDefaultChunkSize),
               Pair(49, base::File::FILE_OK));
 
   // The client then requests from the previous offset and the same length, we
   // want to avoid sending this to the FSP as we have all this data available.
-  EXPECT_THAT(ReadBytesFromContentCache(file, buffer.get(),
+  EXPECT_THAT(ReadBytesFromContentCache(file, buffer,
                                         /*offset=*/49, kDefaultChunkSize),
               Pair(0, base::File::FILE_OK));
 }
@@ -438,7 +438,7 @@
   scoped_refptr<net::IOBufferWithSize> buffer =
       base::MakeRefCounted<net::IOBufferWithSize>(kDefaultChunkSize);
   // First request is made for a file that is `kDefaultChunkSize` bytes.
-  EXPECT_THAT(ReadBytesFromContentCache(file, buffer.get(),
+  EXPECT_THAT(ReadBytesFromContentCache(file, buffer,
                                         /*offset=*/0, kDefaultChunkSize),
               Pair(kDefaultChunkSize, base::File::FILE_OK));
 
@@ -467,14 +467,14 @@
   TestFuture<int, bool, base::File::Error> future;
 
   // First request is made for a file that is `kDefaultChunkSize` bytes.
-  EXPECT_THAT(ReadBytesFromContentCache(file, buffer.get(),
+  EXPECT_THAT(ReadBytesFromContentCache(file, buffer,
                                         /*offset=*/0, kDefaultChunkSize),
               Pair(kDefaultChunkSize, base::File::FILE_OK));
 
   // The client then requests from the previous offset but the remaining length,
   // this should return true but only 64 bytes should be returned.
   EXPECT_THAT(
-      ReadBytesFromContentCache(file, buffer.get(),
+      ReadBytesFromContentCache(file, buffer,
                                 /*offset=*/kDefaultChunkSize, /*length=*/128),
       Pair(64, base::File::FILE_OK));
 
@@ -502,7 +502,7 @@
   scoped_refptr<net::IOBufferWithSize> buffer =
       base::MakeRefCounted<net::IOBufferWithSize>(kDefaultChunkSize);
   EXPECT_THAT(
-      ReadBytesFromContentCache(file, buffer.get(),
+      ReadBytesFromContentCache(file, buffer,
                                 /*offset=*/0, /*length=*/kDefaultChunkSize),
       Pair(kDefaultChunkSize, base::File::FILE_OK));
 }
diff --git a/chrome/browser/ash/file_system_provider/content_cache/local_file.cc b/chrome/browser/ash/file_system_provider/content_cache/local_fd.cc
similarity index 86%
rename from chrome/browser/ash/file_system_provider/content_cache/local_file.cc
rename to chrome/browser/ash/file_system_provider/content_cache/local_fd.cc
index 379ca79..4df0cb0 100644
--- a/chrome/browser/ash/file_system_provider/content_cache/local_file.cc
+++ b/chrome/browser/ash/file_system_provider/content_cache/local_fd.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ash/file_system_provider/content_cache/local_file.h"
+#include "chrome/browser/ash/file_system_provider/content_cache/local_fd.h"
 
 #include "base/files/file_error_or.h"
 #include "base/logging.h"
@@ -45,6 +45,7 @@
   }
   int bytes_read = file->Read(offset, buffer->data(), length);
   if (bytes_read < 0) {
+    PLOG(ERROR) << "Failed to read bytes from file";
     return base::unexpected(base::File::FILE_ERROR_FAILED);
   }
 
@@ -56,24 +57,24 @@
 
 }  // namespace
 
-LocalFile::LocalFile(
+LocalFD::LocalFD(
     const base::FilePath& file_path,
     scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
     : file_path_(file_path), blocking_task_runner_(blocking_task_runner) {
-  VLOG(2) << "Local file instance created {file_path = '" << file_path_ << "'}";
+  VLOG(2) << "LocalFD instance created {file_path = '" << file_path_ << "'}";
 }
 
-LocalFile::~LocalFile() {
+LocalFD::~LocalFD() {
   DCHECK(!in_progress_operation_)
-      << "Operation still pending when file destroyed";
-  VLOG(2) << "Local file instance destroyed {file_path = '" << file_path_
+      << "Operation still pending when FD destroyed";
+  VLOG(2) << "LocalFD instance destroyed {file_path = '" << file_path_
           << "'}";
   if (file_) {
     CloseFile();
   }
 }
 
-void LocalFile::WriteBytes(
+void LocalFD::WriteBytes(
     scoped_refptr<net::IOBuffer> buffer,
     int64_t offset,
     int length,
@@ -94,11 +95,11 @@
       FROM_HERE,
       base::BindOnce(&WriteBytesBlocking, std::move(file_), file_path_, buffer,
                      offset, length),
-      base::BindOnce(&LocalFile::OnBytesWritten, weak_ptr_factory_.GetWeakPtr(),
+      base::BindOnce(&LocalFD::OnBytesWritten, weak_ptr_factory_.GetWeakPtr(),
                      std::move(callback)));
 }
 
-void LocalFile::OnBytesWritten(
+void LocalFD::OnBytesWritten(
     base::OnceCallback<void(base::File::Error)> callback,
     FileErrorOrFile error_or_file) {
   base::File::Error result = error_or_file.error_or(base::File::FILE_OK);
@@ -108,7 +109,7 @@
   std::move(callback).Run(result);
 }
 
-void LocalFile::ReadBytes(scoped_refptr<net::IOBuffer> buffer,
+void LocalFD::ReadBytes(scoped_refptr<net::IOBuffer> buffer,
                           int64_t offset,
                           int length,
                           FileErrorOrBytesReadCallback callback) {
@@ -121,11 +122,11 @@
       FROM_HERE,
       base::BindOnce(&ReadBytesBlocking, std::move(file_), file_path_, buffer,
                      offset, length),
-      base::BindOnce(&LocalFile::OnBytesRead, weak_ptr_factory_.GetWeakPtr(),
+      base::BindOnce(&LocalFD::OnBytesRead, weak_ptr_factory_.GetWeakPtr(),
                      std::move(callback)));
 }
 
-void LocalFile::OnBytesRead(
+void LocalFD::OnBytesRead(
     FileErrorOrBytesReadCallback callback,
     FileErrorOrFileAndBytesRead error_or_file_and_bytes_read) {
   base::File::Error result =
@@ -140,7 +141,7 @@
   std::move(callback).Run(bytes_read);
 }
 
-void LocalFile::CloseOrCacheFile(std::unique_ptr<base::File> file) {
+void LocalFD::CloseOrCacheFile(std::unique_ptr<base::File> file) {
   in_progress_operation_ = false;
   if (!close_closure_.is_null()) {
     VLOG(2) << "File closed whilst reading/writing, closing FD";
@@ -151,7 +152,7 @@
   }
 }
 
-void LocalFile::Close(base::OnceClosure close_closure) {
+void LocalFD::Close(base::OnceClosure close_closure) {
   DCHECK(close_closure_.is_null());
   close_closure_ = std::move(close_closure);
   if (in_progress_operation_) {
@@ -163,7 +164,7 @@
   CloseFile();
 }
 
-void LocalFile::CloseFile() {
+void LocalFD::CloseFile() {
   if (close_closure_) {
     std::move(close_closure_).Run();
   }
diff --git a/chrome/browser/ash/file_system_provider/content_cache/local_file.h b/chrome/browser/ash/file_system_provider/content_cache/local_fd.h
similarity index 93%
rename from chrome/browser/ash/file_system_provider/content_cache/local_file.h
rename to chrome/browser/ash/file_system_provider/content_cache/local_fd.h
index 32de3b4b..e6b47b0c 100644
--- a/chrome/browser/ash/file_system_provider/content_cache/local_file.h
+++ b/chrome/browser/ash/file_system_provider/content_cache/local_fd.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_CONTENT_CACHE_LOCAL_FILE_H_
-#define CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_CONTENT_CACHE_LOCAL_FILE_H_
+#ifndef CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_CONTENT_CACHE_LOCAL_FD_H_
+#define CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_CONTENT_CACHE_LOCAL_FD_H_
 
 #include "base/files/file.h"
 #include "base/files/file_error_or.h"
@@ -29,15 +29,15 @@
 // if the events come in interleaved (e.g. a `ReadFile` is still responding when
 // a `CloseFile` is received, the `CloseFile` will happen only after the
 // `ReadFile` returns).
-class LocalFile {
+class LocalFD {
  public:
-  LocalFile(const base::FilePath& file_path,
+  LocalFD(const base::FilePath& file_path,
             scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
 
-  LocalFile(const LocalFile&) = delete;
-  LocalFile& operator=(const LocalFile&) = delete;
+  LocalFD(const LocalFD&) = delete;
+  LocalFD& operator=(const LocalFD&) = delete;
 
-  ~LocalFile();
+  ~LocalFD();
 
   // Write the bytes in `buffer` at `offset` for `length` into the underlying
   // `file_` that was opened. If `file_` is `nullptr` one will be created with
@@ -97,9 +97,9 @@
   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
   std::unique_ptr<base::File> file_;
 
-  base::WeakPtrFactory<LocalFile> weak_ptr_factory_{this};
+  base::WeakPtrFactory<LocalFD> weak_ptr_factory_{this};
 };
 
 }  // namespace ash::file_system_provider
 
-#endif  // CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_CONTENT_CACHE_LOCAL_FILE_H_
+#endif  // CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_CONTENT_CACHE_LOCAL_FD_H_
diff --git a/chrome/browser/ash/file_system_provider/content_cache/local_file_unittest.cc b/chrome/browser/ash/file_system_provider/content_cache/local_fd_unittest.cc
similarity index 89%
rename from chrome/browser/ash/file_system_provider/content_cache/local_file_unittest.cc
rename to chrome/browser/ash/file_system_provider/content_cache/local_fd_unittest.cc
index 5881f251..6548e135 100644
--- a/chrome/browser/ash/file_system_provider/content_cache/local_file_unittest.cc
+++ b/chrome/browser/ash/file_system_provider/content_cache/local_fd_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ash/file_system_provider/content_cache/local_file.h"
+#include "chrome/browser/ash/file_system_provider/content_cache/local_fd.h"
 
 #include <cstring>
 
@@ -22,10 +22,10 @@
 
 using testing::Property;
 
-class FileSystemProviderLocalFileTest : public testing::Test {
+class FileSystemProviderLocalFDTest : public testing::Test {
  protected:
-  FileSystemProviderLocalFileTest() = default;
-  ~FileSystemProviderLocalFileTest() override = default;
+  FileSystemProviderLocalFDTest() = default;
+  ~FileSystemProviderLocalFDTest() override = default;
 
   void SetUp() override {
     EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
@@ -49,12 +49,12 @@
   base::ScopedTempDir temp_dir_;
 };
 
-TEST_F(FileSystemProviderLocalFileTest, BytesCanBeReadSuccessfully) {
+TEST_F(FileSystemProviderLocalFDTest, BytesCanBeReadSuccessfully) {
   // Create a buffer that the contents of `file_path` will be read into.
   scoped_refptr<net::IOBuffer> read_buffer =
       base::MakeRefCounted<net::IOBufferWithSize>(test_file_size_);
 
-  LocalFile file(test_file_path_, task_runner_);
+  LocalFD file(test_file_path_, task_runner_);
   base::test::TestFuture<base::FileErrorOr<int>> read_bytes_future;
   file.ReadBytes(read_buffer, /*offset=*/0, /*length=*/test_file_size_,
                  read_bytes_future.GetCallback());
@@ -70,12 +70,12 @@
   EXPECT_TRUE(close_future.Wait());
 }
 
-TEST_F(FileSystemProviderLocalFileTest, BytesCanBeReadThenWrittenTo) {
+TEST_F(FileSystemProviderLocalFDTest, BytesCanBeReadThenWrittenTo) {
   scoped_refptr<net::IOBuffer> read_buffer =
       base::MakeRefCounted<net::IOBufferWithSize>(test_file_size_);
 
   // Read the current bytes from the existing file.
-  LocalFile file(test_file_path_, task_runner_);
+  LocalFD file(test_file_path_, task_runner_);
   base::test::TestFuture<base::FileErrorOr<int>> future;
   file.ReadBytes(read_buffer, /*offset=*/0, /*length=*/test_file_size_,
                  future.GetCallback());
@@ -105,11 +105,11 @@
                base::StrCat({test_file_contents_, contents_to_append}).c_str());
 }
 
-TEST_F(FileSystemProviderLocalFileTest, FileCanBeScheduledToBeClosed) {
+TEST_F(FileSystemProviderLocalFDTest, FileCanBeScheduledToBeClosed) {
   scoped_refptr<net::IOBuffer> buffer =
       base::MakeRefCounted<net::IOBufferWithSize>(test_file_size_);
 
-  LocalFile file(test_file_path_, task_runner_);
+  LocalFD file(test_file_path_, task_runner_);
   base::test::TestFuture<base::FileErrorOr<int>> read_bytes_future;
   file.ReadBytes(buffer, /*offset=*/0, /*length=*/test_file_size_,
                  read_bytes_future.GetCallback());
@@ -121,11 +121,11 @@
   EXPECT_TRUE(close_future.Wait());
 }
 
-TEST_F(FileSystemProviderLocalFileTest, ConcurrentReadsAreNotAllowed) {
+TEST_F(FileSystemProviderLocalFDTest, ConcurrentReadsAreNotAllowed) {
   scoped_refptr<net::IOBuffer> buffer =
       base::MakeRefCounted<net::IOBufferWithSize>(test_file_size_);
 
-  LocalFile file(test_file_path_, task_runner_);
+  LocalFD file(test_file_path_, task_runner_);
 
   // First read call should succeed.
   base::test::TestFuture<base::FileErrorOr<int>> read_bytes_future_allowed;
diff --git a/chrome/browser/ash/mahi/mahi_cache_manager.cc b/chrome/browser/ash/mahi/mahi_cache_manager.cc
index 06588cb..267edab 100644
--- a/chrome/browser/ash/mahi/mahi_cache_manager.cc
+++ b/chrome/browser/ash/mahi/mahi_cache_manager.cc
@@ -26,14 +26,14 @@
 MahiCacheManager::MahiData::MahiData(
     const std::string& url,
     const std::u16string& title,
-    const std::optional<gfx::ImageSkia>& favicon_image,
     const std::u16string& page_content,
-    const std::u16string& summary,
+    const std::optional<gfx::ImageSkia>& favicon_image,
+    const std::optional<std::u16string>& summary,
     const std::vector<MahiQA>& previous_qa)
     : url(url),
       title(title),
-      favicon_image(favicon_image),
       page_content(page_content),
+      favicon_image(favicon_image),
       summary(summary),
       previous_qa(previous_qa),
       creation_time(base::Time::Now()) {}
@@ -59,12 +59,18 @@
   page_cache_[gurl] = data;
 }
 
+std::u16string MahiCacheManager::GetPageContentForUrl(
+    const std::string& url) const {
+  auto gurl = GURL(url).GetWithoutRef();
+  return page_cache_.contains(gurl) ? page_cache_.at(gurl).page_content
+                                    : std::u16string();
+}
+
 std::optional<std::u16string> MahiCacheManager::GetSummaryForUrl(
     const std::string& url) const {
   auto gurl = GURL(url).GetWithoutRef();
-  return page_cache_.contains(gurl)
-             ? std::make_optional(page_cache_.at(gurl).summary)
-             : std::nullopt;
+  return page_cache_.contains(gurl) ? page_cache_.at(gurl).summary
+                                    : std::nullopt;
 }
 
 std::vector<MahiCacheManager::MahiQA> MahiCacheManager::GetQAForUrl(
diff --git a/chrome/browser/ash/mahi/mahi_cache_manager.h b/chrome/browser/ash/mahi/mahi_cache_manager.h
index 80e95a2..4522cc7 100644
--- a/chrome/browser/ash/mahi/mahi_cache_manager.h
+++ b/chrome/browser/ash/mahi/mahi_cache_manager.h
@@ -27,9 +27,9 @@
     MahiData();
     MahiData(const std::string& url,
              const std::u16string& title,
-             const std::optional<gfx::ImageSkia>& favicon_image,
              const std::u16string& page_content,
-             const std::u16string& summary,
+             const std::optional<gfx::ImageSkia>& favicon_image,
+             const std::optional<std::u16string>& summary,
              const std::vector<MahiQA>& previous_qa);
     MahiData(const MahiData&);
     MahiData& operator=(const MahiData&);
@@ -39,12 +39,12 @@
     std::string url;
     // The title of the page.
     std::u16string title;
-    // The favicon of the page.
-    std::optional<gfx::ImageSkia> favicon_image;
     // The extracted content of the page.
     std::u16string page_content;
+    // The favicon of the page.
+    std::optional<gfx::ImageSkia> favicon_image;
     // The summary of the page;
-    std::u16string summary;
+    std::optional<std::u16string> summary;
     // List of previous questions and answers for this page.
     std::vector<MahiQA> previous_qa;
 
@@ -63,6 +63,9 @@
   // with the new one.
   void AddCacheForUrl(const std::string& url, const MahiData& data);
 
+  // Return the content for the given url.
+  std::u16string GetPageContentForUrl(const std::string& url) const;
+
   // Return the summary for the given url. If it's not in the cache, return
   // nullopt.
   std::optional<std::u16string> GetSummaryForUrl(const std::string& url) const;
diff --git a/chrome/browser/ash/mahi/mahi_cache_manager_unittest.cc b/chrome/browser/ash/mahi/mahi_cache_manager_unittest.cc
index 3e565f5..ea9e748 100644
--- a/chrome/browser/ash/mahi/mahi_cache_manager_unittest.cc
+++ b/chrome/browser/ash/mahi/mahi_cache_manager_unittest.cc
@@ -29,17 +29,18 @@
     mahi_cache_manager_ = std::make_unique<MahiCacheManager>();
     mahi_cache_manager_->page_cache_[GURL("http://url1.com/")] =
         MahiCacheManager::MahiData(
-            "http://url1.com", u"title 1", std::nullopt, u"page content 1",
-            u"summary 1",
+            "http://url1.com", u"title 1", u"page content 1",
+            /* favicon_image = */ std::nullopt, u"summary 1",
             {{u"Question 1", u"Answer 1"}, {u"Question 2", u"Answer 2"}});
 
     // Next item in the cache is logged 5 hours later.
     task_environment_.FastForwardBy(base::Hours(5));
 
     mahi_cache_manager_->page_cache_[GURL("http://url2.com/")] =
-        MahiCacheManager::MahiData("http://url2.com", u"title 2", std::nullopt,
-                                   u"page content 2", u"summary 2",
-                                   {{u"question 1", u"answer 1"}});
+        MahiCacheManager::MahiData(
+            "http://url2.com", u"title 2", u"page content 2",
+            /* favicon_image = */ std::nullopt, u"summary 2",
+            {{u"question 1", u"answer 1"}});
   }
 
   void TearDown() override { mahi_cache_manager_.reset(); }
@@ -57,8 +58,8 @@
   GetMahiCacheManager()->AddCacheForUrl("http://url3.com",
                                         {"http://url3.com",
                                          u"title 3",
-                                         std::nullopt,
                                          u"page content 3",
+                                         /* favicon_image = */ std::nullopt,
                                          u"summary 3",
                                          {{u"new question", u"new answer"}}});
   EXPECT_EQ(GetPageCache().size(), 3u);
@@ -66,8 +67,9 @@
 
 TEST_F(MahiCacheManagerTest, ReplacingExistingURLWithNewContent) {
   MahiCacheManager::MahiData new_data(
-      "http://url1.com", u"New title", std::nullopt, u"New content",
-      u"New summary", {{u"new question", u"new answer"}});
+      "http://url1.com", u"New title", u"New content",
+      /* favicon_image = */ std::nullopt, u"New summary",
+      {{u"new question", u"new answer"}});
   GetMahiCacheManager()->AddCacheForUrl("http://url1.com", new_data);
   EXPECT_EQ(GetPageCache().size(), 2u);
   EXPECT_EQ(GetPageCache().at(GURL("http://url1.com")).url, new_data.url);
@@ -116,6 +118,10 @@
 }
 
 TEST_F(MahiCacheManagerTest, ClearCacheSuccessfully) {
+  // Current cache size.
+  EXPECT_EQ(GetPageCache().size(), 2u);
+
+  // Clear the cache.
   GetMahiCacheManager()->ClearCache();
   EXPECT_EQ(GetPageCache().size(), 0u);
 }
@@ -140,4 +146,14 @@
   EXPECT_EQ(GetPageCache().size(), 0u);
 }
 
+TEST_F(MahiCacheManagerTest, GetCorrectPageContentFromURL) {
+  // Get correct content if the url is found.
+  auto result = GetMahiCacheManager()->GetPageContentForUrl("http://url1.com");
+  EXPECT_EQ(result, u"page content 1");
+
+  // No url is found
+  result = GetMahiCacheManager()->GetPageContentForUrl("http://notfound.com");
+  EXPECT_EQ(result, u"");
+}
+
 }  // namespace ash
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index 4ac294d..f0de5f2d 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -177,14 +177,14 @@
 #if !defined(OFFICIAL_BUILD)
 #include "chrome/browser/ui/webui/new_tab_page/foo/foo.mojom.h"  // nogncheck crbug.com/1125897
 #endif
+#include "chrome/browser/ui/lens/lens_untrusted_ui.h"
+#include "chrome/browser/ui/lens/search_bubble_ui.h"
 #include "chrome/browser/ui/side_panel/customize_chrome/customize_chrome_utils.h"
 #include "chrome/browser/ui/webui/commerce/product_specifications_ui.h"
 #include "chrome/browser/ui/webui/commerce/shopping_insights_side_panel_ui.h"
 #include "chrome/browser/ui/webui/hats/hats_ui.h"
 #include "chrome/browser/ui/webui/history/history_ui.h"
 #include "chrome/browser/ui/webui/internals/user_education/user_education_internals.mojom.h"
-#include "chrome/browser/ui/webui/lens/lens_untrusted_ui.h"
-#include "chrome/browser/ui/webui/lens/search_bubble_ui.h"
 #include "chrome/browser/ui/webui/new_tab_page/new_tab_page.mojom.h"
 #include "chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h"
 #include "chrome/browser/ui/webui/new_tab_page_third_party/new_tab_page_third_party_ui.h"
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
index c673a58..a3f311f 100644
--- a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
+++ b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
@@ -1273,6 +1273,10 @@
   if (entry.is_passkey) {
     entry.display_name = base::UTF16ToUTF8(credential.user_display_name);
   }
+  if (credential.creation_time.has_value()) {
+    entry.creation_time =
+        credential.creation_time->InMillisecondsSinceUnixEpoch();
+  }
   entry.stored_in = extensions::StoreSetFromCredential(credential);
   if (!credential.federation_origin.opaque()) {
     std::u16string formatted_origin =
diff --git a/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.cc b/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.cc
index 5bd7145..d8ce6c4 100644
--- a/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.cc
+++ b/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.cc
@@ -59,6 +59,7 @@
   api::passwords_private::PasswordUiEntry passkey = CreateEntry(kNumMocks);
   passkey.is_passkey = true;
   passkey.display_name = "displayName";
+  passkey.creation_time = 1000;
   current_entries_.push_back(std::move(passkey));
 }
 TestPasswordsPrivateDelegate::~TestPasswordsPrivateDelegate() = default;
diff --git a/chrome/browser/resources/password_manager/credential_details/passkey_details_card.ts b/chrome/browser/resources/password_manager/credential_details/passkey_details_card.ts
index 8fe3a30..b1d90c6 100644
--- a/chrome/browser/resources/password_manager/credential_details/passkey_details_card.ts
+++ b/chrome/browser/resources/password_manager/credential_details/passkey_details_card.ts
@@ -13,6 +13,7 @@
 
 import type {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js';
 import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
+import {assert} from 'chrome://resources/js/assert.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {PasswordManagerImpl, PasswordViewPageInteractions} from '../password_manager_proxy.js';
@@ -125,12 +126,14 @@
   }
 
   private updatePasskeyManagementInfoLabel_() {
-    PasswordManagerImpl.getInstance().isPasswordManagerPinAvailable().then(
-        available => {
-          this.infoLabelText_ = available ?
-              this.i18n('passkeyManagementWithPinInfoLabel') :
-              this.i18n('passkeyManagementInfoLabel');
-        });
+    // Google Password Manager passkeys always have their creation time
+    // available.
+    assert(this.passkey.creationTime !== undefined);
+
+    const date = new Date(this.passkey.creationTime);
+    this.infoLabelText_ = this.i18n(
+        'passkeyManagementInfoLabel',
+        date.toLocaleDateString(/*locales=*/ undefined, {dateStyle: 'short'}));
   }
 }
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 1b257f2..5db9491 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1793,12 +1793,6 @@
       "webui/inspect_ui.h",
       "webui/internals/user_education/user_education_internals_page_handler_impl.cc",
       "webui/internals/user_education/user_education_internals_page_handler_impl.h",
-      "webui/lens/lens_untrusted_ui.cc",
-      "webui/lens/lens_untrusted_ui.h",
-      "webui/lens/lens_untrusted_ui_config.cc",
-      "webui/lens/lens_untrusted_ui_config.h",
-      "webui/lens/search_bubble_ui.cc",
-      "webui/lens/search_bubble_ui.h",
       "webui/managed_ui_handler.cc",
       "webui/managed_ui_handler.h",
       "webui/management/management_ui.cc",
@@ -2126,7 +2120,6 @@
       "//chrome/browser/ui/webui/downloads:mojo_bindings",
       "//chrome/browser/ui/webui/hats:mojo_bindings",
       "//chrome/browser/ui/webui/internals/user_education:mojo_bindings",
-      "//chrome/browser/ui/webui/lens",
       "//chrome/browser/ui/webui/new_tab_page:mojo_bindings",
       "//chrome/browser/ui/webui/new_tab_page_third_party:mojo_bindings",
       "//chrome/browser/ui/webui/on_device_internals:mojom",
@@ -4224,6 +4217,12 @@
       "lens/lens_permission_bubble_controller.h",
       "lens/lens_search_bubble_controller.cc",
       "lens/lens_search_bubble_controller.h",
+      "lens/lens_untrusted_ui.cc",
+      "lens/lens_untrusted_ui.h",
+      "lens/lens_untrusted_ui_config.cc",
+      "lens/lens_untrusted_ui_config.h",
+      "lens/search_bubble_ui.cc",
+      "lens/search_bubble_ui.h",
       "signin/signin_modal_dialog.cc",
       "signin/signin_modal_dialog.h",
       "signin/signin_modal_dialog_impl.cc",
diff --git a/chrome/browser/ui/android/desktop_windowing/java/src/org/chromium/chrome/browser/ui/desktop_windowing/AppHeaderUtils.java b/chrome/browser/ui/android/desktop_windowing/java/src/org/chromium/chrome/browser/ui/desktop_windowing/AppHeaderUtils.java
index 5bf4e333..1162233 100644
--- a/chrome/browser/ui/android/desktop_windowing/java/src/org/chromium/chrome/browser/ui/desktop_windowing/AppHeaderUtils.java
+++ b/chrome/browser/ui/android/desktop_windowing/java/src/org/chromium/chrome/browser/ui/desktop_windowing/AppHeaderUtils.java
@@ -7,6 +7,7 @@
 import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
 
+import org.chromium.base.ResettersForTesting;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher.ActivityState;
@@ -55,6 +56,8 @@
         int NUM_ENTRIES = 3;
     }
 
+    private static Boolean sIsAppInDesktopWindowForTesting;
+
     /**
      * Determines whether the currently starting activity is focused, based on the {@link
      * ActivityLifecycleDispatcher} instance associated with it. Note that this method is intended
@@ -78,6 +81,7 @@
      */
     public static boolean isAppInDesktopWindow(
             @Nullable DesktopWindowStateProvider desktopWindowStateProvider) {
+        if (sIsAppInDesktopWindowForTesting != null) return sIsAppInDesktopWindowForTesting;
         if (desktopWindowStateProvider == null) return false;
         var appHeaderState = desktopWindowStateProvider.getAppHeaderState();
 
@@ -121,4 +125,14 @@
         RecordHistogram.recordEnumeratedHistogram(
                 histogramName, state, DesktopWindowModeState.NUM_ENTRIES);
     }
+
+    /**
+     * Sets the desktop windowing mode for tests.
+     *
+     * @param isAppInDesktopWindow Whether desktop windowing mode is activated.
+     */
+    public static void setAppInDesktopWindowForTesting(boolean isAppInDesktopWindow) {
+        sIsAppInDesktopWindowForTesting = isAppInDesktopWindow;
+        ResettersForTesting.register(() -> sIsAppInDesktopWindowForTesting = null);
+    }
 }
diff --git a/chrome/browser/ui/ash/picker/picker_interactive_uitest.cc b/chrome/browser/ui/ash/picker/picker_interactive_uitest.cc
index 833956d..a7bdb9a2 100644
--- a/chrome/browser/ui/ash/picker/picker_interactive_uitest.cc
+++ b/chrome/browser/ui/ash/picker/picker_interactive_uitest.cc
@@ -245,10 +245,9 @@
 
 // Searches for '1 + 1', checks the top result is '2', and inserts it
 // into a web input field.
-// TODO(crbug.com/40240570): Re-enable once MSan stops failing on Rust-side
+// TODO: crbug.com/40240570 - Re-enable once MSan stops failing on Rust-side
 // allocations.
-// TODO(crbug.com/338153458): Re-enable once LSan stops failing on Chromium OS.
-#if defined(MEMORY_SANITIZER) || defined(LEAK_SANITIZER)
+#if defined(MEMORY_SANITIZER)
 #define MAYBE_SearchAndInsertMath DISABLED_SearchAndInsertMath
 #else
 #define MAYBE_SearchAndInsertMath SearchAndInsertMath
diff --git a/chrome/browser/ui/lens/BUILD.gn b/chrome/browser/ui/lens/BUILD.gn
index 3a40a02..fea235ab 100644
--- a/chrome/browser/ui/lens/BUILD.gn
+++ b/chrome/browser/ui/lens/BUILD.gn
@@ -19,6 +19,8 @@
     "lens_overlay_request_id_generator.h",
     "lens_overlay_url_builder.cc",
     "lens_overlay_url_builder.h",
+    "search_bubble_page_handler.cc",
+    "search_bubble_page_handler.h",
   ]
 
   deps = [
@@ -26,6 +28,9 @@
     "//chrome/browser:browser_process",
     "//chrome/browser/lens/core/mojom:mojo_bindings",
     "//chrome/browser/profiles",
+    "//chrome/browser/themes",
+    "//chrome/browser/ui/color:color_headers",
+    "//chrome/browser/ui/webui/top_chrome",
     "//chrome/common:channel_info",
     "//components/endpoint_fetcher",
     "//components/lens:features",
@@ -38,8 +43,10 @@
     "//components/variations",
     "//components/variations:variations_mojom",
     "//components/version_info:channel",
+    "//content/public/browser",
     "//google_apis",
     "//google_apis/common:common",
+    "//mojo/public/cpp/bindings",
     "//net",
     "//net/traffic_annotation",
     "//services/network/public/cpp",
diff --git a/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.cc b/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.cc
index 16d3deb0..bc9f20ce 100644
--- a/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.cc
+++ b/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.cc
@@ -9,13 +9,13 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/lens/lens_overlay_controller.h"
 #include "chrome/browser/ui/lens/lens_overlay_url_builder.h"
+#include "chrome/browser/ui/lens/lens_untrusted_ui.h"
 #include "chrome/browser/ui/side_panel/side_panel_ui.h"
 #include "chrome/browser/ui/views/side_panel/side_panel_content_proxy.h"
 #include "chrome/browser/ui/views/side_panel/side_panel_entry.h"
 #include "chrome/browser/ui/views/side_panel/side_panel_registry.h"
 #include "chrome/browser/ui/views/side_panel/side_panel_util.h"
 #include "chrome/browser/ui/views/side_panel/side_panel_web_ui_view.h"
-#include "chrome/browser/ui/webui/lens/lens_untrusted_ui.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/google/core/common/google_util.h"
diff --git a/chrome/browser/ui/lens/lens_permission_bubble_controller.cc b/chrome/browser/ui/lens/lens_permission_bubble_controller.cc
index b5f2aeb..4a2371e 100644
--- a/chrome/browser/ui/lens/lens_permission_bubble_controller.cc
+++ b/chrome/browser/ui/lens/lens_permission_bubble_controller.cc
@@ -16,6 +16,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
 #include "components/constrained_window/constrained_window_views.h"
+#include "components/lens/lens_features.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/common/referrer.h"
@@ -141,8 +142,7 @@
   LogUserAction(UserAction::kLinkOpened);
   browser_->OpenURL(
       content::OpenURLParams(
-          GURL("https://support.google.com/"
-               "chrome?p=search_from_page#topic=7439538"),
+          GURL(lens::features::GetLensOverlayHelpCenterURL()),
           content::Referrer(),
           ui::DispositionFromEventFlags(
               event.flags(), WindowOpenDisposition::NEW_BACKGROUND_TAB),
diff --git a/chrome/browser/ui/lens/lens_search_bubble_controller.cc b/chrome/browser/ui/lens/lens_search_bubble_controller.cc
index 927f90e..187a55b 100644
--- a/chrome/browser/ui/lens/lens_search_bubble_controller.cc
+++ b/chrome/browser/ui/lens/lens_search_bubble_controller.cc
@@ -7,10 +7,10 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_element_identifiers.h"
+#include "chrome/browser/ui/lens/search_bubble_ui.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/top_container_view.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
-#include "chrome/browser/ui/webui/lens/search_bubble_ui.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "ui/views/view_class_properties.h"
diff --git a/chrome/browser/ui/webui/lens/lens_untrusted_ui.cc b/chrome/browser/ui/lens/lens_untrusted_ui.cc
similarity index 98%
rename from chrome/browser/ui/webui/lens/lens_untrusted_ui.cc
rename to chrome/browser/ui/lens/lens_untrusted_ui.cc
index 89665d8..92d5659 100644
--- a/chrome/browser/ui/webui/lens/lens_untrusted_ui.cc
+++ b/chrome/browser/ui/lens/lens_untrusted_ui.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/webui/lens/lens_untrusted_ui.h"
+#include "chrome/browser/ui/lens/lens_untrusted_ui.h"
 
 #include "base/strings/strcat.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/ui/webui/lens/lens_untrusted_ui.h b/chrome/browser/ui/lens/lens_untrusted_ui.h
similarity index 93%
rename from chrome/browser/ui/webui/lens/lens_untrusted_ui.h
rename to chrome/browser/ui/lens/lens_untrusted_ui.h
index 788ac20..2cc33c40 100644
--- a/chrome/browser/ui/webui/lens/lens_untrusted_ui.h
+++ b/chrome/browser/ui/lens/lens_untrusted_ui.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_LENS_LENS_UNTRUSTED_UI_H_
-#define CHROME_BROWSER_UI_WEBUI_LENS_LENS_UNTRUSTED_UI_H_
+#ifndef CHROME_BROWSER_UI_LENS_LENS_UNTRUSTED_UI_H_
+#define CHROME_BROWSER_UI_LENS_LENS_UNTRUSTED_UI_H_
 
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/lens/core/mojom/lens.mojom.h"
@@ -69,4 +69,4 @@
 };
 
 }  // namespace lens
-#endif  // CHROME_BROWSER_UI_WEBUI_LENS_LENS_UNTRUSTED_UI_H_
+#endif  // CHROME_BROWSER_UI_LENS_LENS_UNTRUSTED_UI_H_
diff --git a/chrome/browser/ui/webui/lens/lens_untrusted_ui_config.cc b/chrome/browser/ui/lens/lens_untrusted_ui_config.cc
similarity index 83%
rename from chrome/browser/ui/webui/lens/lens_untrusted_ui_config.cc
rename to chrome/browser/ui/lens/lens_untrusted_ui_config.cc
index 3c60f98..918f801 100644
--- a/chrome/browser/ui/webui/lens/lens_untrusted_ui_config.cc
+++ b/chrome/browser/ui/lens/lens_untrusted_ui_config.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/webui/lens/lens_untrusted_ui_config.h"
+#include "chrome/browser/ui/lens/lens_untrusted_ui_config.h"
 
-#include "chrome/browser/ui/webui/lens/lens_untrusted_ui.h"
+#include "chrome/browser/ui/lens/lens_untrusted_ui.h"
 #include "chrome/common/webui_url_constants.h"
 #include "content/public/common/url_constants.h"
 
diff --git a/chrome/browser/ui/webui/lens/lens_untrusted_ui_config.h b/chrome/browser/ui/lens/lens_untrusted_ui_config.h
similarity index 75%
rename from chrome/browser/ui/webui/lens/lens_untrusted_ui_config.h
rename to chrome/browser/ui/lens/lens_untrusted_ui_config.h
index 26b3ff0..3ce6cfc 100644
--- a/chrome/browser/ui/webui/lens/lens_untrusted_ui_config.h
+++ b/chrome/browser/ui/lens/lens_untrusted_ui_config.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_LENS_LENS_UNTRUSTED_UI_CONFIG_H_
-#define CHROME_BROWSER_UI_WEBUI_LENS_LENS_UNTRUSTED_UI_CONFIG_H_
+#ifndef CHROME_BROWSER_UI_LENS_LENS_UNTRUSTED_UI_CONFIG_H_
+#define CHROME_BROWSER_UI_LENS_LENS_UNTRUSTED_UI_CONFIG_H_
 
 #include "content/public/browser/webui_config.h"
 #include "content/public/common/url_constants.h"
@@ -23,4 +23,4 @@
 
 }  // namespace lens
 
-#endif  // CHROME_BROWSER_UI_WEBUI_LENS_LENS_UNTRUSTED_UI_CONFIG_H_
+#endif  // CHROME_BROWSER_UI_LENS_LENS_UNTRUSTED_UI_CONFIG_H_
diff --git a/chrome/browser/ui/webui/lens/search_bubble_page_handler.cc b/chrome/browser/ui/lens/search_bubble_page_handler.cc
similarity index 96%
rename from chrome/browser/ui/webui/lens/search_bubble_page_handler.cc
rename to chrome/browser/ui/lens/search_bubble_page_handler.cc
index 67d886a..3d52b1b3 100644
--- a/chrome/browser/ui/webui/lens/search_bubble_page_handler.cc
+++ b/chrome/browser/ui/lens/search_bubble_page_handler.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/webui/lens/search_bubble_page_handler.h"
+#include "chrome/browser/ui/lens/search_bubble_page_handler.h"
 
 #include "chrome/browser/themes/theme_service_utils.h"
 #include "chrome/browser/ui/color/chrome_color_id.h"
diff --git a/chrome/browser/ui/webui/lens/search_bubble_page_handler.h b/chrome/browser/ui/lens/search_bubble_page_handler.h
similarity index 88%
rename from chrome/browser/ui/webui/lens/search_bubble_page_handler.h
rename to chrome/browser/ui/lens/search_bubble_page_handler.h
index 06dbea4a..69678b4 100644
--- a/chrome/browser/ui/webui/lens/search_bubble_page_handler.h
+++ b/chrome/browser/ui/lens/search_bubble_page_handler.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_LENS_SEARCH_BUBBLE_PAGE_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_LENS_SEARCH_BUBBLE_PAGE_HANDLER_H_
+#ifndef CHROME_BROWSER_UI_LENS_SEARCH_BUBBLE_PAGE_HANDLER_H_
+#define CHROME_BROWSER_UI_LENS_SEARCH_BUBBLE_PAGE_HANDLER_H_
 
 #include "base/memory/raw_ptr.h"
 #include "chrome/browser/lens/core/mojom/search_bubble.mojom.h"
@@ -47,4 +47,4 @@
 
 }  // namespace lens
 
-#endif  // CHROME_BROWSER_UI_WEBUI_LENS_SEARCH_BUBBLE_PAGE_HANDLER_H_
+#endif  // CHROME_BROWSER_UI_LENS_SEARCH_BUBBLE_PAGE_HANDLER_H_
diff --git a/chrome/browser/ui/webui/lens/search_bubble_ui.cc b/chrome/browser/ui/lens/search_bubble_ui.cc
similarity index 94%
rename from chrome/browser/ui/webui/lens/search_bubble_ui.cc
rename to chrome/browser/ui/lens/search_bubble_ui.cc
index 8b65e87..e977dbfb 100644
--- a/chrome/browser/ui/webui/lens/search_bubble_ui.cc
+++ b/chrome/browser/ui/lens/search_bubble_ui.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/webui/lens/search_bubble_ui.h"
+#include "chrome/browser/ui/lens/search_bubble_ui.h"
 
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/lens/search_bubble_page_handler.h"
+#include "chrome/browser/ui/lens/search_bubble_page_handler.h"
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/generated_resources.h"
diff --git a/chrome/browser/ui/webui/lens/search_bubble_ui.h b/chrome/browser/ui/lens/search_bubble_ui.h
similarity index 90%
rename from chrome/browser/ui/webui/lens/search_bubble_ui.h
rename to chrome/browser/ui/lens/search_bubble_ui.h
index f15c818..f07fc9b 100644
--- a/chrome/browser/ui/webui/lens/search_bubble_ui.h
+++ b/chrome/browser/ui/lens/search_bubble_ui.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_LENS_SEARCH_BUBBLE_UI_H_
-#define CHROME_BROWSER_UI_WEBUI_LENS_SEARCH_BUBBLE_UI_H_
+#ifndef CHROME_BROWSER_UI_LENS_SEARCH_BUBBLE_UI_H_
+#define CHROME_BROWSER_UI_LENS_SEARCH_BUBBLE_UI_H_
 
 #include "chrome/browser/lens/core/mojom/search_bubble.mojom.h"
 #include "chrome/browser/ui/webui/top_chrome/top_chrome_web_ui_controller.h"
@@ -55,4 +55,4 @@
 
 }  // namespace lens
 
-#endif  // CHROME_BROWSER_UI_WEBUI_LENS_SEARCH_BUBBLE_UI_H_
+#endif  // CHROME_BROWSER_UI_LENS_SEARCH_BUBBLE_UI_H_
diff --git a/chrome/browser/ui/views/extensions/extension_popup.cc b/chrome/browser/ui/views/extensions/extension_popup.cc
index f217990..1e75ad4b 100644
--- a/chrome/browser/ui/views/extensions/extension_popup.cc
+++ b/chrome/browser/ui/views/extensions/extension_popup.cc
@@ -152,11 +152,6 @@
   }
 }
 
-void ExtensionPopup::OnExtensionSizeChanged(ExtensionViewViews* view) {
-  if (GetWidget())
-    SizeToContents();
-}
-
 gfx::Size ExtensionPopup::GetMinBounds() {
   return kMinSize;
 }
@@ -246,7 +241,8 @@
     ShowPopupCallback callback)
     : BubbleDialogDelegateView(anchor_view,
                                arrow,
-                               views::BubbleBorder::STANDARD_SHADOW),
+                               views::BubbleBorder::STANDARD_SHADOW,
+                               /*autosize=*/true),
       host_(std::move(host)),
       show_action_(show_action),
       shown_callback_(std::move(callback)),
diff --git a/chrome/browser/ui/views/extensions/extension_popup.h b/chrome/browser/ui/views/extensions/extension_popup.h
index 33b25e1d..327fce7 100644
--- a/chrome/browser/ui/views/extensions/extension_popup.h
+++ b/chrome/browser/ui/views/extensions/extension_popup.h
@@ -83,7 +83,6 @@
                              views::Widget* active_widget) override;
 
   // ExtensionViewViews::Container:
-  void OnExtensionSizeChanged(ExtensionViewViews* view) override;
   gfx::Size GetMinBounds() override;
   gfx::Size GetMaxBounds() override;
 
diff --git a/chrome/browser/ui/views/extensions/extension_view_views.cc b/chrome/browser/ui/views/extensions/extension_view_views.cc
index 95fe0d8d..8ec5ee8 100644
--- a/chrome/browser/ui/views/extensions/extension_view_views.cc
+++ b/chrome/browser/ui/views/extensions/extension_view_views.cc
@@ -152,12 +152,6 @@
   return ui::Cursor();
 }
 
-void ExtensionViewViews::PreferredSizeChanged() {
-  View::PreferredSizeChanged();
-  if (container_)
-    container_->OnExtensionSizeChanged(this);
-}
-
 void ExtensionViewViews::OnWebContentsAttached(views::WebView*) {
   host_->CreateRendererSoon();
   SetVisible(false);
diff --git a/chrome/browser/ui/views/extensions/extension_view_views.h b/chrome/browser/ui/views/extensions/extension_view_views.h
index 77ccc545..a2bbf4bc 100644
--- a/chrome/browser/ui/views/extensions/extension_view_views.h
+++ b/chrome/browser/ui/views/extensions/extension_view_views.h
@@ -34,7 +34,6 @@
    public:
     virtual ~Container() = default;
 
-    virtual void OnExtensionSizeChanged(ExtensionViewViews* view) {}
     virtual gfx::Size GetMinBounds() = 0;
     virtual gfx::Size GetMaxBounds() = 0;
   };
@@ -77,7 +76,6 @@
 
   // views::WebView:
   ui::Cursor GetCursor(const ui::MouseEvent& event) override;
-  void PreferredSizeChanged() override;
 
   void OnWebContentsAttached(views::WebView*);
 
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_coordinator.cc b/chrome/browser/ui/views/extensions/extensions_menu_coordinator.cc
index 9656cf58..345e40f 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_coordinator.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_coordinator.cc
@@ -69,7 +69,8 @@
   DCHECK(base::FeatureList::IsEnabled(
       extensions_features::kExtensionsMenuAccessControl));
   auto bubble_delegate = std::make_unique<views::BubbleDialogDelegate>(
-      anchor_view, views::BubbleBorder::TOP_RIGHT);
+      anchor_view, views::BubbleBorder::TOP_RIGHT,
+      views::BubbleBorder::DIALOG_SHADOW, /*autosize=*/true);
   bubble_delegate->set_margins(gfx::Insets(0));
   bubble_delegate->set_fixed_width(
       views::LayoutProvider::Get()->GetDistanceMetric(
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_view_controller.cc b/chrome/browser/ui/views/extensions/extensions_menu_view_controller.cc
index f19a1a81..0cbb3ce 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_view_controller.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_view_controller.cc
@@ -667,12 +667,6 @@
     menu_item->Update(site_access_toggle_state, site_permissions_button_state,
                       site_permissions_button_access, is_enterprise);
   }
-
-  // Items can be added/removed from the menu, thus we need to resize the menu
-  // contents (e.g extension is added to the requests section).
-  if (bubble_delegate_->GetBubbleFrameView()) {
-    bubble_delegate_->SizeToContents();
-  }
 }
 
 void ExtensionsMenuViewController::UpdateSitePermissionsPage(
@@ -724,11 +718,6 @@
   DCHECK(main_page);
   int index = FindIndex(*toolbar_model_, action_id);
   InsertMenuItemMainPage(main_page, action_id, index);
-
-  // TODO(crbug.com/40879945): Update message section once
-  // such section is implemented (if the extension added requests
-  // site access, it needs to be added to such section).
-  bubble_delegate_->SizeToContents();
 }
 
 void ExtensionsMenuViewController::OnToolbarActionRemoved(
@@ -749,10 +738,6 @@
   auto* main_page = GetMainPage(current_page_.view());
   DCHECK(main_page);
   main_page->RemoveMenuItem(action_id);
-
-  // TODO(crbug.com/40879945): Update message section (if the extension
-  // removed was in the section, it needs to be removed).
-  bubble_delegate_->SizeToContents();
 }
 
 void ExtensionsMenuViewController::OnToolbarActionUpdated(
@@ -851,9 +836,6 @@
   }
 
   main_page->RemoveExtensionRequestingAccess(extension_id);
-  if (bubble_delegate_->GetBubbleFrameView()) {
-    bubble_delegate_->SizeToContents();
-  }
 }
 
 void ExtensionsMenuViewController::OnSiteAccessRequestAdded(
@@ -948,12 +930,6 @@
   }
   DCHECK(!current_page_);
   current_page_.SetView(bubble_contents_->AddChildView(std::move(page)));
-
-  // Only resize the menu if the bubble is created, since page could be added to
-  // the menu beforehand and delegate wouldn't know the bubble bounds.
-  if (bubble_delegate_->GetBubbleFrameView()) {
-    bubble_delegate_->SizeToContents();
-  }
 }
 
 void ExtensionsMenuViewController::PopulateMainPage(
diff --git a/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs.cc b/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs.cc
index 805876e..d496453 100644
--- a/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs.cc
+++ b/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs.cc
@@ -19,7 +19,7 @@
 #if BUILDFLAG(ENABLE_COMPOSE)
 #include "chrome/browser/ui/webui/compose/compose_untrusted_ui.h"
 #endif  // BUILDFLAG(ENABLE_COMPOSE)
-#include "chrome/browser/ui/webui/lens/lens_untrusted_ui_config.h"
+#include "chrome/browser/ui/lens/lens_untrusted_ui_config.h"
 #endif  // defined(TOOLKIT_VIEWS)
 
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
diff --git a/chrome/browser/ui/webui/chrome_web_ui_configs.cc b/chrome/browser/ui/webui/chrome_web_ui_configs.cc
index 9f0ac9d..a1861fb 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_configs.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_configs.cc
@@ -25,13 +25,13 @@
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/browser/ui/webui/media_router/cast_feedback_ui.h"
 #endif
+#include "chrome/browser/ui/lens/search_bubble_ui.h"
 #include "chrome/browser/ui/webui/bookmarks/bookmarks_ui.h"
 #include "chrome/browser/ui/webui/commerce/product_specifications_ui.h"
 #include "chrome/browser/ui/webui/commerce/shopping_insights_side_panel_ui.h"
 #include "chrome/browser/ui/webui/downloads/downloads_ui.h"
 #include "chrome/browser/ui/webui/feedback/feedback_ui.h"
 #include "chrome/browser/ui/webui/history/history_ui.h"
-#include "chrome/browser/ui/webui/lens/search_bubble_ui.h"
 #include "chrome/browser/ui/webui/on_device_internals/on_device_internals_ui.h"
 #include "chrome/browser/ui/webui/side_panel/bookmarks/bookmarks_side_panel_ui.h"
 #include "chrome/browser/ui/webui/side_panel/reading_list/reading_list_ui.h"
diff --git a/chrome/browser/ui/webui/lens/BUILD.gn b/chrome/browser/ui/webui/lens/BUILD.gn
deleted file mode 100644
index d309e26..0000000
--- a/chrome/browser/ui/webui/lens/BUILD.gn
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright 2024 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("lens") {
-  sources = [
-    "search_bubble_page_handler.cc",
-    "search_bubble_page_handler.h",
-  ]
-  deps = [
-    "//chrome/browser/lens/core/mojom:mojo_bindings",
-    "//chrome/browser/themes",
-    "//chrome/browser/ui/color:color_headers",
-    "//chrome/browser/ui/webui/top_chrome",
-    "//content/public/browser",
-    "//mojo/public/cpp/bindings",
-  ]
-}
diff --git a/chrome/browser/ui/webui/password_manager/password_manager_ui.cc b/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
index 4780476..ec47d808 100644
--- a/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
+++ b/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
@@ -317,8 +317,6 @@
        IDS_PASSWORD_MANAGER_UI_PASSKEY_DETAILS_CARD_DELETE_BUTTON_NO_USERNAME_ARIA_LABEL},
       {"passkeyManagementInfoLabel",
        IDS_PASSWORD_MANAGER_UI_PASSKEY_MANAGEMENT_INFO_LABEL},
-      {"passkeyManagementWithPinInfoLabel",
-       IDS_PASSWORD_MANAGER_UI_PASSKEY_MANAGEMENT_WITH_PIN_INFO_LABEL},
       {"passwordCopiedToClipboard",
        IDS_PASSWORD_MANAGER_UI_PASSWORD_COPIED_TO_CLIPBOARD},
       {"passwordDeleted", IDS_PASSWORD_MANAGER_UI_PASSWORD_DELETED},
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index 35556e3..4b4e14b 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1715428121-ef14e7907578535080c7cbb729d6e247ff335b98-7cccdfaca02341485968a1d9b3c5ac1f9c6bdffb.profdata
+chrome-android32-main-1715557030-479494ced5371cc841e02a68b4d2ec6fbcc9c61d-c452097d82eb788903c2fa9b242977ff06543f98.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index bc54476..86f9175 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1715428121-a29d226e0aac1dbeedd8dd0f895dc0311c16e993-7cccdfaca02341485968a1d9b3c5ac1f9c6bdffb.profdata
+chrome-android64-main-1715526076-e98afbf45707835ade131ec21ae0efc4fa9111ba-5b9e7084bf6b7d1ff10209a99f3074c69bfefc05.profdata
diff --git a/chrome/build/lacros-arm64.pgo.txt b/chrome/build/lacros-arm64.pgo.txt
index e75d389..1b13fe2 100644
--- a/chrome/build/lacros-arm64.pgo.txt
+++ b/chrome/build/lacros-arm64.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-arm64-generic-main-1715385556-d1f10cf555e1bcec45bbe9a011190193ce70b44e-6b65fa41c849f028057a9c77977e236c9192231b.profdata
+chrome-chromeos-arm64-generic-main-1715500081-013300e9465d3f892c75e9ccc4e82fe538db192e-1711cd65cc1938e19e65f00eea236aa04535cedf.profdata
diff --git a/chrome/build/lacros64.pgo.txt b/chrome/build/lacros64.pgo.txt
index 0fa8b0f..dae8f0e 100644
--- a/chrome/build/lacros64.pgo.txt
+++ b/chrome/build/lacros64.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-amd64-generic-main-1715428121-63d5fe45512578df8e22eb0b4f1fd67cfeea29d0-7cccdfaca02341485968a1d9b3c5ac1f9c6bdffb.profdata
+chrome-chromeos-amd64-generic-main-1715500081-af0f79395ad2ecde7a93cc478d60ae3d66604f55-1711cd65cc1938e19e65f00eea236aa04535cedf.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index edd4ea3..ecf10bf 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1715428121-a4b808bf368bcc0cd45a0c5336c2d8118bfaddce-7cccdfaca02341485968a1d9b3c5ac1f9c6bdffb.profdata
+chrome-linux-main-1715526076-9176aa747d5295fedc5cc59f606edea5d38ee346-5b9e7084bf6b7d1ff10209a99f3074c69bfefc05.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index c8e3359b..534b5c2 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1715440928-fed73756aae54a02b1320f58b604ee61a1b997fe-a2121ad239aab7189a34fbec9e4889a53a8f08d4.profdata
+chrome-mac-arm-main-1715557030-ff25757f52de357ae56f68716bcdd80d2773cc3e-c452097d82eb788903c2fa9b242977ff06543f98.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index fcecb1d..ed28a77 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1715428121-dadbfc5376fa80d2de906718bc5a103a1ff24fa6-7cccdfaca02341485968a1d9b3c5ac1f9c6bdffb.profdata
+chrome-win-arm64-main-1715557030-dfe5a44f9ef28e2ca14b013d3005500d88b20be8-c452097d82eb788903c2fa9b242977ff06543f98.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index d09e073..f2773bd 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1715438991-7e34291c80a688d018dd2b9e01b9fe1a69cbb703-6e415a7adc7e6fc77f5b6d50934b03361a46eb52.profdata
+chrome-win32-main-1715526076-2bbbb00961d4be6fbbe2e37caabf5475ad69c961-5b9e7084bf6b7d1ff10209a99f3074c69bfefc05.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index a20823b..b7073e9b 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1715438991-9163625dce09614632681cc412f21b5b63774254-6e415a7adc7e6fc77f5b6d50934b03361a46eb52.profdata
+chrome-win64-main-1715526076-88241d6104a82576549e7c5d429dd83ba220495a-5b9e7084bf6b7d1ff10209a99f3074c69bfefc05.profdata
diff --git a/chrome/common/extensions/api/passwords_private.idl b/chrome/common/extensions/api/passwords_private.idl
index 9599ece4..37392ad 100644
--- a/chrome/common/extensions/api/passwords_private.idl
+++ b/chrome/common/extensions/api/passwords_private.idl
@@ -261,6 +261,11 @@
 
     // Additional information in case a credential is compromised.
     CompromisedInfo? compromisedInfo;
+
+    // The timestamp of when this credential was created, or undefined if not a
+    // passkey. Specified in milliseconds since the UNIX epoch. Intended to be
+    // passed to the JavaScript Date() constructor.
+    double? creationTime;
   };
 
   // Group representing affiliated PasswordUiEntries.
diff --git a/chrome/test/data/extensions/api_test/passwords_private/test.js b/chrome/test/data/extensions/api_test/passwords_private/test.js
index 3f0423c..63a3c58b 100644
--- a/chrome/test/data/extensions/api_test/passwords_private/test.js
+++ b/chrome/test/data/extensions/api_test/passwords_private/test.js
@@ -685,6 +685,7 @@
       var passkey = group.entries[group.entries.length - 1];
       chrome.test.assertTrue(passkey.isPasskey);
       chrome.test.assertEq(passkey.displayName, 'displayName');
+      chrome.test.assertEq(passkey.creationTime, 1000);
 
       // Ensure that all entry ids are unique.
       chrome.test.assertEq(group.entries.length, idSet.size);
diff --git a/chrome/test/data/webui/chromeos/diagnostics/BUILD.gn b/chrome/test/data/webui/chromeos/diagnostics/BUILD.gn
index 47a0bfa..d050c63 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/BUILD.gn
+++ b/chrome/test/data/webui/chromeos/diagnostics/BUILD.gn
@@ -45,12 +45,12 @@
     "network_troubleshooting_test.ts",
     "overview_card_test.ts",
     "percent_bar_chart_test.ts",
-    "realtime_cpu_chart_test.js",
+    "realtime_cpu_chart_test.ts",
     "routine_group_test.ts",
     "routine_list_executor_test.ts",
     "routine_result_entry_test.ts",
     "routine_result_list_test.ts",
-    "routine_section_test.js",
+    "routine_section_test.ts",
     "system_page_test.ts",
     "test_diagnostics_browser_proxy.ts",
     "text_badge_test.ts",
diff --git a/chrome/test/data/webui/chromeos/diagnostics/realtime_cpu_chart_test.js b/chrome/test/data/webui/chromeos/diagnostics/realtime_cpu_chart_test.js
deleted file mode 100644
index 3cf8a61..0000000
--- a/chrome/test/data/webui/chromeos/diagnostics/realtime_cpu_chart_test.js
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'chrome://diagnostics/realtime_cpu_chart.js';
-import 'chrome://webui-test/chromeos/mojo_webui_test_support.js';
-
-import {RealtimeCpuChartElement} from 'chrome://diagnostics/realtime_cpu_chart.js';
-import {assertEquals, assertFalse, assertGT, assertTrue} from 'chrome://webui-test/chromeos/chai_assert.js';
-import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
-
-import * as diagnostics_test_utils from './diagnostics_test_utils.js';
-
-suite('realtimeCpuChartTestSuite', function() {
-  /** @type {?RealtimeCpuChartElement} */
-  let realtimeCpuChartElement = null;
-
-  setup(() => {
-    document.body.innerHTML = window.trustedTypes.emptyHTML;
-  });
-
-  teardown(() => {
-    if (realtimeCpuChartElement) {
-      realtimeCpuChartElement.remove();
-    }
-    realtimeCpuChartElement = null;
-  });
-
-  /**
-   * @param {number} user
-   * @param {number} system
-   * @return {!Promise}
-   */
-  function initializeRealtimeCpuChart(user, system) {
-    assertFalse(!!realtimeCpuChartElement);
-
-    // Add the element to the DOM.
-    realtimeCpuChartElement = /** @type {!RealtimeCpuChartElement} */ (
-        document.createElement('realtime-cpu-chart'));
-    assertTrue(!!realtimeCpuChartElement);
-    document.body.appendChild(realtimeCpuChartElement);
-    realtimeCpuChartElement.user = user;
-    realtimeCpuChartElement.system = system;
-
-    return refreshGraph();
-  }
-
-  /**
-   * Get frameDuration_ private member for testing.
-   * @suppress {visibility} // access private member
-   */
-  function getFrameDuration() {
-    assertTrue(!!realtimeCpuChartElement);
-    return realtimeCpuChartElement.frameDuration;
-  }
-
-  /**
-   * Get padding_ private member for testing.
-   * @suppress {visibility} // access private member
-   */
-  function getPaddings() {
-    assertTrue(!!realtimeCpuChartElement);
-    return realtimeCpuChartElement.padding;
-  }
-
-  /**
-   * Promise that resolves once at least one refresh interval has passed.
-   * @return {!Promise}
-   */
-  function refreshGraph() {
-    assertTrue(!!realtimeCpuChartElement);
-
-    return new Promise(resolve => {
-      setTimeout(() => {
-        flushTasks().then(() => {
-          resolve();
-        });
-      }, getFrameDuration());
-    });
-  }
-
-  test('InitializeRealtimeCpuChart', () => {
-    const user = 10;
-    const system = 30;
-    return initializeRealtimeCpuChart(user, system).then(() => {
-      diagnostics_test_utils.assertElementContainsText(
-          realtimeCpuChartElement.shadowRoot.querySelector('#legend-user>span'),
-          `${user}`);
-      diagnostics_test_utils.assertElementContainsText(
-          realtimeCpuChartElement.shadowRoot.querySelector(
-              '#legend-system>span'),
-          `${system}`);
-
-      assertEquals(user, realtimeCpuChartElement.user);
-      assertEquals(system, realtimeCpuChartElement.system);
-    });
-  });
-
-  test('ChartAreaBoundary', () => {
-    const user = 10;
-    const system = 30;
-    return initializeRealtimeCpuChart(user, system).then(() => {
-      const svg = realtimeCpuChartElement.shadowRoot.querySelector('#chart');
-      const boundary =
-          realtimeCpuChartElement.shadowRoot.querySelector('#defClip>rect');
-
-      // Chart area boundary must fit within svg.
-      assertGT(
-          Number(svg.getAttribute('width')),
-          Number(boundary.getAttribute('width')));
-      assertGT(
-          Number(svg.getAttribute('height')),
-          Number(boundary.getAttribute('height')));
-
-      const chartGroup =
-          realtimeCpuChartElement.shadowRoot.querySelector('#chartGroup');
-
-      // Margins are in effect.
-      assertEquals(
-          `translate(${getPaddings().left},${getPaddings().top})`,
-          chartGroup.getAttribute('transform'));
-    });
-  });
-
-  test('InitializePlot', () => {
-    const user = 10;
-    const system = 30;
-
-    return initializeRealtimeCpuChart(user, system).then(() => {
-      // yAxis is drawn.
-      assertTrue(!!realtimeCpuChartElement.shadowRoot.querySelector(
-          '#gridLines>path.domain'));
-
-      // Correct number of yAxis ticks drawn.
-      assertEquals(
-          5,
-          realtimeCpuChartElement.shadowRoot
-              .querySelectorAll('#gridLines>g.tick')
-              .length);
-
-      // Plot lines are drawn.
-      assertTrue(!!realtimeCpuChartElement.shadowRoot
-                       .querySelector('#plotGroup>path.user-area')
-                       .getAttribute('d'));
-      assertTrue(!!realtimeCpuChartElement.shadowRoot
-                       .querySelector('#plotGroup>path.system-area')
-                       .getAttribute('d'));
-    });
-  });
-});
diff --git a/chrome/test/data/webui/chromeos/diagnostics/realtime_cpu_chart_test.ts b/chrome/test/data/webui/chromeos/diagnostics/realtime_cpu_chart_test.ts
new file mode 100644
index 0000000..98f17bed
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/diagnostics/realtime_cpu_chart_test.ts
@@ -0,0 +1,144 @@
+// Copyright 2020 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://diagnostics/realtime_cpu_chart.js';
+import 'chrome://webui-test/chromeos/mojo_webui_test_support.js';
+
+import {ChartPadding, RealtimeCpuChartElement} from 'chrome://diagnostics/realtime_cpu_chart.js';
+import {assert} from 'chrome://resources/js/assert.js';
+import {assertEquals, assertGT, assertTrue} from 'chrome://webui-test/chromeos/chai_assert.js';
+import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
+
+import * as diagnostics_test_utils from './diagnostics_test_utils.js';
+
+suite('realtimeCpuChartTestSuite', function() {
+  let realtimeCpuChartElement: RealtimeCpuChartElement|null = null;
+
+  setup(() => {
+    document.body.innerHTML = window.trustedTypes!.emptyHTML;
+  });
+
+  teardown(() => {
+    realtimeCpuChartElement?.remove();
+    realtimeCpuChartElement = null;
+  });
+
+  function initializeRealtimeCpuChart(
+      user: number, system: number): Promise<void> {
+    // Add the element to the DOM.
+    realtimeCpuChartElement =
+        document.createElement(RealtimeCpuChartElement.is);
+    assert(realtimeCpuChartElement);
+    document.body.appendChild(realtimeCpuChartElement);
+    realtimeCpuChartElement.user = user;
+    realtimeCpuChartElement.system = system;
+
+    return refreshGraph();
+  }
+
+  /**
+   * Get frameDuration_ private member for testing.
+   */
+  function getFrameDuration() {
+    assert(realtimeCpuChartElement);
+    return realtimeCpuChartElement.getFrameDurationForTesting();
+  }
+
+  /**
+   * Get padding_ private member for testing.
+   */
+  function getPaddings(): ChartPadding {
+    assert(realtimeCpuChartElement);
+    return realtimeCpuChartElement.getPaddingForTesting();
+  }
+
+  /**
+   * Promise that resolves once at least one refresh interval has passed.
+   */
+  function refreshGraph(): Promise<void> {
+    assert(realtimeCpuChartElement);
+
+    return new Promise(resolve => {
+      setTimeout(() => {
+        flushTasks().then(() => {
+          resolve();
+        });
+      }, getFrameDuration());
+    });
+  }
+
+  test('InitializeRealtimeCpuChart', () => {
+    const user = 10;
+    const system = 30;
+    return initializeRealtimeCpuChart(user, system).then(() => {
+      assert(realtimeCpuChartElement);
+      diagnostics_test_utils.assertElementContainsText(
+          realtimeCpuChartElement.shadowRoot!.querySelector(
+              '#legend-user>span'),
+          `${user}`);
+      diagnostics_test_utils.assertElementContainsText(
+          realtimeCpuChartElement.shadowRoot!.querySelector(
+              '#legend-system>span'),
+          `${system}`);
+
+      assertEquals(user, realtimeCpuChartElement.user);
+      assertEquals(system, realtimeCpuChartElement.system);
+    });
+  });
+
+  test('ChartAreaBoundary', () => {
+    const user = 10;
+    const system = 30;
+    return initializeRealtimeCpuChart(user, system).then(() => {
+      assert(realtimeCpuChartElement);
+      const svg = realtimeCpuChartElement!.shadowRoot!.querySelector('#chart');
+      assert(svg);
+      const boundary =
+          realtimeCpuChartElement.shadowRoot!.querySelector('#defClip>rect');
+      assert(boundary);
+      // Chart area boundary must fit within svg.
+      assertGT(
+          Number(svg.getAttribute('width')),
+          Number(boundary.getAttribute('width')));
+      assertGT(
+          Number(svg.getAttribute('height')),
+          Number(boundary.getAttribute('height')));
+
+      const chartGroup =
+          realtimeCpuChartElement.shadowRoot!.querySelector('#chartGroup');
+      assert(chartGroup);
+      // Margins are in effect.
+      assertEquals(
+          `translate(${getPaddings().left},${getPaddings().top})`,
+          chartGroup.getAttribute('transform'));
+    });
+  });
+
+  test('InitializePlot', () => {
+    const user = 10;
+    const system = 30;
+
+    return initializeRealtimeCpuChart(user, system).then(() => {
+      assert(realtimeCpuChartElement);
+      // yAxis is drawn.
+      assertTrue(!!realtimeCpuChartElement.shadowRoot!.querySelector(
+          '#gridLines>path.domain'));
+
+      // Correct number of yAxis ticks drawn.
+      assertEquals(
+          5,
+          realtimeCpuChartElement.shadowRoot!
+              .querySelectorAll('#gridLines>g.tick')
+              .length);
+
+      // Plot lines are drawn.
+      assertTrue(
+          !!realtimeCpuChartElement.shadowRoot!
+                .querySelector('#plotGroup>path.user-area')!.getAttribute('d'));
+      assertTrue(!!realtimeCpuChartElement.shadowRoot!
+                       .querySelector(
+                           '#plotGroup>path.system-area')!.getAttribute('d'));
+    });
+  });
+});
diff --git a/chrome/test/data/webui/chromeos/diagnostics/routine_section_test.js b/chrome/test/data/webui/chromeos/diagnostics/routine_section_test.ts
similarity index 77%
rename from chrome/test/data/webui/chromeos/diagnostics/routine_section_test.js
rename to chrome/test/data/webui/chromeos/diagnostics/routine_section_test.ts
index 1e3b0ff..de9b96747 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/routine_section_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/routine_section_test.ts
@@ -10,36 +10,33 @@
 import {FakeSystemRoutineController} from 'chrome://diagnostics/fake_system_routine_controller.js';
 import {setSystemRoutineControllerForTesting} from 'chrome://diagnostics/mojo_interface_provider.js';
 import {RoutineGroup} from 'chrome://diagnostics/routine_group.js';
-import {ExecutionProgress, TestSuiteStatus} from 'chrome://diagnostics/routine_list_executor.js';
+import {ExecutionProgress, ResultStatusItem, TestSuiteStatus} from 'chrome://diagnostics/routine_list_executor.js';
 import {getRoutineType, RoutineResultEntryElement} from 'chrome://diagnostics/routine_result_entry.js';
 import {RoutineResultListElement} from 'chrome://diagnostics/routine_result_list.js';
 import {RoutineSectionElement} from 'chrome://diagnostics/routine_section.js';
 import {RoutineType, StandardRoutineResult} from 'chrome://diagnostics/system_routine_controller.mojom-webui.js';
 import {BadgeType, TextBadgeElement} from 'chrome://diagnostics/text_badge.js';
-import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js';
+import {CrButtonElement} from 'chrome://resources/ash/common/cr_elements/cr_button/cr_button.js';
+import {assert} from 'chrome://resources/js/assert.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chromeos/chai_assert.js';
 import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
-
-import {isVisible} from '../test_util.js';
+import {isVisible} from 'chrome://webui-test/test_util.js';
 
 import * as dx_utils from './diagnostics_test_utils.js';
 
 suite('routineSectionTestSuite', function() {
-  /** @type {?RoutineSectionElement} */
-  let routineSectionElement = null;
+  let routineSectionElement: RoutineSectionElement|null = null;
 
-  /** @type {!FakeSystemRoutineController} */
-  let routineController;
+  const routineController = new FakeSystemRoutineController();
 
-  /** @type {function(this:Performance): number} */
-  const originalTime = performance.now;
+  const originalTime: () => number = performance.now;
 
   setup(function() {
-    document.body.innerHTML = window.trustedTypes.emptyHTML;
+    document.body.innerHTML = window.trustedTypes!.emptyHTML;
 
     // Setup a fake routine controller so that nothing resolves unless
     // done explicitly.
-    routineController = new FakeSystemRoutineController();
     routineController.setDelayTimeInMillisecondsForTesting(-1);
 
     // Enable all routines by default.
@@ -50,24 +47,18 @@
   });
 
   teardown(function() {
-    if (routineSectionElement) {
-      routineSectionElement.remove();
-    }
+    routineSectionElement?.remove();
     routineSectionElement = null;
   });
 
   /**
    * Initializes the element and sets the routines.
-   * @param {!Array<!RoutineType|RoutineGroup>} routines
-   * @param {number=} runtime in minutes.
    */
-  function initializeRoutineSection(routines, runtime = 1) {
-    assertFalse(!!routineSectionElement);
-
+  function initializeRoutineSection(
+      routines: RoutineType[]|RoutineGroup[], runtime = 1) {
     // Add the entry to the DOM.
-    routineSectionElement = /** @type {!RoutineSectionElement} */ (
-        document.createElement('routine-section'));
-    assertTrue(!!routineSectionElement);
+    routineSectionElement = document.createElement('routine-section');
+    assert(routineSectionElement);
     document.body.appendChild(routineSectionElement);
 
     // Assign the routines to the property.
@@ -78,7 +69,7 @@
     if (!(routines[0] instanceof RoutineGroup) && routines.length === 1 && [
           RoutineType.kBatteryDischarge,
           RoutineType.kBatteryCharge,
-        ].includes(routines[0])) {
+        ].includes(routines[0] as RoutineType)) {
       routineSectionElement.isPowerRoutine = true;
     }
 
@@ -87,228 +78,201 @@
 
   /**
    * Returns the result list element.
-   * @return {!RoutineResultListElement}
    */
-  function getResultList() {
+  function getResultList(): RoutineResultListElement {
     const resultList = dx_utils.getResultList(routineSectionElement);
-    assertTrue(!!resultList);
+    assert(resultList);
     return resultList;
   }
 
   /**
    * Returns the Run Tests button.
-   * @return {!CrButtonElement}
    */
-  function getRunTestsButton() {
+  function getRunTestsButton(): CrButtonElement {
     const button = dx_utils.getRunTestsButtonFromSection(routineSectionElement);
-    assertTrue(!!button);
+    assert(button);
     return button;
   }
 
   /**
    * Returns the Stop tests button.
-   * @return {!CrButtonElement}
    */
-  function getStopTestsButton() {
+  function getStopTestsButton(): CrButtonElement {
     const button =
         dx_utils.getStopTestsButtonFromSection(routineSectionElement);
-    assertTrue(!!button);
+    assert(button);
     return button;
   }
 
   /**
    * Returns the Show/Hide Test Report button.
-   * @return {!CrButtonElement}
    */
-  function getToggleTestReportButton() {
+  function getToggleTestReportButton(): CrButtonElement {
     const button =
         dx_utils.getToggleTestReportButtonFromSection(routineSectionElement);
-    assertTrue(!!button);
+    assert(button);
     return button;
   }
 
   /**
    * Returns the status badge.
-   * @return {!TextBadgeElement}
    */
-  function getStatusBadge() {
-    return /** @type {!TextBadgeElement} */ (
-        routineSectionElement.shadowRoot.querySelector('#testStatusBadge'));
+  function getStatusBadge(): TextBadgeElement {
+    assert(routineSectionElement);
+    const testStatusBadge =
+        routineSectionElement.shadowRoot!.querySelector<TextBadgeElement>(
+            '#testStatusBadge');
+    assert(testStatusBadge);
+    return testStatusBadge;
   }
 
   /**
    * Returns the status text.
-   * @return {!HTMLElement}
    */
-  function getStatusTextElement() {
+  function getStatusTextElement(): HTMLSpanElement {
+    assert(routineSectionElement);
     const statusText =
-        /** @type {!HTMLElement} */ (
-            routineSectionElement.shadowRoot.querySelector('#testStatusText'));
-    assertTrue(!!statusText);
+        routineSectionElement.shadowRoot!.querySelector<HTMLSpanElement>(
+            '#testStatusText');
+    assert(statusText);
     return statusText;
   }
 
   /**
    * Returns whether the run tests button is disabled.
-   * @return {boolean}
    */
-  function isRunTestsButtonDisabled() {
+  function isRunTestsButtonDisabled(): boolean {
     return getRunTestsButton().disabled;
   }
 
   /**
    * Clicks the run tests button.
-   * @return {!Promise}
    */
-  function clickRunTestsButton() {
+  function clickRunTestsButton(): Promise<void> {
     getRunTestsButton().click();
     return flushTasks();
   }
 
   /**
    * Clicks the stop tests button.
-   * @return {!Promise}
    */
-  function clickStopTestsButton() {
+  function clickStopTestsButton(): Promise<void> {
     getStopTestsButton().click();
     return flushTasks();
   }
 
   /**
    * Clicks the show/hide test report button.
-   * @return {!Promise}
    */
-  function clickToggleTestReportButton() {
+  function clickToggleTestReportButton(): Promise<void> {
     getToggleTestReportButton().click();
     return flushTasks();
   }
 
-  /**
-   * @suppress {visibility}
-   * @return {string}
-   */
-  function getAnnouncedText() {
-    assertTrue(!!routineSectionElement);
-
+  function getAnnouncedText(): string {
+    assert(routineSectionElement);
     return routineSectionElement.announcedText;
   }
 
   /**
    * Returns an array of the entries in the list.
-   * @return {!NodeList<!RoutineResultEntryElement>}
    */
-  function getEntries() {
+  function getEntries(): NodeListOf<RoutineResultEntryElement> {
     return dx_utils.getResultEntries(getResultList());
   }
 
   /**
    * Returns whether the "result list" section is expanded or not.
-   * @return {boolean}
    */
-  function isIronCollapseOpen() {
+  function isIronCollapseOpen(): boolean {
+    assert(routineSectionElement);
     return routineSectionElement.$.collapse.opened;
   }
 
   /**
    * Get currentTestName private member for testing.
-   * @suppress {visibility} // access private member
-   * @return {string}
    */
-  function getCurrentTestName() {
-    assertTrue(!!routineSectionElement);
+  function getCurrentTestName(): string {
+    assert(routineSectionElement);
     return routineSectionElement.currentTestName;
   }
 
   /**
-   * @param {number} t Set current time to t.
+   * @param t Set current time to t.
    */
-  function setMockTime(t) {
+  function setMockTime(t: number): void {
     performance.now = () => t;
   }
 
   /**
    * Restores mocked time to the original function.
    */
-  function resetMockTime() {
+  function resetMockTime(): void {
     performance.now = originalTime;
   }
 
   /**
    * Updates time-to-finish status
-   * @suppress {visibility} // access private member for test
-   * @return {!Promise}
    */
-  function triggerStatusUpdate() {
+  function triggerStatusUpdate(): Promise<void> {
+    assert(routineSectionElement);
     routineSectionElement.setRunningStatusBadgeText();
     return flushTasks();
   }
 
-  /**
-   * @param {boolean} isActive
-   * @return {!Promise}
-   */
-  function setIsActive(isActive) {
+  function setIsActive(isActive: boolean): Promise<void> {
+    assert(routineSectionElement);
     routineSectionElement.isActive = isActive;
     return flushTasks();
   }
 
-  /**
-   * @param {!Array<!RoutineType>} routines
-   * @return {!Promise}
-   */
-  function setRoutines(routines) {
+  function setRoutines(routines: RoutineType[]): Promise<void> {
+    assert(routineSectionElement);
     routineSectionElement.routines = routines;
     return flushTasks();
   }
 
-  /**
-   * @param {boolean} hideRoutineStatus
-   * @return {!Promise}
-   */
-  function setHideRoutineStatus(hideRoutineStatus) {
+  function setHideRoutineStatus(hideRoutineStatus: boolean): Promise<void> {
+    assert(routineSectionElement);
     routineSectionElement.hideRoutineStatus = hideRoutineStatus;
     return flushTasks();
   }
 
-  /**
-   * Returns the learn more button.
-   * @return {!CrButtonElement}
-   */
-  function getLearnMoreButton() {
+  function getLearnMoreButton(): CrButtonElement {
+    assert(routineSectionElement);
     const learnMoreButton =
-        /** @type {!CrButtonElement} */ (
-            routineSectionElement.shadowRoot.querySelector('#learnMoreButton'));
-    assertTrue(!!learnMoreButton);
+        routineSectionElement.shadowRoot!.querySelector<CrButtonElement>(
+            '#learnMoreButton');
+    assert(learnMoreButton);
     return learnMoreButton;
   }
 
   test('ElementRenders', () => {
     return initializeRoutineSection([]).then(() => {
       // Verify the element rendered.
-      assertTrue(
-          !!routineSectionElement.shadowRoot.querySelector('#routineSection'));
+      assertTrue(!!routineSectionElement!.shadowRoot!.querySelector(
+          '#routineSection'));
     });
   });
 
   test('ElementVisibleWhenRoutinesLengthGreaterThanZero', () => {
     return initializeRoutineSection([])
         .then(() => {
+          assert(routineSectionElement);
           // Verify the element is hidden.
-          assertFalse(isVisible(/** @type {!HTMLElement} */ (
-              routineSectionElement.shadowRoot.querySelector(
-                  '#routineSection'))));
+          assertFalse(isVisible(routineSectionElement.shadowRoot!.querySelector(
+              '#routineSection')));
         })
         .then(() => setRoutines([RoutineType.kLanConnectivity]))
         .then(() => {
+          assert(routineSectionElement);
           // Verify the element is not hidden.
-          assertTrue(isVisible(/** @type {!HTMLElement} */ (
-              routineSectionElement.shadowRoot.querySelector(
-                  '#routineSection'))));
+          assertTrue(isVisible(routineSectionElement.shadowRoot!.querySelector(
+              '#routineSection')));
         });
   });
 
   test('ClickButtonShowsStopTest', () => {
-    /** @type {!Array<!RoutineType>} */
     const routines = [
       RoutineType.kCpuCache,
       RoutineType.kCpuFloatingPoint,
@@ -316,6 +280,7 @@
 
     return initializeRoutineSection(routines)
         .then(() => {
+          assert(routineSectionElement);
           assertFalse(isRunTestsButtonDisabled());
           assertEquals(
               TestSuiteStatus.NOT_RUNNING,
@@ -323,6 +288,7 @@
           return clickRunTestsButton();
         })
         .then(() => {
+          assert(routineSectionElement);
           assertFalse(isVisible(getRunTestsButton()));
           assertTrue(isVisible(getStopTestsButton()));
           assertEquals(
@@ -334,7 +300,6 @@
   });
 
   test('ResultListToggleButton', () => {
-    /** @type {!Array<!RoutineType>} */
     const routines = [
       RoutineType.kCpuCache,
       RoutineType.kCpuFloatingPoint,
@@ -361,7 +326,6 @@
   });
 
   test('PowerResultListToggleButton', () => {
-    /** @type {!Array<!RoutineType>} */
     const routines = [
       RoutineType.kBatteryCharge,
     ];
@@ -381,7 +345,6 @@
   });
 
   test('ClickButtonInitializesResultList', () => {
-    /** @type {!Array<!RoutineType>} */
     const routines = [
       RoutineType.kCpuCache,
       RoutineType.kCpuFloatingPoint,
@@ -398,12 +361,15 @@
           assertEquals(routines.length, entries.length);
 
           // First routine should be running.
-          assertEquals(routines[0], entries[0].item.routine);
-          assertEquals(ExecutionProgress.RUNNING, entries[0].item.progress);
+          assertEquals(
+              routines[0], (entries[0]!.item as ResultStatusItem).routine);
+          assertEquals(ExecutionProgress.RUNNING, entries[0]!.item.progress);
 
           // Second routine is not started.
-          assertEquals(routines[1], entries[1].item.routine);
-          assertEquals(ExecutionProgress.NOT_STARTED, entries[1].item.progress);
+          assertEquals(
+              routines[1], (entries[1]!.item as ResultStatusItem).routine);
+          assertEquals(
+              ExecutionProgress.NOT_STARTED, entries[1]!.item.progress);
 
           // Resolve the running test.
           return routineController.resolveRoutineForTesting();
@@ -416,12 +382,14 @@
           assertEquals(routines.length, entries.length);
 
           // First routine should be completed.
-          assertEquals(routines[0], entries[0].item.routine);
-          assertEquals(ExecutionProgress.COMPLETED, entries[0].item.progress);
+          assertEquals(
+              routines[0], (entries[0]!.item as ResultStatusItem).routine);
+          assertEquals(ExecutionProgress.COMPLETED, entries[0]!.item.progress);
 
           // Second routine should be running.
-          assertEquals(routines[1], entries[1].item.routine);
-          assertEquals(ExecutionProgress.RUNNING, entries[1].item.progress);
+          assertEquals(
+              routines[1], (entries[1]!.item as ResultStatusItem).routine);
+          assertEquals(ExecutionProgress.RUNNING, entries[1]!.item.progress);
 
           // Resolve the running test.
           return routineController.resolveRoutineForTesting();
@@ -434,17 +402,18 @@
           assertEquals(routines.length, entries.length);
 
           // First routine should be completed.
-          assertEquals(routines[0], entries[0].item.routine);
-          assertEquals(ExecutionProgress.COMPLETED, entries[0].item.progress);
+          assertEquals(
+              routines[0], (entries[0]!.item as ResultStatusItem).routine);
+          assertEquals(ExecutionProgress.COMPLETED, entries[0]!.item.progress);
 
           // Second routine should be completed.
-          assertEquals(routines[1], entries[1].item.routine);
-          assertEquals(ExecutionProgress.COMPLETED, entries[1].item.progress);
+          assertEquals(
+              routines[1], (entries[1]!.item as ResultStatusItem).routine);
+          assertEquals(ExecutionProgress.COMPLETED, entries[1]!.item.progress);
         });
   });
 
   test('ResultListFiltersBySupported', () => {
-    /** @type {!Array<!RoutineType>} */
     const routines = [
       RoutineType.kCpuCache,
       RoutineType.kMemory,
@@ -463,7 +432,9 @@
         .then(() => {
           const entries = getEntries();
           assertEquals(1, entries.length);
-          assertEquals(RoutineType.kMemory, entries[0].item.routine);
+          assertEquals(
+              RoutineType.kMemory,
+              (entries[0]!.item as ResultStatusItem).routine);
           // Resolve the running test.
           return routineController.resolveRoutineForTesting();
         })
@@ -473,12 +444,13 @@
         .then(() => {
           const entries = getEntries();
           assertEquals(1, entries.length);
-          assertEquals(RoutineType.kMemory, entries[0].item.routine);
+          assertEquals(
+              RoutineType.kMemory,
+              (entries[0]!.item as ResultStatusItem).routine);
         });
   });
 
   test('ResultListStatusSuccess', () => {
-    /** @type {!Array<!RoutineType>} */
     const routines = [
       RoutineType.kMemory,
     ];
@@ -529,7 +501,6 @@
   });
 
   test('PowerTestResultListStatusSuccess', () => {
-    /** @type {!Array<!RoutineType>} */
     const routines = [
       RoutineType.kBatteryCharge,
     ];
@@ -568,7 +539,6 @@
   });
 
   test('ResultListStatusFail', () => {
-    /** @type {!Array<!RoutineType>} */
     const routines = [
       RoutineType.kCpuFloatingPoint,
       RoutineType.kCpuCache,
@@ -644,7 +614,6 @@
   });
 
   test('CancelQueuedRoutinesWithRoutineCompleted', () => {
-    /** @type {!Array<!RoutineType>} */
     const routines = [
       RoutineType.kCpuCache,
       RoutineType.kCpuStress,
@@ -661,12 +630,15 @@
           assertEquals(routines.length, entries.length);
 
           // First routine should be running.
-          assertEquals(routines[0], entries[0].item.routine);
-          assertEquals(ExecutionProgress.RUNNING, entries[0].item.progress);
+          assertEquals(
+              routines[0], (entries[0]!.item as ResultStatusItem).routine);
+          assertEquals(ExecutionProgress.RUNNING, entries[0]!.item.progress);
 
           // Second routine is not started.
-          assertEquals(routines[1], entries[1].item.routine);
-          assertEquals(ExecutionProgress.NOT_STARTED, entries[1].item.progress);
+          assertEquals(
+              routines[1], (entries[1]!.item as ResultStatusItem).routine);
+          assertEquals(
+              ExecutionProgress.NOT_STARTED, entries[1]!.item.progress);
           // // Resolve the running test.
           return routineController.resolveRoutineForTesting();
         })
@@ -674,18 +646,18 @@
         .then(() => {
           const entries = getEntries();
           // First routine should be completed.
-          assertEquals(ExecutionProgress.COMPLETED, entries[0].item.progress);
+          assertEquals(ExecutionProgress.COMPLETED, entries[0]!.item.progress);
 
           // Second routine should be running.
-          assertEquals(ExecutionProgress.RUNNING, entries[1].item.progress);
+          assertEquals(ExecutionProgress.RUNNING, entries[1]!.item.progress);
         })
         .then(() => clickStopTestsButton())
         .then(() => {
           const entries = getEntries();
           // First routine should still be completed.
-          assertEquals(ExecutionProgress.COMPLETED, entries[0].item.progress);
+          assertEquals(ExecutionProgress.COMPLETED, entries[0]!.item.progress);
           // Second routine should be cancelled.
-          assertEquals(ExecutionProgress.CANCELLED, entries[1].item.progress);
+          assertEquals(ExecutionProgress.CANCELLED, entries[1]!.item.progress);
 
           // Badge and status are visible.
           assertTrue(isVisible(getStatusBadge()));
@@ -707,7 +679,6 @@
   });
 
   test('CancelRunningAndQueuedRoutines', () => {
-    /** @type {!Array<!RoutineType>} */
     const routines = [
       RoutineType.kCpuCache,
       RoutineType.kCpuStress,
@@ -726,12 +697,15 @@
 
           const entries = getEntries();
           // First routine should be running.
-          assertEquals(routines[0], entries[0].item.routine);
-          assertEquals(ExecutionProgress.RUNNING, entries[0].item.progress);
+          assertEquals(
+              routines[0], (entries[0]!.item as ResultStatusItem).routine);
+          assertEquals(ExecutionProgress.RUNNING, entries[0]!.item.progress);
 
           // Second routine is not started.
-          assertEquals(routines[1], entries[1].item.routine);
-          assertEquals(ExecutionProgress.NOT_STARTED, entries[1].item.progress);
+          assertEquals(
+              routines[1], (entries[1]!.item as ResultStatusItem).routine);
+          assertEquals(
+              ExecutionProgress.NOT_STARTED, entries[1]!.item.progress);
         })
         // Stop running test.
         .then(() => clickStopTestsButton())
@@ -742,9 +716,9 @@
 
           const entries = getEntries();
           // First routine should be cancelled.
-          assertEquals(ExecutionProgress.CANCELLED, entries[0].item.progress);
+          assertEquals(ExecutionProgress.CANCELLED, entries[0]!.item.progress);
           // Second routine should be cancelled.
-          assertEquals(ExecutionProgress.CANCELLED, entries[1].item.progress);
+          assertEquals(ExecutionProgress.CANCELLED, entries[1]!.item.progress);
 
           // Status text shows test that was cancelled.
           dx_utils.assertElementContainsText(
@@ -777,9 +751,9 @@
 
           const entries = getEntries();
           // First routine should be cancelled.
-          assertEquals(ExecutionProgress.CANCELLED, entries[0].item.progress);
+          assertEquals(ExecutionProgress.CANCELLED, entries[0]!.item.progress);
           // Second routine should be cancelled.
-          assertEquals(ExecutionProgress.CANCELLED, entries[1].item.progress);
+          assertEquals(ExecutionProgress.CANCELLED, entries[1]!.item.progress);
 
           // Status text shows test that was cancelled.
           dx_utils.assertElementContainsText(
@@ -813,8 +787,9 @@
 
           const entries = getEntries();
           // First routine should be completed.
-          assertEquals(routines[0], entries[0].item.routine);
-          assertEquals(ExecutionProgress.COMPLETED, entries[0].item.progress);
+          assertEquals(
+              routines[0], (entries[0]!.item as ResultStatusItem).routine);
+          assertEquals(ExecutionProgress.COMPLETED, entries[0]!.item.progress);
 
           // Status text shows that a routine succeeded.
           dx_utils.assertElementContainsText(
@@ -833,7 +808,7 @@
 
           const entries = getEntries();
           // First routine should be running.
-          assertEquals(ExecutionProgress.RUNNING, entries[0].item.progress);
+          assertEquals(ExecutionProgress.RUNNING, entries[0]!.item.progress);
 
           // Button text should be "Stop test"
           dx_utils.assertElementContainsText(
@@ -1003,7 +978,7 @@
           assertFalse(isVisible(getResultList()));
           // Memory routine should be cancelled.
           assertEquals(
-              ExecutionProgress.CANCELLED, getEntries()[0].item.progress);
+              ExecutionProgress.CANCELLED, getEntries()[0]!.item.progress);
         });
   });
 
@@ -1011,13 +986,12 @@
     return initializeRoutineSection([])
         .then(() => setHideRoutineStatus(true))
         .then(() => {
+          assert(routineSectionElement);
           assertFalse(isVisible(getLearnMoreButton()));
-          assertFalse(isVisible(/** @type {!HTMLElement} */ (
-              routineSectionElement.shadowRoot.querySelector(
-                  '.routine-status-container'))));
-          assertFalse(isVisible(/** @type {!HTMLElement} */ (
-              routineSectionElement.shadowRoot.querySelector(
-                  '.button-container'))));
+          assertFalse(isVisible(routineSectionElement.shadowRoot!.querySelector(
+              '.routine-status-container')));
+          assertFalse(isVisible(routineSectionElement.shadowRoot!.querySelector(
+              '.button-container')));
         });
   });
 
@@ -1048,8 +1022,11 @@
 
           // First routine should be running.
           assertEquals(
-              RoutineType.kGatewayCanBePinged, entries[0].item.routines[0]);
-          assertEquals(ExecutionProgress.RUNNING, entries[0].item.progress);
+              RoutineType.kGatewayCanBePinged,
+              (entries[0]!.item as RoutineGroup).routines[0]);
+          assertEquals(
+              ExecutionProgress.RUNNING,
+              (entries[0]!.item as RoutineGroup).progress);
 
           // Resolve the running test.
           return routineController.resolveRoutineForTesting();
@@ -1060,14 +1037,18 @@
 
           // Second routine in the first group should be running.
           assertEquals(
-              RoutineType.kLanConnectivity, entries[0].item.routines[1]);
-          assertEquals(ExecutionProgress.RUNNING, entries[0].item.progress);
+              RoutineType.kLanConnectivity,
+              (entries[0]!.item as RoutineGroup).routines[1]);
+          assertEquals(
+              ExecutionProgress.RUNNING,
+              (entries[0]!.item as RoutineGroup).progress);
 
           // Resolve the running test.
           return routineController.resolveRoutineForTesting();
         })
         .then(() => flushTasks())
         .then(() => {
+          assert(routineSectionElement);
           const entries = getEntries();
           // We've encountered a test failure which means we should no longer
           // update the status of our remaining routine result entries.
@@ -1076,16 +1057,20 @@
           // Second routine in the first group should have completed.
 
           assertEquals(
-              RoutineType.kLanConnectivity, entries[0].item.routines[1]);
-          assertEquals(ExecutionProgress.COMPLETED, entries[0].item.progress);
+              RoutineType.kLanConnectivity,
+              (entries[0]!.item as RoutineGroup).routines[1]);
+          assertEquals(
+              ExecutionProgress.COMPLETED,
+              (entries[0]!.item as RoutineGroup).progress);
 
           // Text badge should display 'FAILED' for the first group.
-          const textBadge = entries[0].shadowRoot.querySelector('#status');
+          const textBadge = entries[0]!.shadowRoot!.querySelector('#status');
+          assert(textBadge);
           dx_utils.assertElementContainsText(
-              textBadge.shadowRoot.querySelector('#textBadge'), 'FAILED');
+              textBadge.shadowRoot!.querySelector('#textBadge'), 'FAILED');
 
           // Remaining routine groups should display the skipped state.
-          assertEquals(ExecutionProgress.SKIPPED, entries[1].item.progress);
+          assertEquals(ExecutionProgress.SKIPPED, entries[1]!.item.progress);
 
           // Remaining routine should still be running in the background.
           assertEquals(
@@ -1096,6 +1081,7 @@
         })
         .then(() => flushTasks())
         .then(() => {
+          assert(routineSectionElement);
           // All tests are completed and the ignore updates flag should be off
           // again.
           assertEquals(
@@ -1130,8 +1116,9 @@
 
           // First routine should be running.
           assertEquals(
-              RoutineType.kSignalStrength, entries[0].item.routines[0]);
-          assertEquals(ExecutionProgress.RUNNING, entries[0].item.progress);
+              RoutineType.kSignalStrength,
+              (entries[0]!.item as RoutineGroup).routines[0]);
+          assertEquals(ExecutionProgress.RUNNING, entries[0]!.item.progress);
 
           // Resolve the running test.
           return routineController.resolveRoutineForTesting();
@@ -1143,15 +1130,20 @@
 
           // Second routine in the first group should still be running
           // despite the |kSignalStrength| routine failure.
-          assertEquals(RoutineType.kCaptivePortal, entries[0].item.routines[1]);
+          assertEquals(
+              RoutineType.kCaptivePortal,
+              (entries[0]!.item as RoutineGroup).routines[1]);
           assertEquals(
               getCurrentTestName(),
-              getRoutineType(entries[0].item.routines[1]));
+              getRoutineType(
+                  (entries[0]!.item as RoutineGroup).routines[1] as
+                  RoutineType));
 
           // Text badge should display 'WARNING' for the first group.
-          const textBadge = entries[0].shadowRoot.querySelector('#status');
+          const textBadge = entries[0]!.shadowRoot!.querySelector('#status');
+          assert(textBadge);
           dx_utils.assertElementContainsText(
-              textBadge.shadowRoot.querySelector('#textBadge'), 'WARNING');
+              textBadge.shadowRoot!.querySelector('#textBadge'), 'WARNING');
 
           // Resolve the running test.
           return routineController.resolveRoutineForTesting();
@@ -1161,14 +1153,18 @@
           const entries = getEntries();
 
           // Text badge should still display 'WARNING' for the first group.
-          const textBadge = entries[0].shadowRoot.querySelector('#status');
+          const textBadge = entries[0]!.shadowRoot!.querySelector('#status');
+          assert(textBadge);
           dx_utils.assertElementContainsText(
-              textBadge.shadowRoot.querySelector('#textBadge'), 'WARNING');
+              textBadge.shadowRoot!.querySelector('#textBadge'), 'WARNING');
 
           // First routine in the second group should be running.
           assertEquals(
-              RoutineType.kDnsResolverPresent, entries[1].item.routines[0]);
-          assertEquals(ExecutionProgress.RUNNING, entries[1].item.progress);
+              RoutineType.kDnsResolverPresent,
+              (entries[1]!.item as RoutineGroup).routines[0]);
+          assertEquals(
+              ExecutionProgress.RUNNING,
+              (entries[1]!.item as RoutineGroup).progress);
 
 
           // Resolve the running test.
@@ -1176,13 +1172,15 @@
         })
         .then(() => flushTasks())
         .then(() => {
+          assert(routineSectionElement);
           const entries = getEntries();
 
           // Text badge should display 'PASSED' for the second group.
-          const textBadge = entries[1].shadowRoot.querySelector('#status');
+          const textBadge = entries[1]!.shadowRoot!.querySelector('#status');
+          assert(textBadge);
           dx_utils.assertElementContainsText(
-              textBadge.shadowRoot.querySelector('#textBadge'), 'PASSED');
-          assertEquals(ExecutionProgress.COMPLETED, entries[1].item.progress);
+              textBadge.shadowRoot!.querySelector('#textBadge'), 'PASSED');
+          assertEquals(ExecutionProgress.COMPLETED, entries[1]!.item.progress);
           assertEquals(
               routineSectionElement.testSuiteStatus, TestSuiteStatus.COMPLETED);
         });
@@ -1206,8 +1204,9 @@
           const entries = getEntries();
           // First routine should be running.
           assertEquals(
-              RoutineType.kSignalStrength, entries[0].item.routines[0]);
-          assertEquals(ExecutionProgress.RUNNING, entries[0].item.progress);
+              RoutineType.kSignalStrength,
+              (entries[0]!.item as RoutineGroup).routines[0]);
+          assertEquals(ExecutionProgress.RUNNING, entries[0]!.item.progress);
           // Resolve the running test.
           return routineController.resolveRoutineForTesting();
         })
@@ -1217,16 +1216,23 @@
           assertFalse(getResultList().ignoreRoutineStatusUpdates);
           // Second routine in the first group should still be running
           // despite the |kSignalStrength| routine failure.
-          assertEquals(RoutineType.kCaptivePortal, entries[0].item.routines[1]);
+          assertEquals(
+              RoutineType.kCaptivePortal,
+              (entries[0]!.item as RoutineGroup).routines[1]);
           assertEquals(
               getCurrentTestName(),
-              getRoutineType(entries[0].item.routines[1]));
+              getRoutineType(
+                  (entries[0]!.item as RoutineGroup).routines[1] as
+                  RoutineType));
           // Text badge should display 'WARNING' for the first group.
-          const textBadge = entries[0].shadowRoot.querySelector('#status');
+          const textBadge = entries[0]!.shadowRoot!.querySelector('#status');
+          assert(textBadge);
           dx_utils.assertElementContainsText(
-              textBadge.shadowRoot.querySelector('#textBadge'), 'WARNING');
+              textBadge.shadowRoot!.querySelector('#textBadge'), 'WARNING');
           // Failed test text should be set properly.
-          assertEquals(entries[0].item.failedTest, RoutineType.kSignalStrength);
+          assertEquals(
+              (entries[0]!.item as RoutineGroup).failedTest,
+              RoutineType.kSignalStrength);
           // Resolve the running test.
           return routineController.resolveRoutineForTesting();
         })
@@ -1234,11 +1240,14 @@
         .then(() => {
           const entries = getEntries();
           // Text badge should still display 'WARNING' for the first group.
-          const textBadge = entries[0].shadowRoot.querySelector('#status');
+          const textBadge = entries[0]!.shadowRoot!.querySelector('#status');
+          assert(textBadge);
           dx_utils.assertElementContainsText(
-              textBadge.shadowRoot.querySelector('#textBadge'), 'WARNING');
+              textBadge.shadowRoot!.querySelector('#textBadge'), 'WARNING');
           // Failed test does not get overwritten.
-          assertEquals(entries[0].item.failedTest, RoutineType.kSignalStrength);
+          assertEquals(
+              (entries[0]!.item as RoutineGroup).failedTest,
+              RoutineType.kSignalStrength);
         });
   });
 
@@ -1260,26 +1269,32 @@
           const entries = getEntries();
           // First routine should be running.
           assertEquals(
-              RoutineType.kSignalStrength, entries[0].item.routines[0]);
-          assertEquals(ExecutionProgress.RUNNING, entries[0].item.progress);
+              RoutineType.kSignalStrength,
+              (entries[0]!.item as RoutineGroup).routines[0]);
+          assertEquals(ExecutionProgress.RUNNING, entries[0]!.item.progress);
           // Resolve the running test.
           return routineController.resolveRoutineForTesting();
         })
         .then(() => flushTasks())
         .then(() => {
           const entries = getEntries();
-          assertEquals(RoutineType.kCaptivePortal, entries[0].item.routines[1]);
+          assertEquals(
+              RoutineType.kCaptivePortal,
+              (entries[0]!.item as RoutineGroup).routines[1]);
           assertEquals(
               getCurrentTestName(),
-              getRoutineType(entries[0].item.routines[1]));
+              getRoutineType(
+                  (entries[0]!.item as RoutineGroup).routines[1] as
+                  RoutineType));
           // Text badge should display 'RUNNING' for the first group since
           // the signal strength test passed but we still have unfinished
           // routines in this group.
-          const textBadge = entries[0].shadowRoot.querySelector('#status');
+          const textBadge = entries[0]!.shadowRoot!.querySelector('#status');
+          assert(textBadge);
           dx_utils.assertElementContainsText(
-              textBadge.shadowRoot.querySelector('#textBadge'), 'RUNNING');
+              textBadge.shadowRoot!.querySelector('#textBadge'), 'RUNNING');
           // Failed test text should be unset.
-          assertFalse(!!entries[0].item.failedTest);
+          assertFalse(!!(entries[0]!.item as RoutineGroup).failedTest);
           // Resolve the running test.
           return routineController.resolveRoutineForTesting();
         })
@@ -1288,12 +1303,15 @@
           const entries = getEntries();
           // Text badge should display 'WARNING' despite being in a completed
           // state.
-          const textBadge = entries[0].shadowRoot.querySelector('#status');
+          const textBadge = entries[0]!.shadowRoot!.querySelector('#status');
+          assert(textBadge);
           dx_utils.assertElementContainsText(
-              textBadge.shadowRoot.querySelector('#textBadge'), 'WARNING');
-          assertEquals(entries[0].item.progress, ExecutionProgress.COMPLETED);
+              textBadge.shadowRoot!.querySelector('#textBadge'), 'WARNING');
+          assertEquals(entries[0]!.item.progress, ExecutionProgress.COMPLETED);
           // Failed test text should be set properly.
-          assertEquals(entries[0].item.failedTest, RoutineType.kCaptivePortal);
+          assertEquals(
+              (entries[0]!.item as RoutineGroup).failedTest,
+              RoutineType.kCaptivePortal);
         });
   });
 
@@ -1315,6 +1333,7 @@
         })
         .then(() => flushTasks())
         .then(() => {
+          assert(routineSectionElement);
           assertEquals(
               routineSectionElement.testSuiteStatus, TestSuiteStatus.COMPLETED);
           assertEquals('Diagnostics completed', getAnnouncedText());
@@ -1354,6 +1373,7 @@
         })
         .then(() => flushTasks())
         .then(() => {
+          assert(routineSectionElement);
           assertEquals(
               routineSectionElement.testSuiteStatus, TestSuiteStatus.COMPLETED);
           assertEquals('Diagnostics completed', getAnnouncedText());
@@ -1378,6 +1398,7 @@
         })
         .then(() => flushTasks())
         .then(() => {
+          assert(routineSectionElement);
           assertEquals(
               routineSectionElement.testSuiteStatus, TestSuiteStatus.COMPLETED);
           assertEquals('Diagnostics completed', getAnnouncedText());
@@ -1401,6 +1422,7 @@
           return clickStopTestsButton();
         })
         .then(() => {
+          assert(routineSectionElement);
           assertEquals(
               routineSectionElement.testSuiteStatus,
               TestSuiteStatus.NOT_RUNNING);
diff --git a/chrome/test/data/webui/password_manager/passkey_details_card_test.ts b/chrome/test/data/webui/password_manager/passkey_details_card_test.ts
index e19e342..118e6046 100644
--- a/chrome/test/data/webui/password_manager/passkey_details_card_test.ts
+++ b/chrome/test/data/webui/password_manager/passkey_details_card_test.ts
@@ -44,7 +44,9 @@
     assertEquals(passkey.username, card.$.usernameValue.value);
     assertEquals(passkey.displayName, card.$.displayNameValue.value);
     assertEquals(
-        card.i18n('passkeyManagementInfoLabel'),
+        // 1/12/70 is the date that matches the creation time set by
+        // `createPasswordEntry`.
+        card.i18n('passkeyManagementInfoLabel', '1/12/70'),
         card.$.infoLabel.innerText.trim());
     assertTrue(isVisible(card.$.editButton));
     assertTrue(isVisible(card.$.deleteButton));
@@ -105,18 +107,4 @@
     await domChange;
     assertEquals(card.shadowRoot!.querySelector('delete-passkey-dialog'), null);
   });
-
-  test('Mobile device is not needed if PIN available', async function() {
-    passwordManager.data.isPasswordManagerPinAvailable = true;
-
-    card = document.createElement('passkey-details-card');
-    card.passkey = passkey;
-    document.body.appendChild(card);
-    await flushTasks();
-
-    assertEquals(
-        card.i18n('passkeyManagementWithPinInfoLabel'),
-        card.$.infoLabel.innerText.trim());
-  });
-
 });
diff --git a/chrome/test/data/webui/password_manager/test_util.ts b/chrome/test/data/webui/password_manager/test_util.ts
index 6fd1889..c40aafd 100644
--- a/chrome/test/data/webui/password_manager/test_util.ts
+++ b/chrome/test/data/webui/password_manager/test_util.ts
@@ -100,6 +100,7 @@
     changePasswordUrl: params.changePasswordUrl,
     password: params.password || '',
     affiliatedDomains: params.affiliatedDomains || [domain],
+    creationTime: params.isPasskey ? 1000000000 : undefined,
   };
 }
 
@@ -216,6 +217,7 @@
     password: params.password,
     note: '',
     compromisedInfo: types.length ? compromisedInfo : undefined,
+    creationTime: undefined,
   };
 }
 
@@ -226,4 +228,4 @@
     url: `https://${domain}/login`,
     signonRealm: `https://${domain}/login`,
   };
-}
\ No newline at end of file
+}
diff --git a/chromeos/profiles/arm-exp.afdo.newest.txt b/chromeos/profiles/arm-exp.afdo.newest.txt
index 54555ad7..e57e3ce9 100644
--- a/chromeos/profiles/arm-exp.afdo.newest.txt
+++ b/chromeos/profiles/arm-exp.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-exp-126-6422.10-1714388261-benchmark-126.0.6440.0-r3-redacted.afdo.xz
+chromeos-chrome-arm-exp-126-6422.19-1714991850-benchmark-126.0.6473.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/arm.afdo.newest.txt b/chromeos/profiles/arm.afdo.newest.txt
index 112538a..1e99728 100644
--- a/chromeos/profiles/arm.afdo.newest.txt
+++ b/chromeos/profiles/arm.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-none-126-6367.66-1714391546-benchmark-126.0.6449.0-r1-redacted.afdo.xz
+chromeos-chrome-arm-none-126-6422.10-1714995387-benchmark-126.0.6474.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt
index 0283ab10..133cfe8 100644
--- a/chromeos/profiles/atom.afdo.newest.txt
+++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-atom-126-6422.19-1714991850-benchmark-126.0.6471.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-atom-126-6422.19-1714991850-benchmark-126.0.6474.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index 9d3f357c..6b5e020 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-126-6422.19-1714988737-benchmark-126.0.6471.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-126-6422.19-1714988737-benchmark-126.0.6474.0-r1-redacted.afdo.xz
diff --git a/clank b/clank
index 6812543..cdaa3f1 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 6812543ef91ca93164dcce5ff24ef746ae4467fd
+Subproject commit cdaa3f151a155c0c0a3e907ea53fc968343d7c98
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index dd94bdc..c37a9c2 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
 {
-  "version": "34.13",
-  "log_list_timestamp": "2024-05-11T12:56:05Z",
+  "version": "34.14",
+  "log_list_timestamp": "2024-05-12T12:55:05Z",
   "operators": [
     {
       "name": "Google",
diff --git a/components/lens/lens_features.cc b/components/lens/lens_features.cc
index 02dc9d2..2697af2 100644
--- a/components/lens/lens_features.cc
+++ b/components/lens/lens_features.cc
@@ -48,6 +48,9 @@
 BASE_FEATURE(kLensOverlay, "LensOverlay", base::FEATURE_DISABLED_BY_DEFAULT);
 const base::FeatureParam<int> kLensOverlayMinRamMb{&kLensOverlay, "min_ram_mb",
                                                    /*default=value=*/-1};
+const base::FeatureParam<std::string> kHelpCenterUrl{
+    &kLensOverlay, "help-center-url",
+    "https://support.google.com/chrome?p=search_from_page"};
 const base::FeatureParam<std::string> kResultsSearchUrl{
     &kLensOverlay, "results-search-url", "https://www.google.com/search"};
 const base::FeatureParam<int> kLensOverlayScreenshotRenderQuality{
@@ -231,6 +234,10 @@
   return base::FeatureList::IsEnabled(kLensOverlay);
 }
 
+std::string GetLensOverlayHelpCenterURL() {
+  return kHelpCenterUrl.Get();
+}
+
 int GetLensOverlayMinRamMb() {
   return kLensOverlayMinRamMb.Get();
 }
diff --git a/components/lens/lens_features.h b/components/lens/lens_features.h
index 6e69167..96e7613 100644
--- a/components/lens/lens_features.h
+++ b/components/lens/lens_features.h
@@ -200,6 +200,10 @@
 COMPONENT_EXPORT(LENS_FEATURES)
 extern bool IsLensOverlayEnabled();
 
+// Returns the finch configured help center URL for lens permission modal.
+COMPONENT_EXPORT(LENS_FEATURES)
+extern std::string GetLensOverlayHelpCenterURL();
+
 // Returns the minimum amount of physical memory required to enable the Lens
 // overlay feature.
 COMPONENT_EXPORT(LENS_FEATURES)
diff --git a/components/password_manager/core/browser/passkey_credential.cc b/components/password_manager/core/browser/passkey_credential.cc
index e3350b0..412b958 100644
--- a/components/password_manager/core/browser/passkey_credential.cc
+++ b/components/password_manager/core/browser/passkey_credential.cc
@@ -47,9 +47,13 @@
         CredentialId(ProtobufBytesToVector(passkey.credential_id())),
         UserId(ProtobufBytesToVector(passkey.user_id())),
         Username(passkey.has_user_name() ? passkey.user_name() : ""),
-        DisplayName(passkey.has_user_display_name()
-                        ? passkey.user_display_name()
-                        : ""));
+        DisplayName(
+            passkey.has_user_display_name() ? passkey.user_display_name() : ""),
+        passkey.creation_time() != 0
+            ? std::optional<base::Time>(
+                  base::Time::FromMillisecondsSinceUnixEpoch(
+                      passkey.creation_time()))
+            : std::nullopt);
   }
   return ret;
 }
@@ -78,13 +82,15 @@
                                      CredentialId credential_id,
                                      UserId user_id,
                                      Username username,
-                                     DisplayName display_name)
+                                     DisplayName display_name,
+                                     std::optional<base::Time> creation_time)
     : source_(source),
       rp_id_(std::move(rp_id)),
       credential_id_(std::move(credential_id)),
       user_id_(std::move(user_id)),
       username_(std::move(username)),
-      display_name_(std::move(display_name)) {}
+      display_name_(std::move(display_name)),
+      creation_time_(std::move(creation_time)) {}
 
 PasskeyCredential::~PasskeyCredential() = default;
 
diff --git a/components/password_manager/core/browser/passkey_credential.h b/components/password_manager/core/browser/passkey_credential.h
index aa5101f..00cf899 100644
--- a/components/password_manager/core/browser/passkey_credential.h
+++ b/components/password_manager/core/browser/passkey_credential.h
@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "base/containers/span.h"
+#include "base/time/time.h"
 #include "base/types/strong_alias.h"
 #include "build/build_config.h"
 
@@ -51,7 +52,9 @@
                     CredentialId credential_id,
                     UserId user_id,
                     Username username = Username(""),
-                    DisplayName display_name = DisplayName(""));
+                    DisplayName display_name = DisplayName(""),
+                    // Must be provided for kAndroidPhone credentials.
+                    std::optional<base::Time> creation_time = std::nullopt);
   ~PasskeyCredential();
 
   PasskeyCredential(const PasskeyCredential&);
@@ -76,6 +79,9 @@
   const std::vector<uint8_t>& user_id() const { return user_id_; }
   const std::string& username() const { return username_; }
   const std::string& display_name() const { return display_name_; }
+  const std::optional<base::Time>& creation_time() const {
+    return creation_time_;
+  }
 
  private:
   friend bool operator==(const PasskeyCredential& lhs,
@@ -107,6 +113,10 @@
   // An optional label for the authenticator. If this is not set, a generic
   // device name will be returned by GetAuthenticatorLabel().
   std::optional<std::u16string> authenticator_label_;
+
+  // The time when the credential was created. Used for display in management
+  // UIs. This value is not available for passkeys from some sources.
+  std::optional<base::Time> creation_time_;
 };
 
 bool operator==(const PasskeyCredential& lhs, const PasskeyCredential& rhs);
diff --git a/components/password_manager/core/browser/passkey_credential_unittest.cc b/components/password_manager/core/browser/passkey_credential_unittest.cc
index d3645d0b..1779ad9 100644
--- a/components/password_manager/core/browser/passkey_credential_unittest.cc
+++ b/components/password_manager/core/browser/passkey_credential_unittest.cc
@@ -29,11 +29,13 @@
 constexpr std::array<const uint8_t, 4> kUserId1 = {'1', '2', '3', '4'};
 constexpr char kUserName1[] = "reimu";
 constexpr char kUserDisplayName1[] = "Reimu Hakurei";
+constexpr int kCreationEpochSecs1 = 1;
 
 constexpr std::array<const uint8_t, 4> kCredentialId2 = {'e', 'f', 'g', 'h'};
 constexpr std::array<const uint8_t, 4> kUserId2 = {'5', '6', '7', '8'};
 constexpr char kUserName2[] = "marisa";
 constexpr char kUserDisplayName2[] = "Marisa Kirisame";
+constexpr int kCreationEpochSecs2 = 2;
 
 constexpr std::array<const uint8_t, 4> kCredentialIdShadow1 = {'i', 'j', 'k'};
 constexpr std::array<const uint8_t, 4> kCredentialIdShadow2 = {'l', 'm', 'n'};
@@ -58,6 +60,7 @@
   credential1.set_user_id(kUserId1.data(), kUserId1.size());
   credential1.set_user_name(kUserName1);
   credential1.set_user_display_name(kUserDisplayName1);
+  credential1.set_creation_time(kCreationEpochSecs1 * 1000);
 
   sync_pb::WebauthnCredentialSpecifics credential2;
   credential2.set_sync_id(base::RandBytesAsString(16));
@@ -66,6 +69,7 @@
   credential2.set_user_id(kUserId2.data(), kUserId2.size());
   credential2.set_user_name(kUserName2);
   credential2.set_user_display_name(kUserDisplayName2);
+  credential2.set_creation_time(kCreationEpochSecs2 * 1000);
 
   // Shadow the first credential.
   sync_pb::WebauthnCredentialSpecifics credential1_shadow;
@@ -78,6 +82,7 @@
   credential1_shadow.set_user_display_name(kUserDisplayName1);
   credential1_shadow.add_newly_shadowed_credential_ids(
       credential1.credential_id());
+  credential1_shadow.set_creation_time(kCreationEpochSecs1 * 1000);
 
   std::vector<PasskeyCredential> credentials =
       PasskeyCredential::FromCredentialSpecifics(std::vector{
@@ -95,14 +100,16 @@
                                 ToUint8Vector(kCredentialIdShadow1)),
                             PasskeyCredential::UserId(ToUint8Vector(kUserId1)),
                             PasskeyCredential::Username(kUserName1),
-                            PasskeyCredential::DisplayName(kUserDisplayName1)),
+                            PasskeyCredential::DisplayName(kUserDisplayName1),
+                            base::Time::FromTimeT(kCreationEpochSecs1)),
           PasskeyCredential(
               PasskeyCredential::Source::kAndroidPhone,
               PasskeyCredential::RpId(kRpId),
               PasskeyCredential::CredentialId(ToUint8Vector(kCredentialId2)),
               PasskeyCredential::UserId(ToUint8Vector(kUserId2)),
               PasskeyCredential::Username(kUserName2),
-              PasskeyCredential::DisplayName(kUserDisplayName2))));
+              PasskeyCredential::DisplayName(kUserDisplayName2),
+              base::Time::FromTimeT(kCreationEpochSecs2))));
 }
 
 // Regression test for crbug.com/1447116.
@@ -152,14 +159,16 @@
               PasskeyCredential::CredentialId(ToUint8Vector(kCredentialId1)),
               PasskeyCredential::UserId(ToUint8Vector(kUserId1)),
               PasskeyCredential::Username(""),
-              PasskeyCredential::DisplayName("")),
+              PasskeyCredential::DisplayName(""),
+              base::Time::FromMillisecondsSinceUnixEpoch(200)),
           PasskeyCredential(
               PasskeyCredential::Source::kAndroidPhone,
               PasskeyCredential::RpId(kRpId),
               PasskeyCredential::CredentialId(ToUint8Vector(kCredentialId2)),
               PasskeyCredential::UserId(ToUint8Vector(kUserId2)),
               PasskeyCredential::Username(""),
-              PasskeyCredential::DisplayName(""))));
+              PasskeyCredential::DisplayName(""),
+              base::Time::FromMillisecondsSinceUnixEpoch(400))));
 }
 
 TEST_F(PasskeyCredentialTest, FromCredentialSpecifics_EmptyOptionalFields) {
diff --git a/components/password_manager/core/browser/ui/credential_ui_entry.cc b/components/password_manager/core/browser/ui/credential_ui_entry.cc
index bf7f07c..a71b47b9 100644
--- a/components/password_manager/core/browser/ui/credential_ui_entry.cc
+++ b/components/password_manager/core/browser/ui/credential_ui_entry.cc
@@ -78,10 +78,12 @@
 
   facets.push_back(std::move(facet));
 
-  if (form.IsUsingAccountStore())
+  if (form.IsUsingAccountStore()) {
     stored_in.insert(PasswordForm::Store::kAccountStore);
-  if (form.IsUsingProfileStore())
+  }
+  if (form.IsUsingProfileStore()) {
     stored_in.insert(PasswordForm::Store::kProfileStore);
+  }
 }
 
 CredentialUIEntry::CredentialUIEntry(const std::vector<PasswordForm>& forms) {
@@ -114,17 +116,20 @@
 
     facets.push_back(std::move(facet));
 
-    if (form.IsUsingAccountStore())
+    if (form.IsUsingAccountStore()) {
       stored_in.insert(PasswordForm::Store::kAccountStore);
-    if (form.IsUsingProfileStore())
+    }
+    if (form.IsUsingProfileStore()) {
       stored_in.insert(PasswordForm::Store::kProfileStore);
+    }
   }
 }
 
 CredentialUIEntry::CredentialUIEntry(const PasskeyCredential& passkey)
     : passkey_credential_id(passkey.credential_id()),
       username(base::UTF8ToUTF16(passkey.username())),
-      user_display_name(base::UTF8ToUTF16(passkey.display_name())) {
+      user_display_name(base::UTF8ToUTF16(passkey.display_name())),
+      creation_time(passkey.creation_time()) {
   CHECK(!passkey.credential_id().empty());
   CredentialFacet facet;
   facet.url = GURL(base::StrCat(
diff --git a/components/password_manager/core/browser/ui/credential_ui_entry.h b/components/password_manager/core/browser/ui/credential_ui_entry.h
index 602a6a14..628f4fef 100644
--- a/components/password_manager/core/browser/ui/credential_ui_entry.h
+++ b/components/password_manager/core/browser/ui/credential_ui_entry.h
@@ -115,6 +115,9 @@
   // The origin of identity provider used for federated login.
   url::Origin federation_origin;
 
+  // The creation time, if this is a passkey, nullopt otherwise.
+  std::optional<base::Time> creation_time;
+
   // Indicates the stores where the credential is stored.
   base::flat_set<PasswordForm::Store> stored_in;
 
diff --git a/content/browser/interest_group/auction_runner_unittest.cc b/content/browser/interest_group/auction_runner_unittest.cc
index eb0800c..fa7fe82 100644
--- a/content/browser/interest_group/auction_runner_unittest.cc
+++ b/content/browser/interest_group/auction_runner_unittest.cc
@@ -22532,10 +22532,6 @@
 }
 
 TEST_F(AuctionRunnerTest, TrustedBiddingSignalsJointBatchedRequests) {
-  base::test::ScopedFeatureList debug_features;
-  debug_features.InitAndEnableFeature(
-      blink::features::kFledgeSplitTrustedSignalsFetchingURL);
-
   url_loader_factory_.ClearResponses();
   auction_worklet::AddJavascriptResponse(
       &url_loader_factory_, kBidder1Url,
@@ -22578,10 +22574,6 @@
 }
 
 TEST_F(AuctionRunnerTest, TrustedBiddingSignalsSplitBatchedRequests) {
-  base::test::ScopedFeatureList debug_features;
-  debug_features.InitAndEnableFeature(
-      blink::features::kFledgeSplitTrustedSignalsFetchingURL);
-
   url_loader_factory_.ClearResponses();
   auction_worklet::AddJavascriptResponse(
       &url_loader_factory_, kBidder1Url,
@@ -22626,10 +22618,6 @@
 }
 
 TEST_F(AuctionRunnerTest, TrustedScoringSignalsJointBatchedRequests) {
-  base::test::ScopedFeatureList debug_features;
-  debug_features.InitAndEnableFeature(
-      blink::features::kFledgeSplitTrustedSignalsFetchingURL);
-
   url_loader_factory_.ClearResponses();
   trusted_scoring_signals_url_ =
       GURL("https://adstuff.publisher1.com/seller_signals");
@@ -22670,10 +22658,6 @@
 }
 
 TEST_F(AuctionRunnerTest, TrustedScoringSignalsSplitBatchedRequests) {
-  base::test::ScopedFeatureList debug_features;
-  debug_features.InitAndEnableFeature(
-      blink::features::kFledgeSplitTrustedSignalsFetchingURL);
-
   url_loader_factory_.ClearResponses();
   trusted_scoring_signals_url_ =
       GURL("https://adstuff.publisher1.com/seller_signals");
diff --git a/content/services/auction_worklet/trusted_signals_request_manager_unittest.cc b/content/services/auction_worklet/trusted_signals_request_manager_unittest.cc
index fcc98448..53ac839 100644
--- a/content/services/auction_worklet/trusted_signals_request_manager_unittest.cc
+++ b/content/services/auction_worklet/trusted_signals_request_manager_unittest.cc
@@ -277,18 +277,6 @@
   TrustedSignalsRequestManager scoring_request_manager_;
 };
 
-class TrustedSignalsRequestManagerSplitURLTest
-    : public TrustedSignalsRequestManagerTest {
- public:
-  TrustedSignalsRequestManagerSplitURLTest() {
-    feature_list_.InitAndEnableFeature(
-        blink::features::kFledgeSplitTrustedSignalsFetchingURL);
-  }
-
- protected:
-  base::test::ScopedFeatureList feature_list_;
-};
-
 TEST_F(TrustedSignalsRequestManagerTest, BiddingSignalsError) {
   url_loader_factory_.AddResponse(
       "https://url.test/?hostname=publisher&keys=key1&interestGroupNames=name1"
@@ -1403,7 +1391,7 @@
 // TODO(crbug.com/326082728): Remove this test because it will be duplicated
 // with `BiddingSignalsOneRequest` after the split feature is enabled by
 // default.
-TEST_F(TrustedSignalsRequestManagerSplitURLTest,
+TEST_F(TrustedSignalsRequestManagerTest,
        BiddingSignalsOneRequestWithZeroLimit) {
   const std::vector<std::string> kKeys{"key2", "key1"};
   const std::string kUrl =
@@ -1436,7 +1424,7 @@
 // Test a single scoring request with 0 (unlimited) length limit.
 // TODO(xtlsheep): Remove this test because it will be duplicated with
 // `ScoringSignalsOneRequest` after the split feature is enabled by default.
-TEST_F(TrustedSignalsRequestManagerSplitURLTest,
+TEST_F(TrustedSignalsRequestManagerTest,
        ScoringSignalsOneRequestWithZeroLimit) {
   const GURL kRenderUrl = GURL("https://foo.test/");
   const std::vector<std::string> kAdComponentRenderUrls{
@@ -1468,7 +1456,7 @@
 
 // Test a single bidding request with a tiny length limit that is smaller than
 // the URL generated by itself.
-TEST_F(TrustedSignalsRequestManagerSplitURLTest,
+TEST_F(TrustedSignalsRequestManagerTest,
        BiddingSignalsOneRequestWithTinyLimit) {
   const std::vector<std::string> kKeys{"key2", "key1"};
   const std::string kUrl =
@@ -1500,7 +1488,7 @@
 
 // Test a single scoring request with a tiny length limit that is smaller than
 // the URL generated by itself.
-TEST_F(TrustedSignalsRequestManagerSplitURLTest,
+TEST_F(TrustedSignalsRequestManagerTest,
        ScoringSignalsOneRequestWithTinyLimit) {
   const GURL kRenderUrl = GURL("https://foo.test/");
   const std::vector<std::string> kAdComponentRenderUrls{
@@ -1532,7 +1520,7 @@
 
 // Test a single bidding request with normal length limit that is larger than
 // the URL generated by itself.
-TEST_F(TrustedSignalsRequestManagerSplitURLTest,
+TEST_F(TrustedSignalsRequestManagerTest,
        BiddingSignalsOneRequestWithNormalLimit) {
   const std::vector<std::string> kKeys{"key2", "key1"};
   const std::string kUrl =
@@ -1565,7 +1553,7 @@
 
 // Test a single scoring request with normal length limit that is larger than
 // the URL generated by itself.
-TEST_F(TrustedSignalsRequestManagerSplitURLTest,
+TEST_F(TrustedSignalsRequestManagerTest,
        ScoringSignalsOneRequestWithNormalLimit) {
   const GURL kRenderUrl = GURL("https://foo.test/");
   const std::vector<std::string> kAdComponentRenderUrls{
@@ -1600,8 +1588,7 @@
 // Request A has a limit of 0.
 // Request B has a limit of 1000.
 // The combined URL length of requests A and B is 131.
-TEST_F(TrustedSignalsRequestManagerSplitURLTest,
-       BiddingSignalsJointBatchedRequests) {
+TEST_F(TrustedSignalsRequestManagerTest, BiddingSignalsJointBatchedRequests) {
   // Use partially overlapping keys, to cover both the shared and distinct key
   // cases.
   const std::vector<std::string> kKeys1{"key1", "key3"};
@@ -1667,8 +1654,7 @@
 // Request A has a limit of 0.
 // Request B has a limit of 1000.
 // The combined URL length of requests A and B is 208.
-TEST_F(TrustedSignalsRequestManagerSplitURLTest,
-       ScoringSignalsJointBatchedRequests) {
+TEST_F(TrustedSignalsRequestManagerTest, ScoringSignalsJointBatchedRequests) {
   // Use partially overlapping keys, to cover both the shared and distinct
   // cases.
   const GURL kRenderUrl1 = GURL("https://foo.test/");
@@ -1744,8 +1730,7 @@
 // Request A has a limit of 130.
 // Request B has a limit of 130.
 // The combined URL length of requests A and B is 131.
-TEST_F(TrustedSignalsRequestManagerSplitURLTest,
-       BiddingSignalsSplitBatchedRequests) {
+TEST_F(TrustedSignalsRequestManagerTest, BiddingSignalsSplitBatchedRequests) {
   const std::vector<std::string> kKeys1{"key1", "key3"};
   const std::string kUrl1 =
       "https://url.test/?hostname=publisher"
@@ -1821,8 +1806,7 @@
 // Request A has a limit of 200.
 // Request B has a limit of 200.
 // The combined URL length of requests A and B is 208.
-TEST_F(TrustedSignalsRequestManagerSplitURLTest,
-       ScoringSignalsSplitBatchedRequests) {
+TEST_F(TrustedSignalsRequestManagerTest, ScoringSignalsSplitBatchedRequests) {
   // Use partially overlapping keys, to cover both the shared and distinct
   // cases.
   const GURL kRenderUrl1 = GURL("https://foo.test/");
@@ -1908,7 +1892,7 @@
 // Request C has a limit of 130.
 // The combined URL length of requests A and B is 131.
 // The combined URL length of requests A, B and C is 137.
-TEST_F(TrustedSignalsRequestManagerSplitURLTest,
+TEST_F(TrustedSignalsRequestManagerTest,
        BiddingSignalsPartlyJointBatchedRequests1) {
   const std::vector<std::string> kKeys1{"key1", "key3"};
   const std::vector<std::string> kKeys2{"key2", "key3"};
@@ -2003,7 +1987,7 @@
 // Request C has a limit of 200.
 // The combined URL length of requests A and B is 208.
 // The combined URL length of requests A, B and C is 234.
-TEST_F(TrustedSignalsRequestManagerSplitURLTest,
+TEST_F(TrustedSignalsRequestManagerTest,
        ScoringSignalsPartlyJointBatchedRequests1) {
   const GURL kRenderUrl1 = GURL("https://bar.test/");
   const std::vector<std::string> kAdComponentRenderUrls1{
@@ -2113,7 +2097,7 @@
 // Request C has a limit of 131.
 // The combined URL length of requests A and B is 143.
 // The combined URL length of requests B and C is 131.
-TEST_F(TrustedSignalsRequestManagerSplitURLTest,
+TEST_F(TrustedSignalsRequestManagerTest,
        BiddingSignalsPartlyJointBatchedRequests2) {
   const std::vector<std::string> kKeys1{"key1", "key3"};
   const std::vector<std::string> kKeys2{"key2", "key3"};
@@ -2211,7 +2195,7 @@
 // Request C has a limit of 208.
 // The combined URL length of requests A and B is 221.
 // The combined URL length of requests B and C is 208.
-TEST_F(TrustedSignalsRequestManagerSplitURLTest,
+TEST_F(TrustedSignalsRequestManagerTest,
        ScoringSignalsPartlyJointBatchedRequests2) {
   const GURL kRenderUrl1 = GURL("https://barExtremelyLong.test/");
   const std::vector<std::string> kAdComponentRenderUrls1{
@@ -2318,8 +2302,7 @@
 // bidder keys will result two separate fetch request.
 // Request A has a limit of 104.
 // Request B has a limit of 104.
-TEST_F(TrustedSignalsRequestManagerSplitURLTest,
-       BiddingSignalsIdenticalRequests) {
+TEST_F(TrustedSignalsRequestManagerTest, BiddingSignalsIdenticalRequests) {
   const std::string kUrl =
       "https://url.test/?hostname=publisher"
       "&interestGroupNames=name"
@@ -2377,8 +2360,7 @@
 // ad component urls will result two separate fetch request.
 // Request A has a limit of 73.
 // Request B has a limit of 73.
-TEST_F(TrustedSignalsRequestManagerSplitURLTest,
-       ScoringSignalsIdenticalRequests) {
+TEST_F(TrustedSignalsRequestManagerTest, ScoringSignalsIdenticalRequests) {
   // Use partially overlapping keys, to cover both the shared and distinct
   // cases.
   const GURL kRenderUrl = GURL("https://foo.test/");
diff --git a/infra/config/generated/testing/variants.pyl b/infra/config/generated/testing/variants.pyl
index 145fe80..bc24210 100644
--- a/infra/config/generated/testing/variants.pyl
+++ b/infra/config/generated/testing/variants.pyl
@@ -267,16 +267,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'identifier': 'Lacros version skew testing ash canary',
-    'description': 'Run with ash-chrome version 126.0.6472.0',
+    'description': 'Run with ash-chrome version 126.0.6475.0',
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6472.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome',
     ],
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v126.0.6472.0',
-          'revision': 'version:126.0.6472.0',
+          'location': 'lacros_version_skew_tests_v126.0.6475.0',
+          'revision': 'version:126.0.6475.0',
         },
       ],
     },
diff --git a/infra/config/targets/lacros-version-skew-variants.json b/infra/config/targets/lacros-version-skew-variants.json
index b7a010d..4acc33c 100644
--- a/infra/config/targets/lacros-version-skew-variants.json
+++ b/infra/config/targets/lacros-version-skew-variants.json
@@ -1,16 +1,16 @@
 {
   "LACROS_VERSION_SKEW_CANARY": {
     "args": [
-      "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6472.0/test_ash_chrome"
+      "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome"
     ],
-    "description": "Run with ash-chrome version 126.0.6472.0",
+    "description": "Run with ash-chrome version 126.0.6475.0",
     "identifier": "Lacros version skew testing ash canary",
     "swarming": {
       "cipd_packages": [
         {
           "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-          "location": "lacros_version_skew_tests_v126.0.6472.0",
-          "revision": "version:126.0.6472.0"
+          "location": "lacros_version_skew_tests_v126.0.6475.0",
+          "revision": "version:126.0.6475.0"
         }
       ]
     }
diff --git a/internal b/internal
index 4d87df6..e635ef2 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit 4d87df689432aab83f5fad3a0b3230fe78dd7a4e
+Subproject commit e635ef2a5ee69af88e8d02569f2505fe336271a8
diff --git a/ios/build/chrome_build.gni b/ios/build/chrome_build.gni
index a04c05e0..dfbbf4d 100644
--- a/ios/build/chrome_build.gni
+++ b/ios/build/chrome_build.gni
@@ -38,7 +38,7 @@
   ios_enable_shortcuts_widget = true
 
   # Enable iOS Push Notification Service extension.
-  ios_enable_push_notification_service_extension = false
+  ios_enable_push_notification_service_extension = true
 
   # Label of the target providing implementation for AccountVerificationProvider.
   # Overridden when using the Google-internal repository to build Chrome on iOS.
diff --git a/ios/chrome/browser/ntp/model/set_up_list.h b/ios/chrome/browser/ntp/model/set_up_list.h
index 3f4bb25..a084b0c 100644
--- a/ios/chrome/browser/ntp/model/set_up_list.h
+++ b/ios/chrome/browser/ntp/model/set_up_list.h
@@ -25,16 +25,20 @@
 // `localState` is used to store each SetUpListItem's state.
 // `authenticationService` is used to determine signed-in status. Returns `nil`
 // if the Set Up List has been disabled in local state prefs.
+// `contentNotificationEnabled` is `YES` if the user is enabled to content
+// notifications.
 + (instancetype)buildFromPrefs:(PrefService*)prefs
                     localState:(PrefService*)localState
                    syncService:(syncer::SyncService*)syncService
-         authenticationService:(AuthenticationService*)authService;
+         authenticationService:(AuthenticationService*)authService
+    contentNotificationEnabled:(BOOL)isContentNotificationEnabled;
 
 // Initializes a SetUpList with the given `items`. `localState` is used to
 // store the state of each item and to observe changes to that state.
 - (instancetype)initWithItems:(NSArray<SetUpListItem*>*)items
-                   localState:(PrefService*)localState
-        authenticationService:(AuthenticationService*)authService
+                    localState:(PrefService*)localState
+         authenticationService:(AuthenticationService*)authService
+    contentNotificationEnabled:(BOOL)isContentNotificationEnabled
     NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)init NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/ntp/model/set_up_list.mm b/ios/chrome/browser/ntp/model/set_up_list.mm
index 244963f..fbdfa04a 100644
--- a/ios/chrome/browser/ntp/model/set_up_list.mm
+++ b/ios/chrome/browser/ntp/model/set_up_list.mm
@@ -137,7 +137,8 @@
 + (instancetype)buildFromPrefs:(PrefService*)prefs
                     localState:(PrefService*)localState
                    syncService:(syncer::SyncService*)syncService
-         authenticationService:(AuthenticationService*)authService {
+         authenticationService:(AuthenticationService*)authService
+    contentNotificationEnabled:(BOOL)isContentNotificationEnabled {
   if (set_up_list_prefs::IsSetUpListDisabled(localState)) {
     return nil;
   }
@@ -159,11 +160,8 @@
   AddItemIfNotNil(items, BuildItem(SetUpListItemType::kAutofill, prefs,
                                    localState, authService));
 
-  // Add content notification item if the feature is enabled and the user has
-  // signed in.
-  if (IsIOSTipsNotificationsEnabled() ||
-      (IsContentPushNotificationsSetUpListEnabled() &&
-       authService->HasPrimaryIdentity(signin::ConsentLevel::kSignin))) {
+  // Add content notification item if the feature is enabled.
+  if (IsIOSTipsNotificationsEnabled() || isContentNotificationEnabled) {
     AddItemIfNotNil(items, BuildItem(SetUpListItemType::kNotifications, prefs,
                                      localState, authService));
   }
@@ -182,12 +180,14 @@
   // TODO(crbug.com/40262090): Add a Follow item to the Set Up List.
   return [[self alloc] initWithItems:items
                           localState:localState
-               authenticationService:authService];
+               authenticationService:authService
+          contentNotificationEnabled:isContentNotificationEnabled];
 }
 
 - (instancetype)initWithItems:(NSArray<SetUpListItem*>*)items
-                   localState:(PrefService*)localState
-        authenticationService:(AuthenticationService*)authService {
+                    localState:(PrefService*)localState
+         authenticationService:(AuthenticationService*)authService
+    contentNotificationEnabled:(BOOL)isContentNotificationEnabled {
   self = [super init];
   if (self) {
     _items = items;
@@ -205,9 +205,7 @@
     _prefObserverBridge->ObserveChangesForPreference(
         set_up_list_prefs::kNotificationsItemState, &_prefChangeRegistrar);
     _shouldIncludeNotificationItem =
-        IsIOSTipsNotificationsEnabled() ||
-        (IsContentPushNotificationsSetUpListEnabled() &&
-         authService->HasPrimaryIdentity(signin::ConsentLevel::kSignin));
+        IsIOSTipsNotificationsEnabled() || isContentNotificationEnabled;
   }
   return self;
 }
diff --git a/ios/chrome/browser/ntp/model/set_up_list_unittest.mm b/ios/chrome/browser/ntp/model/set_up_list_unittest.mm
index e630f07..f94c5fb9 100644
--- a/ios/chrome/browser/ntp/model/set_up_list_unittest.mm
+++ b/ios/chrome/browser/ntp/model/set_up_list_unittest.mm
@@ -61,6 +61,7 @@
         std::make_unique<FakeAuthenticationServiceDelegate>());
     auth_service_ =
         AuthenticationServiceFactory::GetForBrowserState(GetBrowserState());
+    content_notification_feature_enabled_ = false;
   }
 
   ~SetUpListTest() override { [set_up_list_ disconnect]; }
@@ -80,10 +81,11 @@
     [set_up_list_ disconnect];
     set_up_list_ =
         [SetUpList buildFromPrefs:prefs_
-                       localState:GetLocalState()
-                      syncService:SyncServiceFactory::GetForBrowserState(
-                                      GetBrowserState())
-            authenticationService:auth_service_];
+                            localState:GetLocalState()
+                           syncService:SyncServiceFactory::GetForBrowserState(
+                                           GetBrowserState())
+                 authenticationService:auth_service_
+            contentNotificationEnabled:content_notification_feature_enabled_];
   }
 
   // Fakes a sign-in with a fake identity.
@@ -178,6 +180,7 @@
   std::unique_ptr<TestChromeBrowserStateManager> test_manager_;
   raw_ptr<AuthenticationService> auth_service_;
   SetUpList* set_up_list_;
+  bool content_notification_feature_enabled_;
 };
 
 // Tests the SignInSync item is hidden if sync is disabled by policy.
@@ -289,10 +292,7 @@
 // Tests that the SetUpList uses the correct criteria when including the
 // Notifications item and content notifications is enabled.
 TEST_F(SetUpListTest, BuildListWithNotifications_Content) {
-  feature_list_.InitAndEnableFeatureWithParameters(
-      kContentPushNotifications,
-      {{kContentPushNotificationsExperimentType, "2"}});
-  SignInFakeIdentity();
+  content_notification_feature_enabled_ = YES;
 
   SetContentNotificationsEnabled(false);
   BuildSetUpList();
diff --git a/ios/chrome/browser/ui/content_suggestions/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
index 30d94e0..2a043b3 100644
--- a/ios/chrome/browser/ui/content_suggestions/BUILD.gn
+++ b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
@@ -25,6 +25,7 @@
     "//components/password_manager/core/browser/ui:credential_ui_entry",
     "//components/pref_registry",
     "//components/prefs",
+    "//components/search_engines",
     "//components/segmentation_platform/public",
     "//components/strings",
     "//components/sync/base:features",
@@ -52,6 +53,7 @@
     "//ios/chrome/browser/reading_list/model",
     "//ios/chrome/browser/safety_check/model",
     "//ios/chrome/browser/safety_check/model:factory",
+    "//ios/chrome/browser/search_engines/model:template_url_service_factory",
     "//ios/chrome/browser/segmentation_platform/model",
     "//ios/chrome/browser/shared/coordinator/alert",
     "//ios/chrome/browser/shared/coordinator/chrome_coordinator",
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
index a981bbc..42be34b 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
@@ -16,6 +16,10 @@
 #import "components/password_manager/core/browser/ui/credential_ui_entry.h"
 #import "components/password_manager/core/browser/ui/password_check_referrer.h"
 #import "components/prefs/pref_service.h"
+#import "components/search_engines/prepopulated_engines.h"
+#import "components/search_engines/template_url.h"
+#import "components/search_engines/template_url_prepopulate_data.h"
+#import "components/search_engines/template_url_service.h"
 #import "components/segmentation_platform/public/features.h"
 #import "ios/chrome/app/application_delegate/app_state.h"
 #import "ios/chrome/app/tests_hook.h"
@@ -40,6 +44,7 @@
 #import "ios/chrome/browser/reading_list/model/reading_list_model_factory.h"
 #import "ios/chrome/browser/safety_check/model/ios_chrome_safety_check_manager.h"
 #import "ios/chrome/browser/safety_check/model/ios_chrome_safety_check_manager_factory.h"
+#import "ios/chrome/browser/search_engines/model/template_url_service_factory.h"
 #import "ios/chrome/browser/segmentation_platform/model/segmentation_platform_service_factory.h"
 #import "ios/chrome/browser/shared/coordinator/alert/action_sheet_coordinator.h"
 #import "ios/chrome/browser/shared/coordinator/alert/alert_coordinator.h"
@@ -294,6 +299,14 @@
     _setUpListMediator.contentSuggestionsMetricsRecorder =
         self.contentSuggestionsMetricsRecorder;
     _setUpListMediator.delegate = self.delegate;
+    const TemplateURL* defaultSearchURLTemplate =
+        ios::TemplateURLServiceFactory::GetForBrowserState(
+            self.browser->GetBrowserState())
+            ->GetDefaultSearchProvider();
+    BOOL isDefaultSearchEngine = defaultSearchURLTemplate &&
+                                 defaultSearchURLTemplate->prepopulate_id() ==
+                                     TemplateURLPrepopulateData::google.id;
+    _setUpListMediator.isDefaultSearchEngine = isDefaultSearchEngine;
     self.contentSuggestionsMediator.setUpListMediator = _setUpListMediator;
     [moduleMediators addObject:_setUpListMediator];
   }
diff --git a/ios/chrome/browser/ui/content_suggestions/set_up_list/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/set_up_list/BUILD.gn
index ad66fa5f..1c2626b 100644
--- a/ios/chrome/browser/ui/content_suggestions/set_up_list/BUILD.gn
+++ b/ios/chrome/browser/ui/content_suggestions/set_up_list/BUILD.gn
@@ -29,9 +29,11 @@
     "//components/password_manager/core/common:features",
     "//components/prefs",
     "//components/prefs/ios",
+    "//components/signin/public/identity_manager",
     "//components/signin/public/identity_manager/objc",
     "//components/sync/base:features",
     "//ios/chrome/app/strings",
+    "//ios/chrome/browser/content_notification/model:util",
     "//ios/chrome/browser/default_browser/model:utils",
     "//ios/chrome/browser/ntp/model:set_up_list",
     "//ios/chrome/browser/ntp/model:set_up_list_item_type",
diff --git a/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_mediator.h b/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_mediator.h
index 762804c7..9dd8ba6 100644
--- a/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_mediator.h
+++ b/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_mediator.h
@@ -107,6 +107,9 @@
 @property(nonatomic, weak)
     ContentSuggestionsMetricsRecorder* contentSuggestionsMetricsRecorder;
 
+// `YES` if the user is using Google as default search engine.
+@property(nonatomic, assign) BOOL isDefaultSearchEngine;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_SET_UP_LIST_SET_UP_LIST_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_mediator.mm b/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_mediator.mm
index b56c6472..1d62b77 100644
--- a/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_mediator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/set_up_list/set_up_list_mediator.mm
@@ -11,7 +11,9 @@
 #import "base/strings/sys_string_conversions.h"
 #import "components/prefs/ios/pref_observer_bridge.h"
 #import "components/prefs/pref_service.h"
+#import "components/signin/public/identity_manager/identity_manager.h"
 #import "components/signin/public/identity_manager/objc/identity_manager_observer_bridge.h"
+#import "ios/chrome/browser/content_notification/model/content_notification_util.h"
 #import "ios/chrome/browser/default_browser/model/utils.h"
 #import "ios/chrome/browser/ntp/model/set_up_list.h"
 #import "ios/chrome/browser/ntp/model/set_up_list_delegate.h"
@@ -166,10 +168,15 @@
     _sceneState = sceneState;
     [_sceneState addObserver:self];
 
+    BOOL isUserSignedIn =
+        identityManager->HasPrimaryAccount(signin::ConsentLevel::kSignin);
+    BOOL isContentNotificationEnabled = IsContentNotificationSetUpListEnabled(
+        isUserSignedIn, self.isDefaultSearchEngine, prefService);
     _setUpList = [SetUpList buildFromPrefs:prefService
                                 localState:_localState
                                syncService:syncService
-                     authenticationService:authService];
+                     authenticationService:authService
+                contentNotificationEnabled:isContentNotificationEnabled];
     _setUpList.delegate = self;
 
     _consumers = [SetUpListConsumerList
diff --git a/ios/chrome/push_notification_service_extension/push_notification_service_extension.mm b/ios/chrome/push_notification_service_extension/push_notification_service_extension.mm
new file mode 100644
index 0000000..7084364
--- /dev/null
+++ b/ios/chrome/push_notification_service_extension/push_notification_service_extension.mm
@@ -0,0 +1,21 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/push_notification_service_extension/push_notification_service_extension.h"
+
+@implementation PushNotificationServiceExtension
+
+- (instancetype)init {
+  self = [super init];
+  return self;
+}
+
+- (void)didReceiveNotificationRequest:(UNNotificationRequest*)request
+                   withContentHandler:
+                       (void (^)(UNNotificationContent* contentToDeliver))
+                           contentHandler {
+  contentHandler(request.content);
+}
+
+@end
\ No newline at end of file
diff --git a/ios_internal b/ios_internal
index de983f7..a4bca5f 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit de983f7b4091b42ba405f8d75909e47d4bf7c0d8
+Subproject commit a4bca5f99ed1d6460e444e82d9359ef57826fa0b
diff --git a/media/capture/video/chromeos/camera_app_device_impl.cc b/media/capture/video/chromeos/camera_app_device_impl.cc
index 1bae9689..afde802 100644
--- a/media/capture/video/chromeos/camera_app_device_impl.cc
+++ b/media/capture/video/chromeos/camera_app_device_impl.cc
@@ -17,6 +17,7 @@
 #include "media/capture/video/chromeos/camera_metadata_utils.h"
 #include "media/capture/video/chromeos/mojom/document_scanner.mojom.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/cros_system_api/mojo/service_constants.h"
 #include "third_party/libyuv/include/libyuv.h"
 
 namespace media {
@@ -38,9 +39,8 @@
     if (!ash::mojo_service_manager::IsServiceManagerBound()) {
       return;
     }
-    // TODO(b/333927344): Add service name to chromeos::mojo_services.
     ash::mojo_service_manager::GetServiceManagerProxy()->Request(
-        "CrosDocumentScanner", std::nullopt,
+        chromeos::mojo_services::kCrosDocumentScanner, std::nullopt,
         document_scanner_remote_.BindNewPipeAndPassReceiver().PassPipe());
   }
 
diff --git a/media/gpu/chromeos/image_processor_backend.cc b/media/gpu/chromeos/image_processor_backend.cc
index 15c1e8c..79359cf8 100644
--- a/media/gpu/chromeos/image_processor_backend.cc
+++ b/media/gpu/chromeos/image_processor_backend.cc
@@ -131,6 +131,15 @@
 
 void default_delete<media::ImageProcessorBackend>::operator()(
     media::ImageProcessorBackend* ptr) const {
+  CHECK(ptr->backend_task_runner_);
+  if (!ptr->backend_task_runner_->RunsTasksInCurrentSequence()) {
+    // base::Unretained() is safe because ImageProcessorBackend::Destroy() *is*
+    // the thing that destroys *|ptr|.
+    ptr->backend_task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(&media::ImageProcessorBackend::Destroy,
+                                  base::Unretained(ptr)));
+    return;
+  }
   ptr->Destroy();
 }
 
diff --git a/media/gpu/chromeos/image_processor_backend.h b/media/gpu/chromeos/image_processor_backend.h
index 6f4b61a..7caf844 100644
--- a/media/gpu/chromeos/image_processor_backend.h
+++ b/media/gpu/chromeos/image_processor_backend.h
@@ -162,7 +162,7 @@
 
 namespace std {
 
-// Specialize std::default_delete to call Destroy().
+// Specialize std::default_delete to call Destroy() on the right sequence.
 template <>
 struct MEDIA_GPU_EXPORT default_delete<media::ImageProcessorBackend> {
   constexpr default_delete() = default;
diff --git a/net/http/transport_security_state_static.pins b/net/http/transport_security_state_static.pins
index 3b24ade..d256bc8 100644
--- a/net/http/transport_security_state_static.pins
+++ b/net/http/transport_security_state_static.pins
@@ -43,9 +43,9 @@
 #   hash function for preloaded entries again (we have already done so once).
 #
 
-# Last updated: 2024-05-11 12:56 UTC
+# Last updated: 2024-05-12 12:55 UTC
 PinsListTimestamp
-1715432165
+1715518505
 
 TestSPKI
 sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
diff --git a/net/http/transport_security_state_static_pins.json b/net/http/transport_security_state_static_pins.json
index 0fd74d2..4ea2cd4 100644
--- a/net/http/transport_security_state_static_pins.json
+++ b/net/http/transport_security_state_static_pins.json
@@ -31,7 +31,7 @@
 // the 'static_spki_hashes' and 'bad_static_spki_hashes' fields in 'pinsets'
 // refer to, and the timestamp at which the pins list was last updated.
 //
-// Last updated: 2024-05-11 12:56 UTC
+// Last updated: 2024-05-12 12:55 UTC
 //
 {
   "pinsets": [
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index f7b8691..d0829e4 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5487,9 +5487,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6472.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6472.0",
+        "description": "Run with ash-chrome version 126.0.6475.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5499,8 +5499,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6472.0",
-              "revision": "version:126.0.6472.0"
+              "location": "lacros_version_skew_tests_v126.0.6475.0",
+              "revision": "version:126.0.6475.0"
             }
           ],
           "dimensions": {
@@ -5643,9 +5643,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6472.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6472.0",
+        "description": "Run with ash-chrome version 126.0.6475.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5655,8 +5655,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6472.0",
-              "revision": "version:126.0.6472.0"
+              "location": "lacros_version_skew_tests_v126.0.6475.0",
+              "revision": "version:126.0.6475.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json
index aa69a3db..560f12e 100644
--- a/testing/buildbot/chromium.coverage.json
+++ b/testing/buildbot/chromium.coverage.json
@@ -19664,9 +19664,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6472.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6472.0",
+        "description": "Run with ash-chrome version 126.0.6475.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -19676,8 +19676,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6472.0",
-              "revision": "version:126.0.6472.0"
+              "location": "lacros_version_skew_tests_v126.0.6475.0",
+              "revision": "version:126.0.6475.0"
             }
           ],
           "dimensions": {
@@ -19820,9 +19820,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6472.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6472.0",
+        "description": "Run with ash-chrome version 126.0.6475.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -19832,8 +19832,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6472.0",
-              "revision": "version:126.0.6472.0"
+              "location": "lacros_version_skew_tests_v126.0.6475.0",
+              "revision": "version:126.0.6475.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index f1e987a..eaf6514 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -41840,9 +41840,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6472.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6472.0",
+        "description": "Run with ash-chrome version 126.0.6475.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -41851,8 +41851,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6472.0",
-              "revision": "version:126.0.6472.0"
+              "location": "lacros_version_skew_tests_v126.0.6475.0",
+              "revision": "version:126.0.6475.0"
             }
           ],
           "dimensions": {
@@ -41990,9 +41990,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6472.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6472.0",
+        "description": "Run with ash-chrome version 126.0.6475.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -42001,8 +42001,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6472.0",
-              "revision": "version:126.0.6472.0"
+              "location": "lacros_version_skew_tests_v126.0.6475.0",
+              "revision": "version:126.0.6475.0"
             }
           ],
           "dimensions": {
@@ -43339,9 +43339,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6472.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6472.0",
+        "description": "Run with ash-chrome version 126.0.6475.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -43351,8 +43351,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6472.0",
-              "revision": "version:126.0.6472.0"
+              "location": "lacros_version_skew_tests_v126.0.6475.0",
+              "revision": "version:126.0.6475.0"
             }
           ],
           "dimensions": {
@@ -43495,9 +43495,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6472.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6472.0",
+        "description": "Run with ash-chrome version 126.0.6475.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -43507,8 +43507,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6472.0",
-              "revision": "version:126.0.6472.0"
+              "location": "lacros_version_skew_tests_v126.0.6475.0",
+              "revision": "version:126.0.6475.0"
             }
           ],
           "dimensions": {
@@ -44820,9 +44820,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6472.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6472.0",
+        "description": "Run with ash-chrome version 126.0.6475.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -44831,8 +44831,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6472.0",
-              "revision": "version:126.0.6472.0"
+              "location": "lacros_version_skew_tests_v126.0.6475.0",
+              "revision": "version:126.0.6475.0"
             }
           ],
           "dimensions": {
@@ -44970,9 +44970,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6472.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6472.0",
+        "description": "Run with ash-chrome version 126.0.6475.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -44981,8 +44981,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6472.0",
-              "revision": "version:126.0.6472.0"
+              "location": "lacros_version_skew_tests_v126.0.6475.0",
+              "revision": "version:126.0.6475.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index b6c4e44a..f0664153 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -15763,12 +15763,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6472.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 126.0.6472.0",
+        "description": "Run with ash-chrome version 126.0.6475.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -15778,8 +15778,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6472.0",
-              "revision": "version:126.0.6472.0"
+              "location": "lacros_version_skew_tests_v126.0.6475.0",
+              "revision": "version:126.0.6475.0"
             }
           ],
           "dimensions": {
@@ -15939,12 +15939,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6472.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 126.0.6472.0",
+        "description": "Run with ash-chrome version 126.0.6475.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -15954,8 +15954,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6472.0",
-              "revision": "version:126.0.6472.0"
+              "location": "lacros_version_skew_tests_v126.0.6475.0",
+              "revision": "version:126.0.6475.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 145fe80..bc24210 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -267,16 +267,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'identifier': 'Lacros version skew testing ash canary',
-    'description': 'Run with ash-chrome version 126.0.6472.0',
+    'description': 'Run with ash-chrome version 126.0.6475.0',
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6472.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6475.0/test_ash_chrome',
     ],
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v126.0.6472.0',
-          'revision': 'version:126.0.6472.0',
+          'location': 'lacros_version_skew_tests_v126.0.6475.0',
+          'revision': 'version:126.0.6475.0',
         },
       ],
     },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 79b6ffc..c433701f7 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -15941,26 +15941,6 @@
             ]
         }
     ],
-    "ProtectedAudiencesSplitTrustedSignalsFetchingURL": [
-        {
-            "platforms": [
-                "android",
-                "chromeos",
-                "chromeos_lacros",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "FledgeSplitTrustedSignalsFetchingURL"
-                    ]
-                }
-            ]
-        }
-    ],
     "ProtectedAudiencesUpdateIfOlderThanMs": [
         {
             "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 237b6e601..e9ef551 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -1013,7 +1013,7 @@
 
 BASE_FEATURE(kFledgeSplitTrustedSignalsFetchingURL,
              "FledgeSplitTrustedSignalsFetchingURL",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 const base::FeatureParam<int> kFledgeCustomMaxAuctionAdComponentsValue{
     &kFledgeCustomMaxAuctionAdComponents, "FledgeAdComponentLimit",
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index 4a828dc..4a2144d 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -5207,7 +5207,7 @@
       field_group: "box",
       field_template: "external",
       include_paths: ["third_party/blink/renderer/core/style/text_box_edge.h"],
-      default_value: "TextBoxEdge(TextBoxEdge::TextBoxEdgeType::kLeading)",
+      default_value: "TextBoxEdge()",
       type_name: "TextBoxEdge",
       converter: "ConvertTextBoxEdge",
       runtime_flag: "CSSTextBoxTrim",
diff --git a/third_party/blink/renderer/core/css/css_value_id_mappings.h b/third_party/blink/renderer/core/css/css_value_id_mappings.h
index bb6c3e5a..60e66738 100644
--- a/third_party/blink/renderer/core/css/css_value_id_mappings.h
+++ b/third_party/blink/renderer/core/css/css_value_id_mappings.h
@@ -453,26 +453,26 @@
 }
 
 template <>
-inline TextBoxEdge::TextBoxEdgeType CssValueIDToPlatformEnum(CSSValueID id) {
+inline TextBoxEdge::Type CssValueIDToPlatformEnum(CSSValueID id) {
   switch (id) {
     case CSSValueID::kLeading:
-      return TextBoxEdge::TextBoxEdgeType::kLeading;
+      return TextBoxEdge::Type::kLeading;
     case CSSValueID::kText:
-      return TextBoxEdge::TextBoxEdgeType::kText;
+      return TextBoxEdge::Type::kText;
     case CSSValueID::kCap:
-      return TextBoxEdge::TextBoxEdgeType::kCap;
+      return TextBoxEdge::Type::kCap;
     case CSSValueID::kEx:
-      return TextBoxEdge::TextBoxEdgeType::kEx;
+      return TextBoxEdge::Type::kEx;
     case CSSValueID::kAlphabetic:
-      return TextBoxEdge::TextBoxEdgeType::kAlphabetic;
+      return TextBoxEdge::Type::kAlphabetic;
     default:
       NOTREACHED_NORETURN();
   }
 }
 
 template <>
-inline CSSValueID PlatformEnumToCSSValueID(TextBoxEdge::TextBoxEdgeType type) {
-  using enum TextBoxEdge::TextBoxEdgeType;
+inline CSSValueID PlatformEnumToCSSValueID(TextBoxEdge::Type type) {
+  using enum TextBoxEdge::Type;
   switch (type) {
     case kLeading:
       return CSSValueID::kLeading;
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
index 97fa5f8a..55c3b6e 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -8508,8 +8508,8 @@
   if (text_box_edge.Under() == text_box_edge.Over()) {
     return CSSIdentifierValue::Create(text_box_edge.Over());
   }
-  if (text_box_edge.Under() == ::blink::TextBoxEdge::TextBoxEdgeType::kText) {
-    using enum ::blink::TextBoxEdge::TextBoxEdgeType;
+  if (text_box_edge.Under() == ::blink::TextBoxEdge::Type::kText) {
+    using enum ::blink::TextBoxEdge::Type;
     switch (text_box_edge.Over()) {
       case kCap:
       case kEx:
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
index 89818c6..6b84e37 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -2513,15 +2513,14 @@
     StyleResolverState& status,
     const CSSValue& value) {
   if (auto* identifier_value = DynamicTo<CSSIdentifierValue>(value)) {
-    return TextBoxEdge(
-        identifier_value->ConvertTo<TextBoxEdge::TextBoxEdgeType>());
+    return TextBoxEdge(identifier_value->ConvertTo<TextBoxEdge::Type>());
   }
   const auto* const list = DynamicTo<CSSValueList>(&value);
   DCHECK_EQ(list->length(), 2u);
   const CSSIdentifierValue& over = To<CSSIdentifierValue>(list->Item(0));
   const CSSIdentifierValue& under = To<CSSIdentifierValue>(list->Item(1));
-  return TextBoxEdge(over.ConvertTo<TextBoxEdge::TextBoxEdgeType>(),
-                     under.ConvertTo<TextBoxEdge::TextBoxEdgeType>());
+  return TextBoxEdge(over.ConvertTo<TextBoxEdge::Type>(),
+                     under.ConvertTo<TextBoxEdge::Type>());
 }
 
 TextDecorationThickness StyleBuilderConverter::ConvertTextDecorationThickness(
diff --git a/third_party/blink/renderer/core/style/text_box_edge.h b/third_party/blink/renderer/core/style/text_box_edge.h
index 7c9cf0c2..5fb6aec 100644
--- a/third_party/blink/renderer/core/style/text_box_edge.h
+++ b/third_party/blink/renderer/core/style/text_box_edge.h
@@ -10,12 +10,16 @@
 
 namespace blink {
 
+//
+// Represents the CSS `text-box-edge` property.
+// https://drafts.csswg.org/css-inline-3/#propdef-text-box-edge
+//
 class CORE_EXPORT TextBoxEdge {
   DISALLOW_NEW();
 
  public:
   // https://drafts.csswg.org/css-inline-3/#text-edges.
-  enum class TextBoxEdgeType : uint8_t {
+  enum class Type : uint8_t {
     kLeading,
     kText,
     kCap,
@@ -26,36 +30,35 @@
     // kIdeographicInk, not implemented.
   };
 
-  explicit TextBoxEdge(TextBoxEdgeType over)
-      : TextBoxEdge(over, ComputedMissingUnderEdge(over)) {}
-
-  TextBoxEdge(TextBoxEdgeType over, TextBoxEdgeType under)
-      : over_(over), under_(under) {}
+  TextBoxEdge() : TextBoxEdge(Type::kLeading, Type::kLeading) {}
+  explicit TextBoxEdge(Type over)
+      : TextBoxEdge(over, ComputeMissingUnderEdge(over)) {}
+  TextBoxEdge(Type over, Type under) : over_(over), under_(under) {}
 
   bool operator==(const TextBoxEdge& other) const {
     return over_ == other.Over() && under_ == other.Under();
   }
   bool operator!=(const TextBoxEdge& other) const { return !(*this == other); }
 
-  const TextBoxEdgeType& Over() const { return over_; }
-  const TextBoxEdgeType& Under() const { return under_; }
+  const Type& Over() const { return over_; }
+  const Type& Under() const { return under_; }
 
  private:
-  static TextBoxEdgeType ComputedMissingUnderEdge(TextBoxEdgeType over) {
+  static constexpr Type ComputeMissingUnderEdge(Type over) {
     switch (over) {
-      case TextBoxEdgeType::kText:
-      case TextBoxEdgeType::kLeading:
+      case Type::kText:
+      case Type::kLeading:
         return over;
-      case TextBoxEdgeType::kCap:
-      case TextBoxEdgeType::kEx:
-        return TextBoxEdgeType::kText;
-      case TextBoxEdgeType::kAlphabetic:
+      case Type::kCap:
+      case Type::kEx:
+        return Type::kText;
+      case Type::kAlphabetic:
         NOTREACHED_NORETURN();
     }
   }
 
-  TextBoxEdgeType over_;
-  TextBoxEdgeType under_;
+  Type over_;
+  Type under_;
 };
 
 }  // namespace blink
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 b4fa2d2..8edd19f 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
@@ -23043,6 +23043,19 @@
        ],
        {}
       ]
+     ],
+     "reftest_wait_0-print.html": [
+      "fec62a3cae00655a95f7bc569d2eb1f43eac6062",
+      [
+       null,
+       [
+        [
+         "/infrastructure/reftest/green.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
      ]
     }
    },
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_wait_0-print.html b/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_wait_0-print.html
new file mode 100644
index 0000000..fec62a3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_wait_0-print.html
@@ -0,0 +1,13 @@
+<html class="reftest-wait">
+<title>Test with reftest-wait</title>
+<link rel=match href=green.html>
+<style>
+:root {background-color:red}
+</style>
+<script>
+setTimeout(function() {
+  document.documentElement.style.backgroundColor = "green";
+  document.documentElement.className = "";
+}, 2000);
+</script>
+</html>
diff --git a/third_party/chromium-variations b/third_party/chromium-variations
index 2647e3f..3097b90 160000
--- a/third_party/chromium-variations
+++ b/third_party/chromium-variations
@@ -1 +1 @@
-Subproject commit 2647e3fafdacf32cd37e23e40a42ffa5618cb2f6
+Subproject commit 3097b9057e203656efcd2f6f04eb24198d0c5ec7
diff --git a/third_party/webrtc b/third_party/webrtc
index b0fe794..76c02af 160000
--- a/third_party/webrtc
+++ b/third_party/webrtc
@@ -1 +1 @@
-Subproject commit b0fe794d7d9867c67625b573b1f9afd24bb38a19
+Subproject commit 76c02aff4c76cc2d47c0a975333789978986e2b9
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml
index a2bc90e..a625a26 100644
--- a/tools/metrics/histograms/metadata/network/histograms.xml
+++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -3204,6 +3204,81 @@
   <token key="VPNType" variants="VPNType"/>
 </histogram>
 
+<histogram
+    name="Network.Shill.Vpn.{VPNType}.TimeConnectedToDisconnectedSeconds"
+    units="seconds" expires_after="2025-02-20">
+  <owner>jiejiang@chromium.org</owner>
+  <owner>cros-connectivity@google.com</owner>
+  <owner>cros-network-metrics@google.com</owner>
+  <summary>
+    ChromeOS network usage metric emitted on each time when the state of a
+    {VPNType} VPN transits from connected to a non-connected state (reconnecting
+    or idle), which tracks how long the VPN driver stays in the connected state
+    of this connection.
+  </summary>
+  <token key="VPNType" variants="VPNType"/>
+</histogram>
+
+<histogram name="Network.Shill.Vpn.{VPNType}.TimeConnectToConnectedMillis"
+    units="ms" expires_after="2025-02-20">
+  <owner>jiejiang@chromium.org</owner>
+  <owner>cros-connectivity@google.com</owner>
+  <owner>cros-network-metrics@google.com</owner>
+  <summary>
+    ChromeOS network usage metric emitted on each successful new {VPNType} VPN
+    connection that tracks time duration from the VPN driver starts connecting
+    to the VPN driver reports connected. The time used by shill and patchpanel
+    for datapath configuration is not counted in this metrics.
+  </summary>
+  <token key="VPNType" variants="VPNType"/>
+</histogram>
+
+<histogram name="Network.Shill.Vpn.{VPNType}.TimeConnectToIdleMillis"
+    units="ms" expires_after="2025-02-20">
+  <owner>jiejiang@chromium.org</owner>
+  <owner>cros-connectivity@google.com</owner>
+  <owner>cros-network-metrics@google.com</owner>
+  <summary>
+    ChromeOS network usage metric emitted on each time when the state of a
+    {VPNType} VPN transits from connecting to idle (without being connected
+    once), which tracks the time duration from the VPN driver starts connecting
+    to the VPN driver becomes idle. This can be expected (e.g., user cancel the
+    connection) or unexpected (e.g., cannot reach the VPN server).
+  </summary>
+  <token key="VPNType" variants="VPNType"/>
+</histogram>
+
+<histogram name="Network.Shill.Vpn.{VPNType}.TimeReconnectToConnectedMillis"
+    units="ms" expires_after="2025-02-20">
+  <owner>jiejiang@chromium.org</owner>
+  <owner>cros-connectivity@google.com</owner>
+  <owner>cros-network-metrics@google.com</owner>
+  <summary>
+    ChromeOS network usage metric emitted on each successful {VPNType} VPN
+    reconnection (i.e., was connected before the reconnection restarts) that
+    tracks time duration from the VPN driver starts reconnecting to the VPN
+    driver reports connected. The time used by shill and patchpanel for datapath
+    configuration is not counted in this metrics.
+  </summary>
+  <token key="VPNType" variants="VPNType"/>
+</histogram>
+
+<histogram name="Network.Shill.Vpn.{VPNType}.TimeReconnectToIdleMillis"
+    units="ms" expires_after="2025-02-20">
+  <owner>jiejiang@chromium.org</owner>
+  <owner>cros-connectivity@google.com</owner>
+  <owner>cros-network-metrics@google.com</owner>
+  <summary>
+    ChromeOS network usage metric emitted on each time when the state of a
+    {VPNType} VPN transits from reconnecting (i.e., was connected before) to
+    idle (without being connected once), which tracks the time duration from the
+    VPN driver starts reconnecting to the VPN driver becomes idle. This can be
+    expected (e.g., user disconnects the connection) or unexpected (e.g., VPN
+    server is no longer reachable).
+  </summary>
+  <token key="VPNType" variants="VPNType"/>
+</histogram>
+
 <histogram name="Network.Shill.WiFi.AdapterAllowlisted"
     enum="WiFiAdapterInAllowlist" expires_after="2024-12-31">
   <owner>norvez@chromium.org</owner>
diff --git a/tools/typescript/definitions/passwords_private.d.ts b/tools/typescript/definitions/passwords_private.d.ts
index a991e03..26a679a 100644
--- a/tools/typescript/definitions/passwords_private.d.ts
+++ b/tools/typescript/definitions/passwords_private.d.ts
@@ -147,6 +147,7 @@
         note?: string;
         changePasswordUrl?: string;
         compromisedInfo?: CompromisedInfo;
+        creationTime?: number;
       }
 
       export interface CredentialGroup {
diff --git a/ui/chromeos/translations/ui_chromeos_strings_th.xtb b/ui/chromeos/translations/ui_chromeos_strings_th.xtb
index c9066e6..471f684 100644
--- a/ui/chromeos/translations/ui_chromeos_strings_th.xtb
+++ b/ui/chromeos/translations/ui_chromeos_strings_th.xtb
@@ -428,7 +428,7 @@
 <translation id="4425149324548788773">ไดรฟ์ของฉัน</translation>
 <translation id="4432921877815220091">เครือข่ายที่ <ph name="NETWORK_INDEX" /> จาก <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, , เปิดใช้งานหลังจากตั้งค่าอุปกรณ์, จัดการโดยผู้ดูแลระบบ</translation>
 <translation id="4439427728133035643">เครือข่ายที่ <ph name="NETWORK_INDEX" /> จาก <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, ความแรงสัญญาณ <ph name="SIGNAL_STRENGTH" />%, เชื่อมต่อ</translation>
-<translation id="4442424173763614572">การค้นหา DNS ล้มเหลว</translation>
+<translation id="4442424173763614572">DNS Lookup ล้มเหลว</translation>
 <translation id="4445896958353114391">กำลังซิงค์ไฟล์</translation>
 <translation id="4462159676511157176">เซิร์ฟเวอร์ชื่อที่กำหนดเอง</translation>
 <translation id="4465725236958772856">เครือข่ายที่ <ph name="NETWORK_INDEX" /> จาก <ph name="NETWORK_COUNT" />, <ph name="NETWORK_NAME" />, จัดการโดยผู้ดูแลระบบ, เชื่อมต่อ</translation>