diff --git a/DEPS b/DEPS
index 3f7ab06..f21a7b0 100644
--- a/DEPS
+++ b/DEPS
@@ -306,7 +306,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': '01d0125dd7c53d19a5983726d14b842676311905',
+  'src_internal_revision': '267ce4f58248ec59895483e5ef12b065db32717c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
@@ -314,11 +314,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'deda839adfed890bdcfbbd0a73fd6b1daa94eb23',
+  'v8_revision': '28312d3b2ac96a3a325a4a761851c15808a75c12',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '11eb5eb7ace91dc15ba341dd864c34a841c9f94b',
+  'angle_revision': 'e62bd70a6c748559b384f8acb944b602b91869a2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -381,7 +381,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '432aa4ae6c6931b15f595218bffb6c63512ac179',
+  'catapult_revision': 'c2c3cef34d1a1cee17fffcf34c98a6a9a352d064',
   # 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.
@@ -401,7 +401,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '294f601c1dc3f2eeafe0c65278cc65668eb2c865',
+  'devtools_frontend_revision': '3a113586c2d333056dc944e92db447ddaa492762',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -825,12 +825,12 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    'f1d153819784da755404355b06bf9d91d1789b71',
+    '27098a272f4239731ab13adb3dd53bc91652c28f',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + 'e85b75e5b3355dc1c848bf89a884b33b44693375',
+    'url': Var('chromium_git') + '/website.git' + '@' + 'ab6fa722cd68f58581086289b93bac51775b453e',
   },
 
   'src/ios/third_party/earl_grey2/src': {
@@ -1203,7 +1203,7 @@
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'abdf93162b756e81b7d5d51ffa58bdf210cb4dde',
+      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '30cbeb81ec54e2be41b6de16ad50353ea798740d',
     'condition': 'checkout_src_internal',
   },
 
@@ -1663,7 +1663,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '3deb2358149574207c12407c7a6b2a885a5cef3b',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '786ec3a414ad41aa627a88b83c7fd9bae5d59136',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '8ef97ff3b7332e38e61b347a2fbed425a4617151',
@@ -1982,7 +1982,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'EFr1HkeAoGY-zysVORomkc3fc5W6yGijNg5Wb2xFSNoC',
+        'version': '5rzylxZXRMqHkO3-8w0_UUrGSVLjP5XjSYfhpeM-mrkC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3973,7 +3973,7 @@
 
   'src/components/optimization_guide/internal': {
       'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' +
-        'a1431631ca51a2ed211beb9b2438e260fed5143d',
+        '30306f842234b68abc5fe490db53226b5cf9789c',
       'condition': 'checkout_src_internal',
   },
 
@@ -4033,7 +4033,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        'e0f7bfa6413ecdadaf5626cfe53f3ef58d23c102',
+        'a2e9e8cfd9bd77d59fc632ddb10190e30514189d',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index a063051..9b6c3be 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -333,6 +333,8 @@
     "birch/birch_item.h",
     "birch/birch_model.cc",
     "birch/birch_model.h",
+    "birch/birch_weather_provider.cc",
+    "birch/birch_weather_provider.h",
     "bluetooth_devices_observer.cc",
     "bluetooth_devices_observer.h",
     "booting/booting_animation_controller.cc",
@@ -3314,6 +3316,7 @@
     "assistant/util/deep_link_util_unittest.cc",
     "assistant/util/resource_util_unittest.cc",
     "birch/birch_model_unittest.cc",
+    "birch/birch_weather_provider_unittest.cc",
     "bubble/bubble_event_filter_unittest.cc",
     "bubble/bubble_utils_unittest.cc",
     "capture_mode/capture_audio_mixing_unittests.cc",
diff --git a/ash/ambient/backdrop/ambient_backend_controller_impl.cc b/ash/ambient/backdrop/ambient_backend_controller_impl.cc
index 3268872..06be7bcb 100644
--- a/ash/ambient/backdrop/ambient_backend_controller_impl.cc
+++ b/ash/ambient/backdrop/ambient_backend_controller_impl.cc
@@ -219,6 +219,8 @@
   WeatherInfo weather_info;
   const auto& list_result = result.GetList();
 
+  weather_info.condition_description = GetStringValue(
+      list_result, backdrop::WeatherInfo::kConditionDescriptionFieldNumber);
   weather_info.condition_icon_url = GetStringValue(
       list_result, backdrop::WeatherInfo::kConditionIconUrlFieldNumber);
   weather_info.temp_f =
diff --git a/ash/api/tasks/fake_tasks_client.cc b/ash/api/tasks/fake_tasks_client.cc
index 4a798fa..d7b51a6 100644
--- a/ash/api/tasks/fake_tasks_client.cc
+++ b/ash/api/tasks/fake_tasks_client.cc
@@ -97,13 +97,15 @@
 void FakeTasksClient::UpdateTask(const std::string& task_list_id,
                                  const std::string& task_id,
                                  const std::string& title,
+                                 bool completed,
                                  TasksClient::OnTaskSavedCallback callback) {
   if (paused_) {
-    pending_update_task_callbacks_.push_back(
-        base::BindOnce(&FakeTasksClient::UpdateTaskImpl, base::Unretained(this),
-                       task_list_id, task_id, title, std::move(callback)));
+    pending_update_task_callbacks_.push_back(base::BindOnce(
+        &FakeTasksClient::UpdateTaskImpl, base::Unretained(this), task_list_id,
+        task_id, title, completed, std::move(callback)));
   } else {
-    UpdateTaskImpl(task_list_id, task_id, title, std::move(callback));
+    UpdateTaskImpl(task_list_id, task_id, title, completed,
+                   std::move(callback));
   }
 }
 
@@ -154,8 +156,7 @@
 
   auto pending_task = std::make_unique<Task>(
       base::Uuid::GenerateRandomV4().AsLowercaseString(), title,
-      /*completed=*/false,
-      /*due=*/absl::nullopt,
+      /*due=*/absl::nullopt, /*completed=*/false,
       /*has_subtasks=*/false, /*has_email_link=*/false,
       /*has_notes=*/false,
       /*updated=*/base::Time::Now());
@@ -169,6 +170,7 @@
     const std::string& task_list_id,
     const std::string& task_id,
     const std::string& title,
+    bool completed,
     TasksClient::OnTaskSavedCallback callback) {
   if (run_with_errors_) {
     std::move(callback).Run(/*task=*/nullptr);
@@ -183,8 +185,10 @@
       [&task_id](const auto& task) { return task->id == task_id; });
   CHECK(task_iter != task_list_iter->second->end());
 
-  task_iter->get()->title = title;
-  std::move(callback).Run(task_iter->get());
+  Task* task = task_iter->get();
+  task->title = title;
+  task->completed = completed;
+  std::move(callback).Run(task);
 }
 
 void FakeTasksClient::PopulateTasks(base::Time tasks_due_time) {
@@ -212,30 +216,30 @@
   std::unique_ptr<ui::ListModel<Task>> task_list_1 =
       std::make_unique<ui::ListModel<Task>>();
   task_list_1->Add(std::make_unique<Task>(
-      "TaskListItem1", "Task List 1 Item 1 Title", /*completed=*/false,
-      /*due=*/tasks_due_time,
+      "TaskListItem1", "Task List 1 Item 1 Title",
+      /*due=*/tasks_due_time, /*completed=*/false,
       /*has_subtasks=*/false, /*has_email_link=*/false, /*has_notes=*/false,
       /*updated=*/tasks_due_time));
   task_list_1->Add(std::make_unique<Task>(
-      "TaskListItem2", "Task List 1 Item 2 Title", /*completed=*/false,
-      /*due=*/tasks_due_time,
+      "TaskListItem2", "Task List 1 Item 2 Title",
+      /*due=*/tasks_due_time, /*completed=*/false,
       /*has_subtasks=*/false, /*has_email_link=*/false, /*has_notes=*/false,
       /*updated=*/tasks_due_time));
   std::unique_ptr<ui::ListModel<Task>> task_list_2 =
       std::make_unique<ui::ListModel<Task>>();
   task_list_2->Add(std::make_unique<Task>(
-      "TaskListItem3", "Task List 2 Item 1 Title", /*completed=*/false,
-      /*due=*/tasks_due_time,
+      "TaskListItem3", "Task List 2 Item 1 Title",
+      /*due=*/tasks_due_time, /*completed=*/false,
       /*has_subtasks=*/false, /*has_email_link=*/false, /*has_notes=*/false,
       /*updated=*/tasks_due_time));
   task_list_2->Add(std::make_unique<Task>(
-      "TaskListItem4", "Task List 2 Item 2 Title", /*completed=*/false,
-      /*due=*/tasks_due_time,
+      "TaskListItem4", "Task List 2 Item 2 Title",
+      /*due=*/tasks_due_time, /*completed=*/false,
       /*has_subtasks=*/false, /*has_email_link=*/false, /*has_notes=*/false,
       /*updated=*/tasks_due_time));
   task_list_2->Add(std::make_unique<Task>(
-      "TaskListItem5", "Task List 2 Item 3 Title", /*completed=*/false,
-      /*due=*/tasks_due_time,
+      "TaskListItem5", "Task List 2 Item 3 Title",
+      /*due=*/tasks_due_time, /*completed=*/false,
       /*has_subtasks=*/false, /*has_email_link=*/false, /*has_notes=*/false,
       /*updated=*/tasks_due_time));
   tasks_in_task_lists_.emplace("TaskListID1", std::move(task_list_1));
diff --git a/ash/api/tasks/fake_tasks_client.h b/ash/api/tasks/fake_tasks_client.h
index 5943f57..0064bc2 100644
--- a/ash/api/tasks/fake_tasks_client.h
+++ b/ash/api/tasks/fake_tasks_client.h
@@ -46,6 +46,7 @@
   void UpdateTask(const std::string& task_list_id,
                   const std::string& task_id,
                   const std::string& title,
+                  bool completed,
                   TasksClient::OnTaskSavedCallback callback) override;
   void OnGlanceablesBubbleClosed(OnAllPendingCompletedTasksSavedCallback
                                      callback = base::DoNothing()) override;
@@ -79,6 +80,7 @@
   void UpdateTaskImpl(const std::string& task_list_id,
                       const std::string& task_id,
                       const std::string& title,
+                      bool completed,
                       TasksClient::OnTaskSavedCallback callback);
 
   void PopulateTasks(base::Time tasks_due_time);
diff --git a/ash/api/tasks/tasks_client.h b/ash/api/tasks/tasks_client.h
index 9489deb..ed1e216 100644
--- a/ash/api/tasks/tasks_client.h
+++ b/ash/api/tasks/tasks_client.h
@@ -58,6 +58,7 @@
   virtual void UpdateTask(const std::string& task_list_id,
                           const std::string& task_id,
                           const std::string& title,
+                          bool completed,
                           OnTaskSavedCallback callback) = 0;
 
   // Method called when the glanceables bubble UI closes. The client can use
diff --git a/ash/api/tasks/tasks_delegate.h b/ash/api/tasks/tasks_delegate.h
index 1f88c194..36378c0e2 100644
--- a/ash/api/tasks/tasks_delegate.h
+++ b/ash/api/tasks/tasks_delegate.h
@@ -28,30 +28,16 @@
   virtual void GetTasks(const std::string& task_list_id,
                         TasksClient::GetTasksCallback callback) = 0;
 
-  // Marks the completion state of the task with the given `task_list_id` and
-  // `task_id` as `completed`. Does not immediately send the cached completion
-  // data to the Google Tasks API. `completed` indicates whether the caller
-  // wants to send to the server that the given task is completed. If
-  // `completed` is false, the API will not tell the server that the given task
-  // was completed when updates are sent to the server. Likewise, if the server
-  // already has the tasks marked as complete, this will not mark the task as
-  // incomplete. See `SendCompletedTasks`.
-  virtual void MarkAsCompleted(const std::string& task_list_id,
-                               const std::string& task_id,
-                               bool completed) = 0;
-
-  // Sends cached tasks completion data to the Google Tasks API.
-  virtual void SendCompletedTasks() = 0;
-
   // Adds a task with the given `title` to the task list with id `task_list_id`.
   virtual void AddTask(const std::string& task_list_id,
                        const std::string& title) = 0;
 
-  // Updates the title of the task in the task list with id `task_list_id`
-  // with id `task_id`.
-  virtual void UpdateTaskTitle(const std::string& task_list_id,
-                               const std::string& task_id,
-                               const std::string& title) = 0;
+  // Updates the task in the task list with id `task_list_id` and with id
+  // `task_id`.
+  virtual void UpdateTask(const std::string& task_list_id,
+                          const std::string& task_id,
+                          const std::string& title,
+                          bool completed) = 0;
 };
 
 }  // namespace ash::api
diff --git a/ash/api/tasks/tasks_types.cc b/ash/api/tasks/tasks_types.cc
index 4451f4c1..6f87033 100644
--- a/ash/api/tasks/tasks_types.cc
+++ b/ash/api/tasks/tasks_types.cc
@@ -23,16 +23,16 @@
 
 Task::Task(const std::string& id,
            const std::string& title,
-           bool completed,
            const std::optional<base::Time>& due,
+           bool completed,
            bool has_subtasks,
            bool has_email_link,
            bool has_notes,
            const base::Time& updated)
     : id(id),
       title(title),
-      completed(completed),
       due(due),
+      completed(completed),
       has_subtasks(has_subtasks),
       has_email_link(has_email_link),
       has_notes(has_notes),
diff --git a/ash/api/tasks/tasks_types.h b/ash/api/tasks/tasks_types.h
index 66bf79a..a7d0522 100644
--- a/ash/api/tasks/tasks_types.h
+++ b/ash/api/tasks/tasks_types.h
@@ -42,8 +42,8 @@
 struct ASH_EXPORT Task {
   Task(const std::string& id,
        const std::string& title,
-       bool completed,
        const std::optional<base::Time>& due,
+       bool completed,
        bool has_subtasks,
        bool has_email_link,
        bool has_notes,
@@ -58,13 +58,13 @@
   // Title of the task.
   std::string title;
 
-  // Indicates whether the task is completed (has "status" field equals to
-  // "completed" on the API side).
-  const bool completed;
-
   // Optional due date of the task.
   const std::optional<base::Time> due;
 
+  // Indicates whether the task is completed (has "status" field equals to
+  // "completed" on the API side).
+  bool completed;
+
   // Indicates whether the task has subtasks in it.
   const bool has_subtasks;
 
diff --git a/ash/api/tasks/test_tasks_delegate.cc b/ash/api/tasks/test_tasks_delegate.cc
index a6c069d..1eba859 100644
--- a/ash/api/tasks/test_tasks_delegate.cc
+++ b/ash/api/tasks/test_tasks_delegate.cc
@@ -29,24 +29,15 @@
   NOTIMPLEMENTED();
 }
 
-void TestTasksDelegate::MarkAsCompleted(const std::string& task_list_id,
-                                        const std::string& task_id,
-                                        bool completed) {
-  NOTIMPLEMENTED();
-}
-
-void TestTasksDelegate::SendCompletedTasks() {
-  NOTIMPLEMENTED();
-}
-
 void TestTasksDelegate::AddTask(const std::string& task_list_id,
                                 const std::string& title) {
   NOTIMPLEMENTED();
 }
 
-void TestTasksDelegate::UpdateTaskTitle(const std::string& task_list_id,
-                                        const std::string& task_id,
-                                        const std::string& title) {
+void TestTasksDelegate::UpdateTask(const std::string& task_list_id,
+                                   const std::string& task_id,
+                                   const std::string& title,
+                                   bool completed) {
   NOTIMPLEMENTED();
 }
 
diff --git a/ash/api/tasks/test_tasks_delegate.h b/ash/api/tasks/test_tasks_delegate.h
index 36ec6aaf..b1f3fce 100644
--- a/ash/api/tasks/test_tasks_delegate.h
+++ b/ash/api/tasks/test_tasks_delegate.h
@@ -22,15 +22,12 @@
   void GetTaskLists(TasksClient::GetTaskListsCallback callback) override;
   void GetTasks(const std::string& task_list_id,
                 TasksClient::GetTasksCallback callback) override;
-  void MarkAsCompleted(const std::string& task_list_id,
-                       const std::string& task_id,
-                       bool completed) override;
-  void SendCompletedTasks() override;
   void AddTask(const std::string& task_list_id,
                const std::string& title) override;
-  void UpdateTaskTitle(const std::string& task_list_id,
-                       const std::string& task_id,
-                       const std::string& title) override;
+  void UpdateTask(const std::string& task_list_id,
+                  const std::string& task_id,
+                  const std::string& title,
+                  bool completed) override;
 };
 
 }  // namespace ash::api
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 117d0fc..8d19db9 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -2460,8 +2460,14 @@
       <message name="IDS_ASH_OVERVIEW_CLOSABLE_DESK_MINIVIEW_A11Y_EXTRA_TIP" desc="The accessibility text read by screen readers for a closeable desk mini view when the close all feature is enabled.">
           Press Ctrl + W to combine with <ph name="DESK_NAME">$1<ex>Desk 1</ex></ph>. Press Ctrl + Shift + W to close desk and windows.
       </message>
-       <message name="IDS_ASH_OVERVIEW_SETTINGS_BUTTON_LABEL" translateable="false" desc="The accessible name for the Overview Settings button during faster splitscreen setup.">
-        Multitasking settings
+       <message name="IDS_ASH_OVERVIEW_SETTINGS_BUTTON_LABEL" desc="The accessible name for the Overview Settings button during faster splitscreen setup.">
+        Windows and desks settings
+      </message>
+      <message name="IDS_ASH_OVERVIEW_FASTER_SPLITSCREEN_TOAST" desc="The text for the Faster Splitscreen toast during faster splitscreen setup.">
+        Choose a window for this side
+      </message>
+      <message name="IDS_ASH_OVERVIEW_FASTER_SPLITSCREEN_TOAST_SKIP" desc="The text for the Faster Splitscreen toast skip button.">
+        Dismiss
       </message>
       <message name="IDS_ASH_OVERVIEW_WINDOW_CLOSING_A11Y_ALERT" desc="The accessibility alert read by screen readers to alert the user that a window in overview mode is closing.">
         Window <ph name="WINDOW_TITILE">$1<ex>1</ex></ph> closed.
diff --git a/ash/ash_strings_grd/IDS_ASH_OVERVIEW_FASTER_SPLITSCREEN_TOAST.png.sha1 b/ash/ash_strings_grd/IDS_ASH_OVERVIEW_FASTER_SPLITSCREEN_TOAST.png.sha1
new file mode 100644
index 0000000..7ca5434e
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_OVERVIEW_FASTER_SPLITSCREEN_TOAST.png.sha1
@@ -0,0 +1 @@
+ce88f581202f4cf5a8a4e8d84558fe072fc8b9b7
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_OVERVIEW_FASTER_SPLITSCREEN_TOAST_SKIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_OVERVIEW_FASTER_SPLITSCREEN_TOAST_SKIP.png.sha1
new file mode 100644
index 0000000..ba8b93a
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_OVERVIEW_FASTER_SPLITSCREEN_TOAST_SKIP.png.sha1
@@ -0,0 +1 @@
+3a66c9bf30160c6f3d1c69a5c7f2d5cd4d6a34df
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_OVERVIEW_SETTINGS_BUTTON_LABEL.png.sha1 b/ash/ash_strings_grd/IDS_ASH_OVERVIEW_SETTINGS_BUTTON_LABEL.png.sha1
new file mode 100644
index 0000000..64a88b33
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_OVERVIEW_SETTINGS_BUTTON_LABEL.png.sha1
@@ -0,0 +1 @@
+96dc0a987229a1cc73b06b126d64275a913a4434
\ No newline at end of file
diff --git a/ash/birch/birch_item.cc b/ash/birch/birch_item.cc
index d45c5cf..91b668b 100644
--- a/ash/birch/birch_item.cc
+++ b/ash/birch/birch_item.cc
@@ -12,13 +12,15 @@
 
 namespace ash {
 
-BirchItem::BirchItem(const std::string& title) : title(title) {}
+BirchItem::BirchItem(const std::u16string& title, ui::ImageModel icon)
+    : title(title), icon(std::move(icon)) {}
 
 BirchItem::~BirchItem() = default;
 
 BirchFileItem::BirchFileItem(const base::FilePath& file_path,
                              const std::optional<base::Time>& timestamp)
-    : BirchItem(file_path.BaseName().value()),
+    : BirchItem(base::UTF8ToUTF16(file_path.BaseName().value()),
+                ui::ImageModel()),
       file_path(file_path),
       timestamp(timestamp) {}
 
@@ -26,21 +28,38 @@
 
 std::string BirchFileItem::ToString() const {
   std::stringstream ss;
-  ss << "title: " << title << ", file_path:" << file_path;
+  ss << "File item : {title: " << base::UTF16ToUTF8(title)
+     << ", file_path:" << file_path;
   if (timestamp.has_value()) {
     ss << ", timestamp: "
        << base::UTF16ToUTF8(
               base::TimeFormatShortDateAndTime(timestamp.value()));
   }
+  ss << "}";
   return ss.str();
 }
 
-BirchTabItem::BirchTabItem(const std::string& title,
+BirchWeatherItem::BirchWeatherItem(const std::u16string& weather_description,
+                                   const std::u16string& temperature,
+                                   ui::ImageModel icon)
+    : BirchItem(weather_description, std::move(icon)),
+      temperature(temperature) {}
+
+BirchWeatherItem::~BirchWeatherItem() = default;
+
+std::string BirchWeatherItem::ToString() const {
+  std::stringstream ss;
+  ss << "Weather item: {title: " << base::UTF16ToUTF8(title)
+     << ", temperature:" << base::UTF16ToUTF8(temperature) << "}";
+  return ss.str();
+}
+
+BirchTabItem::BirchTabItem(const std::u16string& title,
                            const GURL& url,
                            const base::Time& timestamp,
                            const GURL& favicon_url,
                            const std::string& session_name)
-    : BirchItem(title),
+    : BirchItem(title, ui::ImageModel()),
       url(url),
       timestamp(timestamp),
       favicon_url(favicon_url),
@@ -52,8 +71,9 @@
 
 std::string BirchTabItem::ToString() const {
   std::stringstream ss;
-  ss << "title: " << title << ", url:" << url << ", timestamp:" << timestamp
-     << ", favicon_url:" << favicon_url << ", session_name:" << session_name;
+  ss << "title: " << base::UTF16ToUTF8(title) << ", url:" << url
+     << ", timestamp:" << timestamp << ", favicon_url:" << favicon_url
+     << ", session_name:" << session_name;
   return ss.str();
 }
 
diff --git a/ash/birch/birch_item.h b/ash/birch/birch_item.h
index fb87c24..23d54d06 100644
--- a/ash/birch/birch_item.h
+++ b/ash/birch/birch_item.h
@@ -11,20 +11,22 @@
 #include "ash/ash_export.h"
 #include "base/files/file_path.h"
 #include "base/time/time.h"
+#include "ui/base/models/image_model.h"
 #include "url/gurl.h"
 
 namespace ash {
 
 // The base item which is stored by the birch model.
 struct ASH_EXPORT BirchItem {
-  explicit BirchItem(const std::string& title);
+  BirchItem(const std::u16string& title, const ui::ImageModel icon);
   BirchItem(BirchItem&&) = default;
   BirchItem(const BirchItem&);
   BirchItem& operator=(const BirchItem&);
   ~BirchItem();
   bool operator==(const BirchItem& rhs) const = default;
 
-  const std::string title;
+  const std::u16string title;
+  const ui::ImageModel icon;
 };
 
 // A birch item which contains file path and time information.
@@ -32,8 +34,8 @@
   BirchFileItem(const base::FilePath& file_path,
                 const std::optional<base::Time>& timestamp);
   BirchFileItem(BirchFileItem&&) = default;
-  BirchFileItem(const BirchFileItem&);
-  BirchFileItem& operator=(const BirchFileItem&);
+  BirchFileItem(const BirchFileItem&) = delete;
+  BirchFileItem& operator=(const BirchFileItem&) = delete;
   bool operator==(const BirchFileItem& rhs) const = default;
   ~BirchFileItem();
 
@@ -46,7 +48,7 @@
 
 // A birch item which contains tab and session information.
 struct ASH_EXPORT BirchTabItem : public BirchItem {
-  BirchTabItem(const std::string& title,
+  BirchTabItem(const std::u16string& title,
                const GURL& url,
                const base::Time& timestamp,
                const GURL& favicon_url,
@@ -66,6 +68,22 @@
   std::string ToString() const;
 };
 
+struct ASH_EXPORT BirchWeatherItem : public BirchItem {
+  BirchWeatherItem(const std::u16string& weather_description,
+                   const std::u16string& temperature,
+                   ui::ImageModel icon);
+  BirchWeatherItem(BirchWeatherItem&&) = default;
+  BirchWeatherItem(const BirchWeatherItem&) = delete;
+  BirchWeatherItem& operator=(const BirchWeatherItem&) = delete;
+  bool operator==(const BirchWeatherItem& rhs) const = default;
+  ~BirchWeatherItem();
+
+  const std::u16string temperature;
+
+  // Intended for debugging.
+  std::string ToString() const;
+};
+
 }  // namespace ash
 
 #endif  // ASH_BIRCH_BIRCH_ITEM_H_
diff --git a/ash/birch/birch_model.cc b/ash/birch/birch_model.cc
index b388f63..9f9ed535 100644
--- a/ash/birch/birch_model.cc
+++ b/ash/birch/birch_model.cc
@@ -4,9 +4,16 @@
 
 #include "ash/birch/birch_model.h"
 
+#include "ash/birch/birch_weather_provider.h"
+#include "ash/constants/ash_features.h"
+
 namespace ash {
 
-BirchModel::BirchModel() = default;
+BirchModel::BirchModel() {
+  if (features::IsBirchWeatherEnabled()) {
+    weather_provider_ = std::make_unique<BirchWeatherProvider>(this);
+  }
+}
 
 BirchModel::~BirchModel() = default;
 
@@ -39,6 +46,13 @@
   }
 
   recent_tab_items_ = std::move(recent_tab_items);
+}
+
+void BirchModel::SetWeatherItems(std::vector<BirchWeatherItem> weather_items) {
+  if (weather_items == weather_items_) {
+    return;
+  }
+  weather_items_ = std::move(weather_items);
 
   for (auto& observer : observers_) {
     observer.OnItemsChanged();
@@ -50,6 +64,9 @@
   if (birch_client_) {
     birch_client_->RequestBirchDataFetch();
   }
+  if (weather_provider_) {
+    weather_provider_->RequestDataFetch();
+  }
 }
 
 }  // namespace ash
diff --git a/ash/birch/birch_model.h b/ash/birch/birch_model.h
index 9589e36..de6c9fd 100644
--- a/ash/birch/birch_model.h
+++ b/ash/birch/birch_model.h
@@ -5,6 +5,9 @@
 #ifndef ASH_BIRCH_BIRCH_MODEL_H_
 #define ASH_BIRCH_BIRCH_MODEL_H_
 
+#include <optional>
+#include <vector>
+
 #include "ash/ash_export.h"
 #include "ash/birch/birch_client.h"
 #include "ash/birch/birch_item.h"
@@ -12,6 +15,8 @@
 
 namespace ash {
 
+class BirchWeatherProvider;
+
 // Birch model, which is used to aggregate and store relevant information from
 // different providers.
 class ASH_EXPORT BirchModel {
@@ -39,8 +44,8 @@
   void RequestBirchDataFetch();
 
   void SetFileSuggestItems(std::vector<BirchFileItem> file_suggest_items);
-
   void SetRecentTabItems(std::vector<BirchTabItem> recent_tab_items);
+  void SetWeatherItems(std::vector<BirchWeatherItem> weather_items);
 
   void SetClient(BirchClient* client) { birch_client_ = client; }
 
@@ -51,6 +56,10 @@
     return recent_tab_items_;
   }
 
+  const std::vector<BirchWeatherItem>& GetWeatherForTest() const {
+    return weather_items_;
+  }
+
  private:
   // A type-specific list of items for all file suggestion items.
   std::vector<BirchFileItem> file_suggest_items_;
@@ -58,8 +67,13 @@
   // A type-specific list of items for all tab items.
   std::vector<BirchTabItem> recent_tab_items_;
 
+  // A type-specific list of weather items.
+  std::vector<BirchWeatherItem> weather_items_;
+
   raw_ptr<BirchClient> birch_client_ = nullptr;
 
+  std::unique_ptr<BirchWeatherProvider> weather_provider_;
+
   base::ObserverList<Observer> observers_;
 };
 
diff --git a/ash/birch/birch_weather_provider.cc b/ash/birch/birch_weather_provider.cc
new file mode 100644
index 0000000..db89a19
--- /dev/null
+++ b/ash/birch/birch_weather_provider.cc
@@ -0,0 +1,124 @@
+// 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.
+
+#include "ash/birch/birch_weather_provider.h"
+
+#include <string>
+
+#include "ash/ambient/ambient_controller.h"
+#include "ash/birch/birch_item.h"
+#include "ash/birch/birch_model.h"
+#include "ash/public/cpp/ambient/ambient_backend_controller.h"
+#include "ash/public/cpp/image_downloader.h"
+#include "ash/public/cpp/session/session_types.h"
+#include "ash/session/session_controller_impl.h"
+#include "ash/shell.h"
+#include "ash/strings/grit/ash_strings.h"
+#include "base/check.h"
+#include "base/functional/bind.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
+
+namespace ash {
+
+namespace {
+
+constexpr net::NetworkTrafficAnnotationTag kWeatherIconTag =
+    net::DefineNetworkTrafficAnnotation("weather_icon", R"(
+        semantics {
+          sender: "Birch feature"
+          description:
+            "Download weather icon image from Google."
+          trigger:
+            "The user opens an UI surface associated with birch feature."
+          data: "None."
+          destination: GOOGLE_OWNED_SERVICE
+        }
+        policy {
+         cookies_allowed: NO
+         setting:
+           "This feature is off by default."
+         policy_exception_justification:
+           "Policy is planned, but not yet implemented."
+        })");
+
+void DownloadImageFromUrl(const std::string& url_string,
+                          ImageDownloader::DownloadCallback callback) {
+  GURL url(url_string);
+  if (!url.is_valid()) {
+    std::move(callback).Run(gfx::ImageSkia());
+    return;
+  }
+
+  const UserSession* active_user_session =
+      Shell::Get()->session_controller()->GetUserSession(0);
+  DCHECK(active_user_session);
+
+  ImageDownloader::Get()->Download(url, kWeatherIconTag,
+                                   active_user_session->user_info.account_id,
+                                   std::move(callback));
+}
+
+}  // namespace
+
+BirchWeatherProvider::BirchWeatherProvider(BirchModel* birch_model)
+    : birch_model_(birch_model) {}
+
+BirchWeatherProvider::~BirchWeatherProvider() = default;
+
+void BirchWeatherProvider::RequestDataFetch() {
+  Shell::Get()
+      ->ambient_controller()
+      ->ambient_backend_controller()
+      ->FetchWeather(base::BindOnce(&BirchWeatherProvider::OnWeatherInfoFetched,
+                                    weak_factory_.GetWeakPtr()));
+}
+
+void BirchWeatherProvider::OnWeatherInfoFetched(
+    const std::optional<WeatherInfo>& weather_info) {
+  if (!weather_info || !weather_info->temp_f.has_value() ||
+      !weather_info->condition_icon_url ||
+      !weather_info->condition_description ||
+      weather_info->condition_icon_url->empty()) {
+    birch_model_->SetWeatherItems({});
+    return;
+  }
+
+  // Ideally we should avoid downloading from the same url again to reduce the
+  // overhead, as it's unlikely that the weather condition is changing
+  // frequently during the day.
+  DownloadImageFromUrl(
+      *weather_info->condition_icon_url,
+      base::BindOnce(&BirchWeatherProvider::OnWeatherConditionIconDownloaded,
+                     weak_factory_.GetWeakPtr(),
+                     base::UTF8ToUTF16(*weather_info->condition_description),
+                     *weather_info->temp_f, weather_info->show_celsius));
+}
+
+void BirchWeatherProvider::OnWeatherConditionIconDownloaded(
+    const std::u16string& weather_description,
+    float temp_f,
+    bool show_celsius,
+    const gfx::ImageSkia& icon) {
+  if (icon.isNull()) {
+    birch_model_->SetWeatherItems({});
+    return;
+  }
+
+  std::u16string temperature_string =
+      show_celsius ? l10n_util::GetStringFUTF16Int(
+                         IDS_ASH_AMBIENT_MODE_WEATHER_TEMPERATURE_IN_CELSIUS,
+                         static_cast<int>((temp_f - 32) * 5 / 9))
+                   : l10n_util::GetStringFUTF16Int(
+                         IDS_ASH_AMBIENT_MODE_WEATHER_TEMPERATURE_IN_FAHRENHEIT,
+                         static_cast<int>(temp_f));
+
+  std::vector<BirchWeatherItem> items;
+  items.emplace_back(weather_description, temperature_string,
+                     ui::ImageModel::FromImageSkia(icon));
+  birch_model_->SetWeatherItems(std::move(items));
+}
+
+}  // namespace ash
diff --git a/ash/birch/birch_weather_provider.h b/ash/birch/birch_weather_provider.h
new file mode 100644
index 0000000..712e0e2
--- /dev/null
+++ b/ash/birch/birch_weather_provider.h
@@ -0,0 +1,54 @@
+// 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.
+
+#ifndef ASH_BIRCH_BIRCH_WEATHER_PROVIDER_H_
+#define ASH_BIRCH_BIRCH_WEATHER_PROVIDER_H_
+
+#include <optional>
+
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+
+namespace gfx {
+class ImageSkia;
+}
+
+namespace ash {
+
+class BirchModel;
+
+struct WeatherInfo;
+
+class BirchWeatherProvider {
+ public:
+  explicit BirchWeatherProvider(BirchModel* birch_model);
+  BirchWeatherProvider(const BirchWeatherProvider&) = delete;
+  BirchWeatherProvider& operator=(const BirchWeatherProvider&) = delete;
+  ~BirchWeatherProvider();
+
+  // Called from birch model to request weather information to be displayed in
+  // UI.
+  void RequestDataFetch();
+
+ private:
+  // Called in response to a weather info request. It initiates icon fetch from
+  // the URL provided in the weather info.
+  void OnWeatherInfoFetched(const std::optional<WeatherInfo>& weather_info);
+
+  // Callback to weather info icon request. It will update birch model with the
+  // fetched weather info (including the downloaded weather icon).
+  void OnWeatherConditionIconDownloaded(
+      const std::u16string& weather_description,
+      float temp_f,
+      bool show_celsius,
+      const gfx::ImageSkia& icon);
+
+  const raw_ptr<BirchModel> birch_model_;
+
+  base::WeakPtrFactory<BirchWeatherProvider> weak_factory_{this};
+};
+
+}  // namespace ash
+
+#endif  // ASH_BIRCH_BIRCH_WEATHER_PROVIDER_H_
diff --git a/ash/birch/birch_weather_provider_unittest.cc b/ash/birch/birch_weather_provider_unittest.cc
new file mode 100644
index 0000000..d780a98e
--- /dev/null
+++ b/ash/birch/birch_weather_provider_unittest.cc
@@ -0,0 +1,278 @@
+// 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.
+
+#include "ash/birch/birch_weather_provider.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "ash/ambient/ambient_controller.h"
+#include "ash/birch/birch_model.h"
+#include "ash/constants/ash_features.h"
+#include "ash/constants/ash_switches.h"
+#include "ash/public/cpp/ambient/ambient_backend_controller.h"
+#include "ash/public/cpp/ambient/fake_ambient_backend_controller_impl.h"
+#include "ash/public/cpp/test/test_image_downloader.h"
+#include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
+#include "base/memory/raw_ptr.h"
+#include "base/test/scoped_feature_list.h"
+
+namespace ash {
+
+class BirchWeatherProviderTest : public AshTestBase {
+ public:
+  BirchWeatherProviderTest() {
+    switches::SetIgnoreForestSecretKeyForTest(true);
+    feature_list_.InitWithFeatures(
+        {features::kForestFeature, features::kBirchWeather}, {});
+  }
+  ~BirchWeatherProviderTest() override {
+    switches::SetIgnoreForestSecretKeyForTest(false);
+  }
+
+  // AshTestBase:
+  void SetUp() override {
+    AshTestBase::SetUp();
+
+    image_downloader_ = std::make_unique<ash::TestImageDownloader>();
+
+    Shell::Get()->ambient_controller()->set_backend_controller_for_testing(
+        nullptr);
+    auto ambient_backend_controller =
+        std::make_unique<FakeAmbientBackendControllerImpl>();
+    ambient_backend_controller_ = ambient_backend_controller.get();
+    Shell::Get()->ambient_controller()->set_backend_controller_for_testing(
+        std::move(ambient_backend_controller));
+  }
+  void TearDown() override {
+    ambient_backend_controller_ = nullptr;
+    image_downloader_.reset();
+    AshTestBase::TearDown();
+  }
+
+  raw_ptr<FakeAmbientBackendControllerImpl> ambient_backend_controller_;
+  std::unique_ptr<TestImageDownloader> image_downloader_;
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_F(BirchWeatherProviderTest, GetWeather) {
+  auto* birch_model = Shell::Get()->birch_model();
+
+  WeatherInfo info;
+  info.condition_description = "Cloudy";
+  info.condition_icon_url = "https://fake-icon-url";
+  info.temp_f = 70.0f;
+  ambient_backend_controller_->SetWeatherInfo(info);
+
+  birch_model->RequestBirchDataFetch();
+
+  EXPECT_TRUE(birch_model->GetWeatherForTest().empty());
+
+  // The fake image downloader post a task to respond with an image.
+  base::RunLoop().RunUntilIdle();
+
+  auto& weather_items = birch_model->GetWeatherForTest();
+  ASSERT_EQ(1u, weather_items.size());
+  EXPECT_EQ(u"Cloudy", weather_items[0].title);
+  EXPECT_EQ(u"70\xB0 F", weather_items[0].temperature);
+  EXPECT_FALSE(weather_items[0].icon.IsEmpty());
+}
+
+TEST_F(BirchWeatherProviderTest, GetWeatherInCelsius) {
+  auto* birch_model = Shell::Get()->birch_model();
+
+  WeatherInfo info;
+  info.condition_description = "Cloudy";
+  info.condition_icon_url = "https://fake-icon-url";
+  info.temp_f = 70.0f;
+  info.show_celsius = true;
+  ambient_backend_controller_->SetWeatherInfo(std::move(info));
+
+  birch_model->RequestBirchDataFetch();
+
+  EXPECT_TRUE(birch_model->GetWeatherForTest().empty());
+
+  // The fake image downloader post a task to respond with an image.
+  base::RunLoop().RunUntilIdle();
+
+  auto& weather_items = birch_model->GetWeatherForTest();
+  ASSERT_EQ(1u, weather_items.size());
+  EXPECT_EQ(u"Cloudy", weather_items[0].title);
+  EXPECT_EQ(u"21\xB0 C", weather_items[0].temperature);
+  EXPECT_FALSE(weather_items[0].icon.IsEmpty());
+}
+
+TEST_F(BirchWeatherProviderTest, NoWeatherInfo) {
+  auto* birch_model = Shell::Get()->birch_model();
+
+  birch_model->RequestBirchDataFetch();
+
+  // The fake image downloader post a task to respond with an image.
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(birch_model->GetWeatherForTest().empty());
+}
+
+TEST_F(BirchWeatherProviderTest, WeatherWithNoIcon) {
+  auto* birch_model = Shell::Get()->birch_model();
+
+  WeatherInfo info;
+  info.condition_description = "Cloudy";
+  info.show_celsius = false;
+  info.temp_f = 70.0f;
+  ambient_backend_controller_->SetWeatherInfo(std::move(info));
+  birch_model->RequestBirchDataFetch();
+
+  // The fake image downloader post a task to respond with an image.
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(birch_model->GetWeatherForTest().empty());
+}
+
+TEST_F(BirchWeatherProviderTest, WeatherWithInvalidIcon) {
+  auto* birch_model = Shell::Get()->birch_model();
+
+  WeatherInfo info;
+  info.condition_description = "Cloudy";
+  info.condition_icon_url = "<invalid url>";
+  info.show_celsius = false;
+  info.temp_f = 70.0f;
+  ambient_backend_controller_->SetWeatherInfo(std::move(info));
+
+  birch_model->RequestBirchDataFetch();
+
+  // The fake image downloader post a task to respond with an image.
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(birch_model->GetWeatherForTest().empty());
+}
+
+TEST_F(BirchWeatherProviderTest, WeatherIconDownloadFailure) {
+  auto* birch_model = Shell::Get()->birch_model();
+
+  WeatherInfo info;
+  info.condition_description = "Cloudy";
+  info.condition_icon_url = "https://fake_icon_url";
+  info.show_celsius = false;
+  info.temp_f = 70.0f;
+  ambient_backend_controller_->SetWeatherInfo(std::move(info));
+
+  image_downloader_->set_should_fail(true);
+  birch_model->RequestBirchDataFetch();
+
+  // The fake image downloader post a task to respond with an image.
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(birch_model->GetWeatherForTest().empty());
+}
+
+TEST_F(BirchWeatherProviderTest, WeatherWithNoTemperature) {
+  auto* birch_model = Shell::Get()->birch_model();
+
+  WeatherInfo info;
+  info.condition_description = "Cloudy";
+  info.condition_icon_url = "https://fake_icon_url";
+  info.show_celsius = false;
+  ambient_backend_controller_->SetWeatherInfo(std::move(info));
+  birch_model->RequestBirchDataFetch();
+
+  // The fake image downloader post a task to respond with an image.
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(birch_model->GetWeatherForTest().empty());
+}
+
+TEST_F(BirchWeatherProviderTest, WeatherWithNoDecription) {
+  auto* birch_model = Shell::Get()->birch_model();
+
+  WeatherInfo info;
+  info.condition_icon_url = "https://fake_icon_url";
+  info.show_celsius = false;
+  info.temp_f = 70.0f;
+  ambient_backend_controller_->SetWeatherInfo(std::move(info));
+  birch_model->RequestBirchDataFetch();
+
+  // The fake image downloader post a task to respond with an image.
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(birch_model->GetWeatherForTest().empty());
+}
+
+TEST_F(BirchWeatherProviderTest, RefetchWeather) {
+  auto* birch_model = Shell::Get()->birch_model();
+
+  WeatherInfo info1;
+  info1.condition_description = "Cloudy";
+  info1.condition_icon_url = "https://fake-icon-url";
+  info1.show_celsius = false;
+  info1.temp_f = 70.0f;
+  ambient_backend_controller_->SetWeatherInfo(info1);
+
+  birch_model->RequestBirchDataFetch();
+
+  // The fake image downloader post a task to respond with an image.
+  base::RunLoop().RunUntilIdle();
+
+  auto& weather_items = birch_model->GetWeatherForTest();
+  ASSERT_EQ(1u, weather_items.size());
+  EXPECT_EQ(u"Cloudy", weather_items[0].title);
+  EXPECT_EQ(u"70\xB0 F", weather_items[0].temperature);
+  EXPECT_FALSE(weather_items[0].icon.IsEmpty());
+
+  WeatherInfo info2;
+  info2.condition_description = "Sunny";
+  info2.condition_icon_url = "https://fake-icon-url";
+  info2.show_celsius = false;
+  info2.temp_f = 73.0f;
+  ambient_backend_controller_->SetWeatherInfo(info2);
+
+  birch_model->RequestBirchDataFetch();
+
+  // The fake image downloader post a task to respond with an image.
+  base::RunLoop().RunUntilIdle();
+
+  auto& updated_weather_items = birch_model->GetWeatherForTest();
+  ASSERT_EQ(1u, updated_weather_items.size());
+  EXPECT_EQ(u"Sunny", updated_weather_items[0].title);
+  EXPECT_EQ(u"73\xB0 F", updated_weather_items[0].temperature);
+  EXPECT_FALSE(updated_weather_items[0].icon.IsEmpty());
+}
+
+TEST_F(BirchWeatherProviderTest, RefetchInvalidWeather) {
+  auto* birch_model = Shell::Get()->birch_model();
+
+  WeatherInfo info1;
+  info1.condition_description = "Cloudy";
+  info1.condition_icon_url = "https://fake-icon-url";
+  info1.show_celsius = false;
+  info1.temp_f = 70.0f;
+  ambient_backend_controller_->SetWeatherInfo(info1);
+
+  birch_model->RequestBirchDataFetch();
+
+  // The fake image downloader post a task to respond with an image.
+  base::RunLoop().RunUntilIdle();
+
+  auto& weather_items = birch_model->GetWeatherForTest();
+  ASSERT_EQ(1u, weather_items.size());
+  EXPECT_EQ(u"Cloudy", weather_items[0].title);
+  EXPECT_EQ(u"70\xB0 F", weather_items[0].temperature);
+  EXPECT_FALSE(weather_items[0].icon.IsEmpty());
+
+  WeatherInfo info2;
+  info2.show_celsius = false;
+  ambient_backend_controller_->SetWeatherInfo(info2);
+
+  birch_model->RequestBirchDataFetch();
+
+  // The fake image downloader post a task to respond with an image.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(birch_model->GetWeatherForTest().empty());
+}
+
+}  // namespace ash
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index bf867018..7b0089d2 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -286,6 +286,9 @@
              "CrosBatterySaverAlwaysOn",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Display weather information in birch UI.
+BASE_FEATURE(kBirchWeather, "BirchWeather", base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Enables or disables the usage of fixed Bluetooth A2DP packet size to improve
 // audio performance in noisy environment.
 BASE_FEATURE(kBluetoothFixA2dpPacketSize,
@@ -393,6 +396,11 @@
              "CameraPrivacySwitchNotifications",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+// Enables the feature to parameterize glyph for "Campbell" feature.
+BASE_FEATURE(kCampbellGlyph,
+             "CampbellGlyph",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Controls whether the capture mode advanced audio settings are enabled.
 BASE_FEATURE(kCaptureModeAudioMixing,
              "CaptureModeAudioMixing",
@@ -3187,6 +3195,10 @@
   return base::FeatureList::IsEnabled(kBatterySaverAlwaysOn);
 }
 
+bool IsBirchWeatherEnabled() {
+  return base::FeatureList::IsEnabled(kBirchWeather);
+}
+
 bool IsBluetoothDisconnectWarningEnabled() {
   return base::FeatureList::IsEnabled(kBluetoothDisconnectWarning);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 0cbc6f3..3f92e95 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -75,6 +75,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kAvatarsCloudMigration);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kBackgroundListening);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kBatterySaver);
+COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kBirchWeather);
 enum BatterySaverNotificationBehavior { kBSMAutoEnable, kBSMOptIn };
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::FeatureParam<BatterySaverNotificationBehavior>
@@ -111,6 +112,7 @@
 BASE_DECLARE_FEATURE(kCameraEffectsSupportedByHardware);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kCameraPrivacySwitchNotifications);
+COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kCampbellGlyph);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kCaptureModeAudioMixing);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kCaptureModeEducation);
 enum class CaptureModeEducationParam {
@@ -933,6 +935,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsBackgroundListeningEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsBatterySaverAvailable();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsBatterySaverAlwaysOn();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsBirchWeatherEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsBluetoothQualityReportEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsBluetoothDisconnectWarningEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsCaptureModeAudioMixingEnabled();
diff --git a/ash/constants/ash_switches.cc b/ash/constants/ash_switches.cc
index 614eb61..2f0ac24 100644
--- a/ash/constants/ash_switches.cc
+++ b/ash/constants/ash_switches.cc
@@ -31,6 +31,11 @@
 // Whether checking the forest secret key is ignored.
 bool g_ignore_forest_secret_key = false;
 
+// The hash value for the secret key of the campbell feature.
+constexpr char kCampbellHashKey[] =
+    "\x78\xb6\xa7\x59\x06\x11\xc7\xea\x09\x7e\x92\xe3\xe9\xff\xa6\x01\x4c"
+    "\x03\x18\x32";
+
 }  // namespace
 
 // Please keep the order of these switches synchronized with the header file
@@ -313,6 +318,11 @@
 // instead of displaying an interactive animation.
 const char kAuraLegacyPowerButton[] = "aura-legacy-power-button";
 
+// Switch used to pass in a secret key for Campbell feature. Unless the correct
+// secret key is provided, Campbell feature will remain disabled, regardless of
+// the state of the associated feature flag.
+const char kCampbellKey[] = "campbell-key";
+
 // If this flag is set, it indicates that this device is a "Cellular First"
 // device. Cellular First devices use cellular telephone data networks as
 // their primary means of connecting to the internet.
@@ -1331,6 +1341,24 @@
       kAllowDefaultShelfPinLayoutIgnoringSync);
 }
 
+bool IsCampbellSecretKeyMatched() {
+  // Commandline looks like:
+  //  out/Default/chrome --user-data-dir=/tmp/tmp123
+  //  --campbell-key="INSERT KEY HERE"
+  //  --enable-features=CampbellGlyph:icon/<icon>
+  const std::string provided_key_hash = base::SHA1HashString(
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          kCampbellKey));
+
+  const bool key_matched = (provided_key_hash == kCampbellHashKey);
+  if (!key_matched) {
+    LOG(ERROR)
+        << "Provided campbel secrey key does not match the expected one.";
+  }
+
+  return key_matched;
+}
+
 bool IsForestSecretKeyMatched() {
   if (g_ignore_forest_secret_key) {
     return true;
diff --git a/ash/constants/ash_switches.h b/ash/constants/ash_switches.h
index 2e14b16..a46e8e3 100644
--- a/ash/constants/ash_switches.h
+++ b/ash/constants/ash_switches.h
@@ -96,6 +96,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kAshUiModeClamshell[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kAshUiModeTablet[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kAuraLegacyPowerButton[];
+COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kCampbellKey[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kCellularFirst[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kChildWallpaperLarge[];
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kChildWallpaperSmall[];
@@ -499,6 +500,9 @@
 bool ShouldAllowDefaultShelfPinLayoutIgnoringSync();
 
 COMPONENT_EXPORT(ASH_CONSTANTS)
+bool IsCampbellSecretKeyMatched();
+
+COMPONENT_EXPORT(ASH_CONSTANTS)
 bool IsForestSecretKeyMatched();
 
 COMPONENT_EXPORT(ASH_CONSTANTS)
diff --git a/ash/glanceables/tasks/glanceables_task_view_pixeltest.cc b/ash/glanceables/tasks/glanceables_task_view_pixeltest.cc
index 4b7d33a..467eac4 100644
--- a/ash/glanceables/tasks/glanceables_task_view_pixeltest.cc
+++ b/ash/glanceables/tasks/glanceables_task_view_pixeltest.cc
@@ -37,9 +37,8 @@
 
     task_ = std::make_unique<api::Task>(
         "task-id", "Task title",
-        /*completed=*/false,
         has_due_date() ? std::make_optional(due_date) : std::nullopt,
-        has_subtasks(),
+        /*completed=*/false, has_subtasks(),
         /*has_email_link=*/false,
         /*has_notes=*/has_notes(), /*updated=*/base::Time());
 
diff --git a/ash/glanceables/tasks/glanceables_task_view_unittest.cc b/ash/glanceables/tasks/glanceables_task_view_unittest.cc
index eff9b36d..c4e1756b 100644
--- a/ash/glanceables/tasks/glanceables_task_view_unittest.cc
+++ b/ash/glanceables/tasks/glanceables_task_view_unittest.cc
@@ -62,8 +62,8 @@
     base::Time due;
     EXPECT_TRUE(base::Time::FromString(tc.due.c_str(), &due));
 
-    const auto task = api::Task("task-id", "Task title", /*completed=*/false,
-                                /*due=*/due,
+    const auto task = api::Task("task-id", "Task title",
+                                /*due=*/due, /*completed=*/false,
                                 /*has_subtasks=*/false,
                                 /*has_email_link=*/false, /*has_notes=*/false,
                                 /*updated=*/due);
@@ -81,8 +81,8 @@
 
 TEST_F(GlanceablesTaskViewTest,
        AppliesStrikeThroughStyleAfterMarkingAsComplete) {
-  const auto task = api::Task("task-id", "Task title", /*completed=*/false,
-                              /*due=*/std::nullopt,
+  const auto task = api::Task("task-id", "Task title",
+                              /*due=*/std::nullopt, /*completed=*/false,
                               /*has_subtasks=*/false, /*has_email_link=*/false,
                               /*has_notes=*/false, /*updated=*/base::Time());
 
@@ -115,8 +115,8 @@
 }
 
 TEST_F(GlanceablesTaskViewTest, InvokesMarkAsCompletedCallback) {
-  const auto task = api::Task("task-id", "Task title", /*completed=*/false,
-                              /*due=*/std::nullopt,
+  const auto task = api::Task("task-id", "Task title",
+                              /*due=*/std::nullopt, /*completed=*/false,
                               /*has_subtasks=*/false, /*has_email_link=*/false,
                               /*has_notes=*/false, /*updated=*/base::Time());
 
diff --git a/ash/glanceables/tasks/glanceables_task_view_v2_unittest.cc b/ash/glanceables/tasks/glanceables_task_view_v2_unittest.cc
index 156306c..f62754f 100644
--- a/ash/glanceables/tasks/glanceables_task_view_v2_unittest.cc
+++ b/ash/glanceables/tasks/glanceables_task_view_v2_unittest.cc
@@ -74,8 +74,8 @@
     base::Time due;
     EXPECT_TRUE(base::Time::FromString(tc.due.c_str(), &due));
 
-    const auto task = api::Task("task-id", "Task title", /*completed=*/false,
-                                /*due=*/due,
+    const auto task = api::Task("task-id", "Task title",
+                                /*due=*/due, /*completed=*/false,
                                 /*has_subtasks=*/false,
                                 /*has_email_link=*/false, /*has_notes=*/false,
                                 /*updated=*/due);
@@ -95,8 +95,8 @@
 
 TEST_F(GlanceablesTaskViewStableLaunchTest,
        AppliesStrikeThroughStyleAfterMarkingAsComplete) {
-  const auto task = api::Task("task-id", "Task title", /*completed=*/false,
-                              /*due=*/std::nullopt,
+  const auto task = api::Task("task-id", "Task title",
+                              /*due=*/std::nullopt, /*completed=*/false,
                               /*has_subtasks=*/false, /*has_email_link=*/false,
                               /*has_notes=*/false, /*updated=*/base::Time());
 
@@ -131,8 +131,8 @@
 }
 
 TEST_F(GlanceablesTaskViewStableLaunchTest, InvokesMarkAsCompletedCallback) {
-  const auto task = api::Task("task-id", "Task title", /*completed=*/false,
-                              /*due=*/std::nullopt,
+  const auto task = api::Task("task-id", "Task title",
+                              /*due=*/std::nullopt, /*completed=*/false,
                               /*has_subtasks=*/false, /*has_email_link=*/false,
                               /*has_notes=*/false, /*updated=*/base::Time());
 
@@ -172,8 +172,8 @@
 }
 
 TEST_F(GlanceablesTaskViewStableLaunchTest, EntersAndExitsEditState) {
-  const auto task = api::Task("task-id", "Task title", /*completed=*/false,
-                              /*due=*/std::nullopt,
+  const auto task = api::Task("task-id", "Task title",
+                              /*due=*/std::nullopt, /*completed=*/false,
                               /*has_subtasks=*/false, /*has_email_link=*/false,
                               /*has_notes=*/false, /*updated=*/base::Time());
 
@@ -262,8 +262,8 @@
 }
 
 TEST_F(GlanceablesTaskViewStableLaunchTest, InvokesSaveCallbackAfterEditing) {
-  const auto task = api::Task("task-id", "Task title", /*completed=*/false,
-                              /*due=*/std::nullopt,
+  const auto task = api::Task("task-id", "Task title",
+                              /*due=*/std::nullopt, /*completed=*/false,
                               /*has_subtasks=*/false, /*has_email_link=*/false,
                               /*has_notes=*/false, /*updated=*/base::Time());
 
@@ -324,8 +324,8 @@
 
     // Simulate reply, the view should update itself with the new task id.
     const auto created_task =
-        api::Task("task-id", "New", /*completed=*/false,
-                  /*due=*/absl::nullopt,
+        api::Task("task-id", "New",
+                  /*due=*/absl::nullopt, /*completed=*/false,
                   /*has_subtasks=*/false,
                   /*has_email_link=*/false, /*has_notes=*/false,
                   /*updated=*/base::Time::Now());
@@ -391,8 +391,8 @@
 
   // Simulate reply, this should re-enable the checkbox and title buttons.
   const auto created_task =
-      api::Task("task-id", "New", /*completed=*/false,
-                /*due=*/absl::nullopt,
+      api::Task("task-id", "New",
+                /*due=*/absl::nullopt, /*completed=*/false,
                 /*has_subtasks=*/false,
                 /*has_email_link=*/false, /*has_notes=*/false,
                 /*updated=*/base::Time::Now());
diff --git a/ash/glanceables/tasks/glanceables_tasks_view.cc b/ash/glanceables/tasks/glanceables_tasks_view.cc
index 7ef470a..3b02694 100644
--- a/ash/glanceables/tasks/glanceables_tasks_view.cc
+++ b/ash/glanceables/tasks/glanceables_tasks_view.cc
@@ -461,7 +461,8 @@
   if (task_id.empty()) {
     client->AddTask(task_list_id, title, std::move(on_task_saved));
   } else {
-    client->UpdateTask(task_list_id, task_id, title, std::move(on_task_saved));
+    client->UpdateTask(task_list_id, task_id, title, /*completed=*/false,
+                       std::move(on_task_saved));
   }
 }
 
diff --git a/ash/public/cpp/ambient/ambient_backend_controller.h b/ash/public/cpp/ambient/ambient_backend_controller.h
index b9f3ba52..70102ea 100644
--- a/ash/public/cpp/ambient/ambient_backend_controller.h
+++ b/ash/public/cpp/ambient/ambient_backend_controller.h
@@ -58,6 +58,9 @@
   WeatherInfo& operator=(const WeatherInfo&);
   ~WeatherInfo();
 
+  // The description of the weather condition.
+  std::optional<std::string> condition_description;
+
   // The url of the weather condition icon image.
   std::optional<std::string> condition_icon_url;
 
diff --git a/ash/public/cpp/holding_space/holding_space_metrics.cc b/ash/public/cpp/holding_space/holding_space_metrics.cc
index f4d88208..ef0152c6 100644
--- a/ash/public/cpp/holding_space/holding_space_metrics.cc
+++ b/ash/public/cpp/holding_space/holding_space_metrics.cc
@@ -9,6 +9,7 @@
 
 #include "ash/public/cpp/holding_space/holding_space_util.h"
 #include "base/check_is_test.h"
+#include "base/check_op.h"
 #include "base/containers/fixed_flat_set.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/notreached.h"
@@ -84,26 +85,6 @@
   return std::string();
 }
 
-}  // namespace
-
-// Utilities -------------------------------------------------------------------
-
-// Note that these values are persisted to histograms so must remain unchanged.
-size_t FilePathToExtension(const base::FilePath& file_path) {
-  if (file_path.empty())
-    return kEmptyExtension;
-
-  const std::string extension = base::ToLowerASCII(file_path.Extension());
-  if (extension.empty())
-    return kEmptyExtension;
-
-  auto* const* it = base::ranges::find(kKnownExtensions, extension);
-  if (it == kKnownExtensions.end())
-    return kOtherExtension;
-
-  return kFirstKnownExtension + std::distance(kKnownExtensions.begin(), it);
-}
-
 // Records the counts of the specified holding space `items` to the item count
 // histograms associated with the specified `prefix`.
 void RecordItemCounts(const std::string& prefix,
@@ -172,20 +153,42 @@
   }
 }
 
+}  // namespace
+
+// Utilities -------------------------------------------------------------------
+
+// Note that these values are persisted to histograms so must remain unchanged.
+size_t FilePathToExtension(const base::FilePath& file_path) {
+  if (file_path.empty()) {
+    return kEmptyExtension;
+  }
+
+  const std::string extension = base::ToLowerASCII(file_path.Extension());
+  if (extension.empty()) {
+    return kEmptyExtension;
+  }
+
+  const char* const* it = base::ranges::find(kKnownExtensions, extension);
+  if (it == kKnownExtensions.end()) {
+    return kOtherExtension;
+  }
+
+  return kFirstKnownExtension + std::distance(kKnownExtensions.begin(), it);
+}
+
 // Metrics ---------------------------------------------------------------------
 
-void RecordPodAction(PodAction action) {
-  base::UmaHistogramEnumeration("HoldingSpace.Pod.Action.All", action);
+void RecordBubbleResizeAnimationSmoothness(int smoothness) {
+  CHECK_GE(smoothness, 0);
+  CHECK_LE(smoothness, 100);
+  base::UmaHistogramPercentage("HoldingSpace.Animation.BubbleResize.Smoothness",
+                               smoothness);
 }
 
 void RecordDownloadsAction(DownloadsAction action) {
   base::UmaHistogramEnumeration("HoldingSpace.Downloads.Action.All", action);
 }
 
-void RecordFilesAppChipAction(FilesAppChipAction action) {
-  base::UmaHistogramEnumeration("HoldingSpace.FilesAppChip.Action.All", action);
-}
-
 void RecordFileCreatedFromShowSaveFilePicker(
     const GURL& file_picker_binding_context,
     const base::FilePath& file_path) {
@@ -197,6 +200,10 @@
       ToFilePickerBindingContext(file_picker_binding_context));
 }
 
+void RecordFilesAppChipAction(FilesAppChipAction action) {
+  base::UmaHistogramEnumeration("HoldingSpace.FilesAppChip.Action.All", action);
+}
+
 void RecordItemAction(const std::vector<const HoldingSpaceItem*>& items,
                       ItemAction action,
                       EventSource event_source) {
@@ -251,6 +258,17 @@
       "HoldingSpace.Item.Action.Launch.Failure.Reason", reason);
 }
 
+void RecordPodAction(PodAction action) {
+  base::UmaHistogramEnumeration("HoldingSpace.Pod.Action.All", action);
+}
+
+void RecordPodResizeAnimationSmoothness(int smoothness) {
+  CHECK_GE(smoothness, 0);
+  CHECK_LE(smoothness, 100);
+  base::UmaHistogramPercentage("HoldingSpace.Animation.PodResize.Smoothness",
+                               smoothness);
+}
+
 void RecordSuggestionsAction(SuggestionsAction action) {
   base::UmaHistogramEnumeration("HoldingSpace.Suggestions.Action.All", action);
 }
@@ -281,20 +299,6 @@
                                 /*buckets=*/50);
 }
 
-void RecordBubbleResizeAnimationSmoothness(int smoothness) {
-  DCHECK_GE(smoothness, 0);
-  DCHECK_LE(smoothness, 100);
-  base::UmaHistogramPercentage("HoldingSpace.Animation.BubbleResize.Smoothness",
-                               smoothness);
-}
-
-void RecordPodResizeAnimationSmoothness(int smoothness) {
-  DCHECK_GE(smoothness, 0);
-  DCHECK_LE(smoothness, 100);
-  base::UmaHistogramPercentage("HoldingSpace.Animation.PodResize.Smoothness",
-                               smoothness);
-}
-
 void RecordTotalItemCounts(const std::vector<const HoldingSpaceItem*>& items) {
   RecordItemCounts("HoldingSpace.Item.TotalCountV2", items);
 }
diff --git a/ash/public/cpp/holding_space/holding_space_metrics.h b/ash/public/cpp/holding_space/holding_space_metrics.h
index 751589a6..80b86fc 100644
--- a/ash/public/cpp/holding_space/holding_space_metrics.h
+++ b/ash/public/cpp/holding_space/holding_space_metrics.h
@@ -16,27 +16,7 @@
 
 namespace ash::holding_space_metrics {
 
-// Returns the numeric representation of the extension for `file_path`.
-ASH_PUBLIC_EXPORT size_t FilePathToExtension(const base::FilePath& file_path);
-
-// Enumeration of actions that can be taken on the holding space pod in the
-// shelf. These values are persisted to logs. Entries should not be renumbered
-// and numeric values should never be reused.
-enum class PodAction {
-  // kClick (Deprecated) = 0,
-  kShowBubble = 1,
-  kCloseBubble = 2,
-  kShowContextMenu = 3,
-  kShowPreviews = 4,
-  kHidePreviews = 5,
-  kShowPod = 6,
-  kHidePod = 7,
-  kDragAndDropToPin = 8,
-  kMaxValue = kDragAndDropToPin,
-};
-
-// Records the specified `action` taken on the holding space pod in the shelf.
-ASH_PUBLIC_EXPORT void RecordPodAction(PodAction action);
+// Enums -----------------------------------------------------------------------
 
 // Enumeration of actions that can be taken on the holding space downloads
 // button. These values are persisted to logs. Entries should not be renumbered
@@ -46,20 +26,18 @@
   kMaxValue = kClick,
 };
 
-// Records the specified `action` taken on the holding space downloads header.
-ASH_PUBLIC_EXPORT void RecordDownloadsAction(DownloadsAction action);
-
-// Enumeration of actions that can be taken on the holding space Files app chip.
-// These values are persisted to logs. Entries should not be renumbered and
-// numeric values should never be reused.
-enum class FilesAppChipAction {
-  kClick = 0,
-  kMaxValue = kClick,
+// Enumeration of sources for events that occur in (and to) holding space.
+enum class EventSource {
+  kHoldingSpaceBubble = 0,
+  kHoldingSpaceItem = 1,
+  kHoldingSpaceItemContextMenu = 2,
+  kHoldingSpaceTray = 3,
+  kFilesApp = 4,
+  kTest = 5,
+  kWallpaper = 6,
+  kMaxValue = kWallpaper,
 };
 
-// Records the specified `action` taken on the holding space Files app chip.
-ASH_PUBLIC_EXPORT void RecordFilesAppChipAction(FilesAppChipAction action);
-
 // Enumeration of binding contexts for the file picker used to create a file in
 // fulfillment of a `window.showSaveFilePicker()` request. These values are
 // persisted to logs. Entries should not be renumbered and numeric values should
@@ -70,12 +48,13 @@
   kMaxValue = kPhotoshopWeb,
 };
 
-// Records that a file picker with the specified `file_picker_binding_context`
-// was used to create the file at the specified `file_path` in fulfillment of a
-// `window.showSaveFilePicker()` request.
-ASH_PUBLIC_EXPORT void RecordFileCreatedFromShowSaveFilePicker(
-    const GURL& file_picker_binding_context,
-    const base::FilePath& file_path);
+// Enumeration of actions that can be taken on the holding space Files app chip.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class FilesAppChipAction {
+  kClick = 0,
+  kMaxValue = kClick,
+};
 
 // Enumeration of actions that can be taken on holding space items. These values
 // are persisted to logs. Entries should not be renumbered and numeric values
@@ -94,29 +73,6 @@
   kMaxValue = kResume,
 };
 
-// Enumeration of sources for events that occur in (and to) holding space.
-enum class EventSource {
-  kHoldingSpaceBubble = 0,
-  kHoldingSpaceItem = 1,
-  kHoldingSpaceItemContextMenu = 2,
-  kHoldingSpaceTray = 3,
-  kFilesApp = 4,
-  kTest = 5,
-  kWallpaper = 6,
-  kMaxValue = kWallpaper,
-};
-
-// Records the specified `action` taken on a set of holding space `items`.
-ASH_PUBLIC_EXPORT void RecordItemAction(
-    const std::vector<const HoldingSpaceItem*>& items,
-    ItemAction action,
-    EventSource event_source);
-
-// Records an attempt to launch a holding space item of the specified `type`
-// backed by the empty file at the specified `file_path`.
-ASH_PUBLIC_EXPORT void RecordItemLaunchEmpty(HoldingSpaceItem::Type type,
-                                             const base::FilePath& file_path);
-
 // Enumeration of reasons that a holding space item might fail to launch. These
 // values are persisted to logs. Entries should not be renumbered and numeric
 // values should never be reused.
@@ -136,11 +92,21 @@
   kMaxValue = kShutdown,
 };
 
-// Records a failure to launch a holding space item of the specified `type`
-// backed by the file at the specified `file_path` with the specified `reason`.
-ASH_PUBLIC_EXPORT void RecordItemLaunchFailure(HoldingSpaceItem::Type type,
-                                               const base::FilePath& file_path,
-                                               ItemLaunchFailureReason reason);
+// Enumeration of actions that can be taken on the holding space pod in the
+// shelf. These values are persisted to logs. Entries should not be renumbered
+// and numeric values should never be reused.
+enum class PodAction {
+  // kClick (Deprecated) = 0,
+  kShowBubble = 1,
+  kCloseBubble = 2,
+  kShowContextMenu = 3,
+  kShowPreviews = 4,
+  kHidePreviews = 5,
+  kShowPod = 6,
+  kHidePod = 7,
+  kDragAndDropToPin = 8,
+  kMaxValue = kDragAndDropToPin,
+};
 
 // Enumeration of actions that can be taken on the holding space suggestions
 // section button. These values are persisted to logs. Entries should not be
@@ -151,6 +117,64 @@
   kMaxValue = kExpand,
 };
 
+// Structs ---------------------------------------------------------------------
+
+// Representation of a user's preferences.
+struct ASH_PUBLIC_EXPORT UserPreferences {
+  bool previews_enabled = false;
+  bool suggestions_expanded = false;
+};
+
+// Utilities -------------------------------------------------------------------
+
+// Returns the numeric representation of the extension for `file_path`.
+ASH_PUBLIC_EXPORT size_t FilePathToExtension(const base::FilePath& file_path);
+
+// Metrics ---------------------------------------------------------------------
+
+// Records the `smoothness` of the holding space bubble resize animation. Note
+// that `smoothness` is expected to be between 0 and 100 (inclusively) with
+// 100 representing ideal smoothness of >= 60 frames per second.
+ASH_PUBLIC_EXPORT void RecordBubbleResizeAnimationSmoothness(int smoothness);
+
+// Records the specified `action` taken on the holding space downloads header.
+ASH_PUBLIC_EXPORT void RecordDownloadsAction(DownloadsAction action);
+
+// Records that a file picker with the specified `file_picker_binding_context`
+// was used to create the file at the specified `file_path` in fulfillment of a
+// `window.showSaveFilePicker()` request.
+ASH_PUBLIC_EXPORT void RecordFileCreatedFromShowSaveFilePicker(
+    const GURL& file_picker_binding_context,
+    const base::FilePath& file_path);
+
+// Records the specified `action` taken on the holding space Files app chip.
+ASH_PUBLIC_EXPORT void RecordFilesAppChipAction(FilesAppChipAction action);
+
+// Records the specified `action` taken on a set of holding space `items`.
+ASH_PUBLIC_EXPORT void RecordItemAction(
+    const std::vector<const HoldingSpaceItem*>& items,
+    ItemAction action,
+    EventSource event_source);
+
+// Records an attempt to launch a holding space item of the specified `type`
+// backed by the empty file at the specified `file_path`.
+ASH_PUBLIC_EXPORT void RecordItemLaunchEmpty(HoldingSpaceItem::Type type,
+                                             const base::FilePath& file_path);
+
+// Records a failure to launch a holding space item of the specified `type`
+// backed by the file at the specified `file_path` with the specified `reason`.
+ASH_PUBLIC_EXPORT void RecordItemLaunchFailure(HoldingSpaceItem::Type type,
+                                               const base::FilePath& file_path,
+                                               ItemLaunchFailureReason reason);
+
+// Records the specified `action` taken on the holding space pod in the shelf.
+ASH_PUBLIC_EXPORT void RecordPodAction(PodAction action);
+
+// Records the `smoothness` of the holding space pod resize animation. Note that
+// `smoothness` is expected to be between 0 and 100 (inclusively) with 100
+// representing ideal smoothness of >= 60 frames per second.
+ASH_PUBLIC_EXPORT void RecordPodResizeAnimationSmoothness(int smoothness);
+
 // Records the specified `action` taken on the holding space suggestions header.
 ASH_PUBLIC_EXPORT void RecordSuggestionsAction(SuggestionsAction action);
 
@@ -167,26 +191,10 @@
 ASH_PUBLIC_EXPORT void RecordTimeFromFirstEntryToFirstPin(
     base::TimeDelta time_delta);
 
-// Records the `smoothness` of the holding space bubble resize animation. Note
-// that `smoothness` is expected to be between 0 and 100 (inclusively) with
-// 100 representing ideal smoothness of >= 60 frames per second.
-ASH_PUBLIC_EXPORT void RecordBubbleResizeAnimationSmoothness(int smoothness);
-
-// Records the `smoothness` of the holding space pod resize animation. Note that
-// `smoothness` is expected to be between 0 and 100 (inclusively) with 100
-// representing ideal smoothness of >= 60 frames per second.
-ASH_PUBLIC_EXPORT void RecordPodResizeAnimationSmoothness(int smoothness);
-
 // Records total counts for the specified holding space `items`.
 ASH_PUBLIC_EXPORT void RecordTotalItemCounts(
     const std::vector<const HoldingSpaceItem*>& items);
 
-// Representation of a user's preferences.
-struct ASH_PUBLIC_EXPORT UserPreferences {
-  bool previews_enabled = false;
-  bool suggestions_expanded = false;
-};
-
 // Records a user's preferences.
 ASH_PUBLIC_EXPORT void RecordUserPreferences(UserPreferences user_preferences);
 
diff --git a/ash/public/cpp/picker/DIR_METADATA b/ash/public/cpp/picker/DIR_METADATA
new file mode 100644
index 0000000..29b0130
--- /dev/null
+++ b/ash/public/cpp/picker/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//ash/picker/COMMON_METADATA"
diff --git a/ash/public/cpp/picker/OWNERS b/ash/public/cpp/picker/OWNERS
new file mode 100644
index 0000000..a1f83773
--- /dev/null
+++ b/ash/public/cpp/picker/OWNERS
@@ -0,0 +1 @@
+file://ash/picker/OWNERS
diff --git a/ash/public/mojom/accelerator_configuration.mojom b/ash/public/mojom/accelerator_configuration.mojom
index 7695cc9..042c0ac9 100644
--- a/ash/public/mojom/accelerator_configuration.mojom
+++ b/ash/public/mojom/accelerator_configuration.mojom
@@ -43,4 +43,6 @@
   kSearchWithFunctionKeyNotAllowed = 12,
   // Error - reserved key is not allowed.
   kReservedKeyNotAllowed = 13,
+  // Error - non-standard key is used with the search modifier.
+  kNonStandardWithSearch = 14,
 };
\ No newline at end of file
diff --git a/ash/quick_pair/feature_status_tracker/BUILD.gn b/ash/quick_pair/feature_status_tracker/BUILD.gn
index 01696f9..2f4ba74 100644
--- a/ash/quick_pair/feature_status_tracker/BUILD.gn
+++ b/ash/quick_pair/feature_status_tracker/BUILD.gn
@@ -25,6 +25,8 @@
     "hardware_offloading_supported_provider.h",
     "logged_in_user_enabled_provider.cc",
     "logged_in_user_enabled_provider.h",
+    "power_connected_provider.cc",
+    "power_connected_provider.h",
     "quick_pair_feature_status_tracker.h",
     "quick_pair_feature_status_tracker_impl.cc",
     "quick_pair_feature_status_tracker_impl.h",
@@ -89,6 +91,7 @@
     "fast_pair_support_utils_unittest.cc",
     "hardware_offloading_supported_provider_unittest.cc",
     "logged_in_user_enabled_provider_unittest.cc",
+    "power_connected_provider_unittest.cc",
     "screen_state_enabled_provider_unittest.cc",
   ]
 
diff --git a/ash/quick_pair/feature_status_tracker/power_connected_provider.cc b/ash/quick_pair/feature_status_tracker/power_connected_provider.cc
new file mode 100644
index 0000000..289ace9
--- /dev/null
+++ b/ash/quick_pair/feature_status_tracker/power_connected_provider.cc
@@ -0,0 +1,31 @@
+// 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.
+
+#include "ash/quick_pair/feature_status_tracker/power_connected_provider.h"
+
+namespace ash {
+namespace quick_pair {
+
+PowerConnectedProvider::PowerConnectedProvider() {
+  if (PowerStatus::IsInitialized()) {
+    power_status_ = PowerStatus::Get();
+    power_status_->AddObserver(this);
+    SetEnabledAndInvokeCallback(power_status_->IsLinePowerConnected());
+    return;
+  }
+}
+
+PowerConnectedProvider::~PowerConnectedProvider() {
+  if (power_status_) {
+    power_status_->RemoveObserver(this);
+  }
+}
+
+void PowerConnectedProvider::OnPowerStatusChanged() {
+  SetEnabledAndInvokeCallback(
+      /*new_value=*/power_status_ && power_status_->IsLinePowerConnected());
+}
+
+}  // namespace quick_pair
+}  // namespace ash
diff --git a/ash/quick_pair/feature_status_tracker/power_connected_provider.h b/ash/quick_pair/feature_status_tracker/power_connected_provider.h
new file mode 100644
index 0000000..34ed2f7
--- /dev/null
+++ b/ash/quick_pair/feature_status_tracker/power_connected_provider.h
@@ -0,0 +1,32 @@
+// 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.
+
+#ifndef ASH_QUICK_PAIR_FEATURE_STATUS_TRACKER_POWER_CONNECTED_PROVIDER_H_
+#define ASH_QUICK_PAIR_FEATURE_STATUS_TRACKER_POWER_CONNECTED_PROVIDER_H_
+
+#include "ash/quick_pair/feature_status_tracker/base_enabled_provider.h"
+#include "ash/system/power/power_status.h"
+
+namespace ash {
+namespace quick_pair {
+
+class PowerConnectedProvider : public BaseEnabledProvider,
+                               public PowerStatus::Observer {
+ public:
+  explicit PowerConnectedProvider();
+  ~PowerConnectedProvider() override;
+
+ private:
+  friend class PowerConnectedProviderTest;
+
+  // PoweStatus::Observer
+  void OnPowerStatusChanged() override;
+
+  raw_ptr<PowerStatus> power_status_;
+};
+
+}  // namespace quick_pair
+}  // namespace ash
+
+#endif  // ASH_QUICK_PAIR_FEATURE_STATUS_TRACKER_POWER_CONNECTED_PROVIDER_H_
diff --git a/ash/quick_pair/feature_status_tracker/power_connected_provider_unittest.cc b/ash/quick_pair/feature_status_tracker/power_connected_provider_unittest.cc
new file mode 100644
index 0000000..6e5ac67a
--- /dev/null
+++ b/ash/quick_pair/feature_status_tracker/power_connected_provider_unittest.cc
@@ -0,0 +1,94 @@
+// 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.
+
+#include "ash/quick_pair/feature_status_tracker/power_connected_provider.h"
+
+#include "ash/system/power/power_status.h"
+#include "ash/test/ash_test_base.h"
+
+namespace ash {
+namespace quick_pair {
+
+class PowerConnectedProviderTest : public AshTestBase {
+ public:
+  // PowerStatus must be initialized before AshTestBase::TearDown() because the
+  // latter calls PowerStatus::Shutdown, which crashes if the PowerStatus is not
+  // initialized.
+  void TearDown() override {
+    power_connected_provider_.reset();
+    if (!PowerStatus::IsInitialized()) {
+      PowerStatus::Initialize();
+    }
+    AshTestBase::TearDown();
+  }
+
+  void SetPowerPropertiesAndNotifyProvider(
+      power_manager::PowerSupplyProperties_ExternalPower power_status) {
+    if (!power_connected_provider_) {
+      return;
+    }
+
+    if (!PowerStatus::IsInitialized()) {
+      return;
+    }
+
+    properties_.set_external_power(power_status);
+    PowerStatus::Get()->SetProtoForTesting(properties_);
+    power_connected_provider_->OnPowerStatusChanged();
+  }
+
+  void InitializeProvider() {
+    power_connected_provider_ = std::make_unique<PowerConnectedProvider>();
+  }
+
+  void InitializePowerStatus(bool should_initialize) {
+    if (should_initialize && !PowerStatus::IsInitialized()) {
+      PowerStatus::Initialize();
+    } else if (!should_initialize && PowerStatus::IsInitialized()) {
+      PowerStatus::Shutdown();
+    }
+    CHECK(should_initialize == PowerStatus::IsInitialized());
+  }
+
+  bool IsPowerConnected() {
+    return power_connected_provider_ && power_connected_provider_->is_enabled();
+  }
+
+ private:
+  std::unique_ptr<PowerConnectedProvider> power_connected_provider_;
+  power_manager::PowerSupplyProperties properties_;
+};
+
+TEST_F(PowerConnectedProviderTest, DisabledIfPowerStatusNotInitialized) {
+  InitializePowerStatus(/*should_initialize=*/false);
+  InitializeProvider();
+  EXPECT_FALSE(IsPowerConnected());
+}
+
+TEST_F(PowerConnectedProviderTest, EnabledWhenACConnection) {
+  InitializePowerStatus(/*should_initialize=*/true);
+  InitializeProvider();
+  SetPowerPropertiesAndNotifyProvider(
+      power_manager::PowerSupplyProperties_ExternalPower_AC);
+  EXPECT_TRUE(IsPowerConnected());
+}
+
+TEST_F(PowerConnectedProviderTest, EnabledWhenUSBConnection) {
+  InitializePowerStatus(/*should_initialize=*/true);
+  InitializeProvider();
+  SetPowerPropertiesAndNotifyProvider(
+      power_manager::PowerSupplyProperties_ExternalPower_USB);
+  EXPECT_TRUE(IsPowerConnected());
+}
+
+TEST_F(PowerConnectedProviderTest, DisabledWhenDisconnected) {
+  InitializePowerStatus(/*should_initialize=*/true);
+  InitializeProvider();
+  SetPowerPropertiesAndNotifyProvider(
+      power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED);
+  EXPECT_FALSE(IsPowerConnected());
+}
+
+}  // namespace quick_pair
+}  // namespace ash
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index 84cc7f9b8..6be78e9 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -43,6 +43,10 @@
     "battery_saver_plus_outline.icon",
     "calendar_background.icon",
     "calendar_up_next_todays_events_button.icon",
+    "campbell_9dot.icon",
+    "campbell_action.icon",
+    "campbell_hero.icon",
+    "campbell_text.icon",
     "cancel.icon",
     "cancel_circle_outline.icon",
     "capture_gif.icon",
diff --git a/ash/resources/vector_icons/campbell_9dot.icon b/ash/resources/vector_icons/campbell_9dot.icon
new file mode 100644
index 0000000..5e14e5a
--- /dev/null
+++ b/ash/resources/vector_icons/campbell_9dot.icon
@@ -0,0 +1,60 @@
+// 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.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 15, 7,
+R_CUBIC_TO, 1.1f, 0, 2, -0.9f, 2, -2,
+R_CUBIC_TO, 0, -1.1f, -0.9f, -2, -2, -2,
+R_CUBIC_TO, -1.1f, 0, -2, 0.9f, -2, 2,
+R_CUBIC_TO, 0, 1.1f, 0.9f, 2, 2, 2,
+CLOSE,
+MOVE_TO, 5, 17,
+R_CUBIC_TO, 1.1f, 0, 2, -0.9f, 2, -2,
+R_CUBIC_TO, 0, -1.1f, -0.9f, -2, -2, -2,
+R_CUBIC_TO, -1.1f, 0, -2, 0.9f, -2, 2,
+R_CUBIC_TO, 0, 1.1f, 0.9f, 2, 2, 2,
+CLOSE,
+R_MOVE_TO, 10, 0,
+R_CUBIC_TO, 1.1f, 0, 2, -0.9f, 2, -2,
+R_CUBIC_TO, 0, -1.1f, -0.9f, -2, -2, -2,
+R_CUBIC_TO, -1.1f, 0, -2, 0.9f, -2, 2,
+R_CUBIC_TO, 0, 1.1f, 0.9f, 2, 2, 2,
+CLOSE,
+R_MOVE_TO, -3, -2,
+R_CUBIC_TO, 0, 1.1f, -0.9f, 2, -2, 2,
+R_CUBIC_TO, -1.1f, 0, -2, -0.9f, -2, -2,
+R_CUBIC_TO, 0, -1.1f, 0.9f, -2, 2, -2,
+R_CUBIC_TO, 1.1f, 0, 2, 0.9f, 2, 2,
+CLOSE,
+MOVE_TO, 7, 5,
+R_CUBIC_TO, 0, 1.1f, -0.9f, 2, -2, 2,
+R_CUBIC_TO, -1.1f, 0, -2, -0.9f, -2, -2,
+R_CUBIC_TO, 0, -1.1f, 0.9f, -2, 2, -2,
+R_CUBIC_TO, 1.1f, 0, 2, 0.9f, 2, 2,
+CLOSE,
+R_MOVE_TO, 3, 2,
+R_CUBIC_TO, 1.1f, 0, 2, -0.9f, 2, -2,
+R_CUBIC_TO, 0, -1.1f, -0.9f, -2, -2, -2,
+R_CUBIC_TO, -1.1f, 0, -2, 0.9f, -2, 2,
+R_CUBIC_TO, 0, 1.1f, 0.9f, 2, 2, 2,
+CLOSE,
+R_MOVE_TO, 7, 3,
+R_CUBIC_TO, 0, 1.1f, -0.9f, 2, -2, 2,
+R_CUBIC_TO, -1.1f, 0, -2, -0.9f, -2, -2,
+R_CUBIC_TO, 0, -1.1f, 0.9f, -2, 2, -2,
+R_CUBIC_TO, 1.1f, 0, 2, 0.9f, 2, 2,
+CLOSE,
+MOVE_TO, 5, 12,
+R_CUBIC_TO, 1.1f, 0, 2, -0.9f, 2, -2,
+R_CUBIC_TO, 0, -1.1f, -0.9f, -2, -2, -2,
+R_CUBIC_TO, -1.1f, 0, -2, 0.9f, -2, 2,
+R_CUBIC_TO, 0, 1.1f, 0.9f, 2, 2, 2,
+CLOSE,
+R_MOVE_TO, 7, -2,
+R_CUBIC_TO, 0, 1.1f, -0.9f, 2, -2, 2,
+R_CUBIC_TO, -1.1f, 0, -2, -0.9f, -2, -2,
+R_CUBIC_TO, 0, -1.1f, 0.9f, -2, 2, -2,
+R_CUBIC_TO, 1.1f, 0, 2, 0.9f, 2, 2,
+CLOSE
+
diff --git a/ash/resources/vector_icons/campbell_action.icon b/ash/resources/vector_icons/campbell_action.icon
new file mode 100644
index 0000000..5744c2d
--- /dev/null
+++ b/ash/resources/vector_icons/campbell_action.icon
@@ -0,0 +1,62 @@
+// 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.
+
+CANVAS_DIMENSIONS, 20,
+R_MOVE_TO, 16.37f, 17.37f,
+R_LINE_TO, -2, -2,
+R_CUBIC_TO, -0.2f, 0.12f, -0.41f, 0.22f, -0.63f, 0.28f,
+R_ARC_TO, 2.87f, 2.87f, 0, 0, 1, -0.7f, 0.08f,
+R_CUBIC_TO, -0.75f, 0, -1.4f, -0.26f, -1.93f, -0.78f,
+R_ARC_TO, 2.64f, 2.64f, 0, 0, 1, -0.78f, -1.92f,
+R_CUBIC_TO, 0, -0.75f, 0.26f, -1.39f, 0.78f, -1.92f,
+R_ARC_TO, 2.63f, 2.63f, 0, 0, 1, 1.93f, -0.8f,
+R_ARC_TO, 2.58f, 2.58f, 0, 0, 1, 1.92f, 0.8f,
+R_CUBIC_TO, 0.52f, 0.52f, 0.78f, 1.16f, 0.78f, 1.92f,
+R_CUBIC_TO, 0, 0.26f, -0.03f, 0.5f, -0.1f, 0.73f,
+R_ARC_TO, 2.34f, 2.34f, 0, 0, 1, -0.28f, 0.63f,
+R_LINE_TO, 2, 1.98f,
+R_LINE_TO, -0.98f, 0.98f,
+CLOSE,
+R_MOVE_TO, -10.6f, -1.63f,
+R_CUBIC_TO, -0.76f, 0, -1.39f, -0.26f, -1.92f, -0.78f,
+R_CUBIC_TO, -0.52f, -0.52f, -0.78f, -1.16f, -0.78f, -1.92f,
+R_CUBIC_TO, 0, -0.75f, 0.26f, -1.39f, 0.78f, -1.92f,
+R_ARC_TO, 2.58f, 2.58f, 0, 0, 1, 1.92f, -0.8f,
+R_ARC_TO, 2.58f, 2.58f, 0, 0, 1, 1.92f, 0.8f,
+R_CUBIC_TO, 0.53f, 0.52f, 0.8f, 1.16f, 0.8f, 1.92f,
+R_ARC_TO, 2.58f, 2.58f, 0, 0, 1, -0.8f, 1.92f,
+R_CUBIC_TO, -0.52f, 0.52f, -1.16f, 0.78f, -1.92f, 0.78f,
+CLOSE,
+R_MOVE_TO, 7.27f, -1.37f,
+R_CUBIC_TO, 0.37f, 0, 0.68f, -0.13f, 0.93f, -0.38f,
+R_CUBIC_TO, 0.26f, -0.27f, 0.38f, -0.58f, 0.38f, -0.95f,
+R_CUBIC_TO, 0, -0.37f, -0.13f, -0.68f, -0.4f, -0.93f,
+R_ARC_TO, 1.24f, 1.24f, 0, 0, 0, -0.93f, -0.4f,
+R_CUBIC_TO, -0.37f, 0, -0.68f, 0.13f, -0.93f, 0.4f,
+R_ARC_TO, 1.27f, 1.27f, 0, 0, 0, -0.38f, 0.93f,
+R_CUBIC_TO, 0, 0.37f, 0.13f, 0.68f, 0.38f, 0.95f,
+R_CUBIC_TO, 0.27f, 0.26f, 0.58f, 0.38f, 0.95f, 0.38f,
+CLOSE,
+MOVE_TO, 5.77f, 8.48f,
+R_CUBIC_TO, -0.76f, 0, -1.39f, -0.26f, -1.92f, -0.78f,
+R_ARC_TO, 2.64f, 2.64f, 0, 0, 1, -0.78f, -1.92f,
+R_CUBIC_TO, 0, -0.75f, 0.26f, -1.39f, 0.78f, -1.92f,
+R_ARC_TO, 2.58f, 2.58f, 0, 0, 1, 1.92f, -0.8f,
+R_ARC_TO, 2.58f, 2.58f, 0, 0, 1, 1.92f, 0.8f,
+R_CUBIC_TO, 0.53f, 0.52f, 0.8f, 1.16f, 0.8f, 1.9f,
+R_CUBIC_TO, 0, 0.76f, -0.27f, 1.4f, -0.8f, 1.93f,
+R_CUBIC_TO, -0.52f, 0.52f, -1.16f, 0.78f, -1.92f, 0.78f,
+CLOSE,
+R_MOVE_TO, 7.27f, 0,
+R_CUBIC_TO, -0.75f, 0, -1.4f, -0.26f, -1.93f, -0.78f,
+R_ARC_TO, 2.64f, 2.64f, 0, 0, 1, -0.78f, -1.92f,
+R_CUBIC_TO, 0, -0.75f, 0.26f, -1.39f, 0.78f, -1.92f,
+R_ARC_TO, 2.62f, 2.62f, 0, 0, 1, 1.92f, -0.8f,
+R_ARC_TO, 2.58f, 2.58f, 0, 0, 1, 1.92f, 0.8f,
+R_CUBIC_TO, 0.53f, 0.52f, 0.8f, 1.16f, 0.8f, 1.9f,
+R_CUBIC_TO, 0, 0.76f, -0.27f, 1.4f, -0.8f, 1.93f,
+R_ARC_TO, 2.59f, 2.59f, 0, 0, 1, -1.9f, 0.78f,
+CLOSE,
+NEW_PATH
+
diff --git a/ash/resources/vector_icons/campbell_hero.icon b/ash/resources/vector_icons/campbell_hero.icon
new file mode 100644
index 0000000..9b73e27
--- /dev/null
+++ b/ash/resources/vector_icons/campbell_hero.icon
@@ -0,0 +1,35 @@
+// 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.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 10, 16.52f,
+R_CUBIC_TO, -0.9f, 0, -1.75f, -0.17f, -2.55f, -0.5f,
+R_ARC_TO, 6.66f, 6.66f, 0, 0, 1, -2.07f, -1.4f,
+R_ARC_TO, 6.66f, 6.66f, 0, 0, 1, -1.4f, -2.07f,
+R_ARC_TO, 6.57f, 6.57f, 0, 0, 1, -0.5f, -2.55f,
+R_CUBIC_TO, 0, -0.9f, 0.17f, -1.74f, 0.5f, -2.53f,
+R_ARC_TO, 6.66f, 6.66f, 0, 0, 1, 1.4f, -2.07f,
+ARC_TO, 6.3f, 6.3f, 0, 0, 1, 7.45f, 4,
+ARC_TO, 6.38f, 6.38f, 0, 0, 1, 10, 3.48f,
+R_CUBIC_TO, 0.82f, 0, 1.6f, 0.15f, 2.33f, 0.45f,
+R_CUBIC_TO, 0.75f, 0.29f, 1.42f, 0.7f, 2.03f, 1.23f,
+R_LINE_TO, -1.85f, 1.8f,
+R_ARC_TO, 3.89f, 3.89f, 0, 0, 0, -1.17f, -0.7f,
+ARC_TO, 3.44f, 3.44f, 0, 0, 0, 10, 6,
+R_CUBIC_TO, -1.09f, 0, -2.02f, 0.39f, -2.78f, 1.18f,
+ARC_TO, 3.93f, 3.93f, 0, 0, 0, 6.08f, 10,
+R_CUBIC_TO, 0, 1.1f, 0.38f, 2.04f, 1.13f, 2.82f,
+R_CUBIC_TO, 0.77f, 0.78f, 1.69f, 1.17f, 2.78f, 1.17f,
+R_CUBIC_TO, 0.92f, 0, 1.71f, -0.25f, 2.37f, -0.77f,
+R_ARC_TO, 3.11f, 3.11f, 0, 0, 0, 1.22f, -1.98f,
+H_LINE_TO, 10,
+V_LINE_TO, 8.82f,
+R_H_LINE_TO, 6.12f,
+R_CUBIC_TO, 0.06f, 0.23f, 0.09f, 0.46f, 0.12f, 0.68f,
+R_CUBIC_TO, 0.02f, 0.21f, 0.03f, 0.43f, 0.03f, 0.65f,
+R_CUBIC_TO, 0, 1.92f, -0.58f, 3.47f, -1.73f, 4.63f,
+R_CUBIC_TO, -1.14f, 1.16f, -2.65f, 1.73f, -4.53f, 1.73f,
+CLOSE,
+NEW_PATH
+
diff --git a/ash/resources/vector_icons/campbell_text.icon b/ash/resources/vector_icons/campbell_text.icon
new file mode 100644
index 0000000..a6460d1
--- /dev/null
+++ b/ash/resources/vector_icons/campbell_text.icon
@@ -0,0 +1,77 @@
+// 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.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 14.17f, 13.81f,
+R_CUBIC_TO, -0.74f, 0, -1.38f, -0.16f, -1.92f, -0.49f,
+R_ARC_TO, 3.42f, 3.42f, 0, 0, 1, -1.26f, -1.39f,
+R_CUBIC_TO, -0.29f, -0.59f, -0.43f, -1.26f, -0.43f, -2.03f,
+R_CUBIC_TO, 0, -0.77f, 0.14f, -1.45f, 0.43f, -2.03f,
+R_ARC_TO, 3.32f, 3.32f, 0, 0, 1, 1.26f, -1.37f,
+R_CUBIC_TO, 0.54f, -0.34f, 1.18f, -0.5f, 1.92f, -0.5f,
+R_CUBIC_TO, 0.75f, 0, 1.39f, 0.17f, 1.92f, 0.5f,
+R_CUBIC_TO, 0.54f, 0.33f, 0.96f, 0.78f, 1.25f, 1.37f,
+R_CUBIC_TO, 0.3f, 0.58f, 0.45f, 1.25f, 0.45f, 2.03f,
+R_CUBIC_TO, 0, 0.77f, -0.15f, 1.44f, -0.45f, 2.03f,
+R_ARC_TO, 3.32f, 3.32f, 0, 0, 1, -1.25f, 1.39f,
+R_CUBIC_TO, -0.53f, 0.33f, -1.17f, 0.49f, -1.92f, 0.49f,
+CLOSE,
+R_MOVE_TO, 0, -1.39f,
+R_CUBIC_TO, 0.42f, 0, 0.79f, -0.1f, 1.11f, -0.29f,
+R_CUBIC_TO, 0.32f, -0.2f, 0.56f, -0.48f, 0.74f, -0.85f,
+R_CUBIC_TO, 0.18f, -0.38f, 0.27f, -0.84f, 0.27f, -1.37f,
+R_CUBIC_TO, 0, -0.54f, -0.09f, -1, -0.27f, -1.37f,
+R_ARC_TO, 1.96f, 1.96f, 0, 0, 0, -0.74f, -0.85f,
+R_ARC_TO, 2.04f, 2.04f, 0, 0, 0, -1.09f, -0.29f,
+R_CUBIC_TO, -0.42f, 0, -0.79f, 0.1f, -1.11f, 0.29f,
+R_CUBIC_TO, -0.32f, 0.2f, -0.57f, 0.48f, -0.76f, 0.85f,
+R_CUBIC_TO, -0.18f, 0.37f, -0.27f, 0.83f, -0.27f, 1.37f,
+R_CUBIC_TO, 0, 0.54f, 0.09f, 1, 0.27f, 1.37f,
+R_CUBIC_TO, 0.19f, 0.37f, 0.44f, 0.66f, 0.76f, 0.85f,
+R_CUBIC_TO, 0.33f, 0.2f, 0.69f, 0.29f, 1.09f, 0.29f,
+CLOSE,
+R_MOVE_TO, -8.51f, 4.41f,
+R_CUBIC_TO, -0.6f, 0, -1.12f, -0.1f, -1.58f, -0.31f,
+R_ARC_TO, 2.83f, 2.83f, 0, 0, 1, -1.11f, -0.81f,
+R_ARC_TO, 2.75f, 2.75f, 0, 0, 1, -0.56f, -1.15f,
+R_LINE_TO, 1.46f, -0.34f,
+R_CUBIC_TO, 0.11f, 0.36f, 0.32f, 0.66f, 0.62f, 0.9f,
+R_CUBIC_TO, 0.3f, 0.24f, 0.69f, 0.36f, 1.18f, 0.36f,
+R_CUBIC_TO, 0.66f, 0, 1.16f, -0.2f, 1.5f, -0.6f,
+R_CUBIC_TO, 0.34f, -0.4f, 0.5f, -0.96f, 0.5f, -1.67f,
+R_V_LINE_TO, -0.84f,
+R_H_LINE_TO, -0.08f,
+R_ARC_TO, 2.65f, 2.65f, 0, 0, 1, -0.91f, 0.85f,
+R_CUBIC_TO, -0.35f, 0.2f, -0.81f, 0.29f, -1.37f, 0.29f,
+R_CUBIC_TO, -0.56f, 0, -1.08f, -0.14f, -1.55f, -0.43f,
+R_CUBIC_TO, -0.47f, -0.3f, -0.84f, -0.73f, -1.13f, -1.29f,
+R_CUBIC_TO, -0.29f, -0.56f, -0.43f, -1.24f, -0.43f, -2.04f,
+R_CUBIC_TO, 0, -0.8f, 0.14f, -1.48f, 0.43f, -2.04f,
+R_CUBIC_TO, 0.29f, -0.56f, 0.67f, -0.98f, 1.15f, -1.27f,
+ARC_TO, 2.96f, 2.96f, 0, 0, 1, 5.34f, 6,
+R_CUBIC_TO, 0.51f, 0, 0.96f, 0.1f, 1.34f, 0.29f,
+R_CUBIC_TO, 0.38f, 0.2f, 0.68f, 0.47f, 0.9f, 0.81f,
+R_H_LINE_TO, 0.08f,
+R_V_LINE_TO, -0.88f,
+R_H_LINE_TO, 1.43f,
+R_V_LINE_TO, 6.97f,
+R_CUBIC_TO, 0, 0.78f, -0.14f, 1.45f, -0.42f, 1.99f,
+R_CUBIC_TO, -0.28f, 0.55f, -0.68f, 0.96f, -1.19f, 1.23f,
+R_CUBIC_TO, -0.51f, 0.28f, -1.12f, 0.42f, -1.82f, 0.42f,
+CLOSE,
+R_MOVE_TO, 0.01f, -4.68f,
+R_CUBIC_TO, 0.36f, 0, 0.7f, -0.09f, 0.99f, -0.27f,
+R_CUBIC_TO, 0.3f, -0.18f, 0.54f, -0.44f, 0.71f, -0.8f,
+R_CUBIC_TO, 0.19f, -0.35f, 0.28f, -0.8f, 0.28f, -1.33f,
+R_CUBIC_TO, 0, -0.53f, -0.09f, -0.97f, -0.28f, -1.33f,
+R_ARC_TO, 1.87f, 1.87f, 0, 0, 0, -0.71f, -0.8f,
+R_ARC_TO, 1.91f, 1.91f, 0, 0, 0, -0.99f, -0.27f,
+R_CUBIC_TO, -0.36f, 0, -0.7f, 0.09f, -1.01f, 0.27f,
+R_ARC_TO, 1.96f, 1.96f, 0, 0, 0, -0.73f, 0.8f,
+R_CUBIC_TO, -0.18f, 0.36f, -0.27f, 0.8f, -0.27f, 1.33f,
+R_CUBIC_TO, 0, 0.53f, 0.09f, 0.98f, 0.27f, 1.33f,
+R_CUBIC_TO, 0.19f, 0.36f, 0.43f, 0.62f, 0.73f, 0.8f,
+R_CUBIC_TO, 0.31f, 0.18f, 0.64f, 0.27f, 1.01f, 0.27f,
+CLOSE
+
diff --git a/ash/shelf/home_button.cc b/ash/shelf/home_button.cc
index 17d0b2fb..33a05de 100644
--- a/ash/shelf/home_button.cc
+++ b/ash/shelf/home_button.cc
@@ -14,9 +14,11 @@
 #include "ash/app_list/quick_app_access_model.h"
 #include "ash/ash_element_identifiers.h"
 #include "ash/constants/ash_features.h"
+#include "ash/constants/ash_switches.h"
 #include "ash/public/cpp/ash_typography.h"
 #include "ash/public/cpp/shelf_config.h"
 #include "ash/public/cpp/shelf_types.h"
+#include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_control_button.h"
 #include "ash/shelf/shelf_focus_cycler.h"
@@ -31,6 +33,7 @@
 #include "base/check_op.h"
 #include "base/i18n/rtl.h"
 #include "base/memory/raw_ptr.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
 #include "base/time/time.h"
@@ -127,6 +130,7 @@
     SetPaintToLayer();
     layer()->SetFillsBoundsOpaquely(false);
     UpdateBackground();
+    UpdateIconImageModel();
   }
 
   ButtonImageView(const ButtonImageView&) = delete;
@@ -138,6 +142,12 @@
   void OnPaint(gfx::Canvas* canvas) override {
     views::View::OnPaint(canvas);
 
+    if (!image_.isNull()) {
+      canvas->DrawImageInt(image_, (width() - image_.width()) / 2,
+                           (height() - image_.height()) / 2, cc::PaintFlags());
+      return;
+    }
+
     gfx::PointF circle_center(gfx::Rect(size()).CenterPoint());
 
     const bool is_assistant_available =
@@ -185,6 +195,9 @@
     if (!chromeos::features::IsJellyEnabled()) {
       UpdateBackground();
     }
+    if (image_model_) {
+      image_ = image_model_->Rasterize(GetColorProvider());
+    }
     SchedulePaint();
   }
 
@@ -194,6 +207,7 @@
         ShelfConfig::Get()->GetShelfControlButtonBlurRadius());
     layer()->SetBackdropFilterQuality(ColorProvider::kBackgroundBlurQuality);
     UpdateBackground();
+    UpdateIconImageModel();
   }
 
   void SetToggled(bool toggled) {
@@ -203,6 +217,7 @@
 
     toggled_ = toggled;
     UpdateBackground();
+    UpdateIconImageModel();
     SchedulePaint();
   }
 
@@ -259,8 +274,42 @@
                     : cros_tokens::kCrosSysSystemOnBase;
   }
 
+  void UpdateIconImageModel() {
+    const std::string campbell_config = base::GetFieldTrialParamValueByFeature(
+        features::kCampbellGlyph, "icon");
+
+    if (campbell_config.empty() || !switches::IsCampbellSecretKeyMatched()) {
+      image_model_ = std::nullopt;
+      image_ = gfx::ImageSkia();
+      return;
+    }
+
+    if (campbell_config == "hero") {
+      image_model_ =
+          ui::ImageModel::FromVectorIcon(kCampbellHeroIcon, GetIconColorId());
+    } else if (campbell_config == "action") {
+      image_model_ =
+          ui::ImageModel::FromVectorIcon(kCampbellActionIcon, GetIconColorId());
+    } else if (campbell_config == "text") {
+      image_model_ =
+          ui::ImageModel::FromVectorIcon(kCampbellTextIcon, GetIconColorId());
+    } else if (campbell_config == "9dot") {
+      image_model_ =
+          ui::ImageModel::FromVectorIcon(kCampbell9dotIcon, GetIconColorId());
+    }
+
+    if (image_model_ && GetColorProvider()) {
+      image_ = image_model_->Rasterize(GetColorProvider());
+    } else {
+      image_ = gfx::ImageSkia();
+    }
+  }
+
   const raw_ptr<HomeButtonController> button_controller_;
 
+  gfx::ImageSkia image_;
+  std::optional<ui::ImageModel> image_model_;
+
   bool toggled_ = false;
 };
 
diff --git a/ash/style/system_textfield.cc b/ash/style/system_textfield.cc
index 8eb048a..e20bddc 100644
--- a/ash/style/system_textfield.cc
+++ b/ash/style/system_textfield.cc
@@ -351,6 +351,10 @@
   render_text->set_selection_background_focused_color(
       color_provider->GetColor(selection_background_color_id_.value_or(
           cros_tokens::kCrosSysHighlightText)));
+
+  // Set placeholder text color
+  set_placeholder_text_color(color_provider->GetColor(
+      placeholder_text_color_id_.value_or(cros_tokens::kCrosSysDisabled)));
 }
 
 BEGIN_METADATA(SystemTextfield, views::Textfield)
diff --git a/ash/system/focus_mode/focus_mode_chip_carousel_unittest.cc b/ash/system/focus_mode/focus_mode_chip_carousel_unittest.cc
index 471b99f..d48644f 100644
--- a/ash/system/focus_mode/focus_mode_chip_carousel_unittest.cc
+++ b/ash/system/focus_mode/focus_mode_chip_carousel_unittest.cc
@@ -56,8 +56,9 @@
 
   std::unique_ptr<api::Task> MakeTask(const std::string& title) {
     return std::make_unique<api::Task>(
-        /*id=*/base::NumberToString(task_id_++), title, /*completed=*/false,
-        /*due=*/absl::nullopt, /*has_subtasks=*/false, /*has_email_link=*/false,
+        /*id=*/base::NumberToString(task_id_++), title,
+        /*due=*/absl::nullopt, /*completed=*/false, /*has_subtasks=*/false,
+        /*has_email_link=*/false,
         /*has_notes=*/false, /*updated=*/base::Time::Now());
   }
 
diff --git a/ash/system/focus_mode/focus_mode_controller_unittest.cc b/ash/system/focus_mode/focus_mode_controller_unittest.cc
index a3c6e3a..537a1dd 100644
--- a/ash/system/focus_mode/focus_mode_controller_unittest.cc
+++ b/ash/system/focus_mode/focus_mode_controller_unittest.cc
@@ -187,8 +187,8 @@
   const std::string title = "Focus Task";
   controller->SetSelectedTask(std::make_unique<api::Task>(
                                   /*id=*/base::NumberToString(id), title,
-                                  /*completed=*/false,
-                                  /*due=*/absl::nullopt, /*has_subtasks=*/false,
+                                  /*due=*/absl::nullopt, /*completed=*/false,
+                                  /*has_subtasks=*/false,
                                   /*has_email_link=*/false,
                                   /*has_notes=*/false,
                                   /*updated=*/base::Time::Now())
diff --git a/ash/system/focus_mode/focus_mode_detailed_view_unittest.cc b/ash/system/focus_mode/focus_mode_detailed_view_unittest.cc
index dddf800..c7b26f2d8 100644
--- a/ash/system/focus_mode/focus_mode_detailed_view_unittest.cc
+++ b/ash/system/focus_mode/focus_mode_detailed_view_unittest.cc
@@ -802,8 +802,8 @@
   const std::string title = "Focus Task";
   controller->SetSelectedTask(std::make_unique<api::Task>(
                                   /*id=*/base::NumberToString(id), title,
-                                  /*completed=*/false,
-                                  /*due=*/absl::nullopt, /*has_subtasks=*/false,
+                                  /*due=*/absl::nullopt, /*completed=*/false,
+                                  /*has_subtasks=*/false,
                                   /*has_email_link=*/false,
                                   /*has_notes=*/false,
                                   /*updated=*/base::Time::Now())
diff --git a/ash/system/focus_mode/focus_mode_tasks_provider.cc b/ash/system/focus_mode/focus_mode_tasks_provider.cc
index d510ab5..806eff7 100644
--- a/ash/system/focus_mode/focus_mode_tasks_provider.cc
+++ b/ash/system/focus_mode/focus_mode_tasks_provider.cc
@@ -86,10 +86,11 @@
 
   base::Time due_date;
   return std::make_unique<api::Task>(
-      task_data.id, task_data.title, task_data.completed,
+      task_data.id, task_data.title,
       base::Time::FromString(task_data.due_string, &due_date)
           ? std::make_optional<base::Time>(due_date)
           : std::nullopt,
+      task_data.completed,
       /*has_subtasks=*/false,
       /*has_email_link=*/false,
       /*has_notes=*/false, update_date);
@@ -120,8 +121,8 @@
                                      OnTaskSavedCallback callback) {
   std::unique_ptr<api::Task> task = std::make_unique<api::Task>(
       /*id=*/base::NumberToString(task_id_++), title,
-      /*completed=*/false,
-      /*due=*/absl::nullopt, /*has_subtasks=*/false, /*has_email_link=*/false,
+      /*due=*/absl::nullopt, /*completed=*/false, /*has_subtasks=*/false,
+      /*has_email_link=*/false,
       /*has_notes=*/false, /*updated=*/base::Time::Now());
 
   api::Task* task_ptr = task.get();
diff --git a/ash/system/focus_mode/focus_mode_tray_unittest.cc b/ash/system/focus_mode/focus_mode_tray_unittest.cc
index 9156868..737c9dd 100644
--- a/ash/system/focus_mode/focus_mode_tray_unittest.cc
+++ b/ash/system/focus_mode/focus_mode_tray_unittest.cc
@@ -186,14 +186,14 @@
       ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
 
   FocusModeController* controller = FocusModeController::Get();
-  controller->SetSelectedTask(std::make_unique<api::Task>(
-                                  /*id=*/base::NumberToString(0),
-                                  "make a travel plan", /*completed=*/false,
-                                  /*due=*/absl::nullopt, /*has_subtasks=*/false,
-                                  /*has_email_link=*/false,
-                                  /*has_notes=*/false,
-                                  /*updated=*/base::Time::Now())
-                                  .get());
+  controller->SetSelectedTask(
+      std::make_unique<api::Task>(
+          /*id=*/base::NumberToString(0), "make a travel plan",
+          /*due=*/absl::nullopt, /*completed=*/false, /*has_subtasks=*/false,
+          /*has_email_link=*/false,
+          /*has_notes=*/false,
+          /*updated=*/base::Time::Now())
+          .get());
 
   //  Start focus mode and click the tray to activate the button.
   controller->ToggleFocusMode();
@@ -296,8 +296,8 @@
   controller->SetInactiveSessionDuration(session_duration);
   controller->SetSelectedTask(std::make_unique<api::Task>(
                                   /*id=*/base::NumberToString(1), task_name,
-                                  /*completed=*/false,
-                                  /*due=*/absl::nullopt, /*has_subtasks=*/false,
+                                  /*due=*/absl::nullopt, /*completed=*/false,
+                                  /*has_subtasks=*/false,
                                   /*has_email_link=*/false,
                                   /*has_notes=*/false,
                                   /*updated=*/base::Time::Now())
diff --git a/ash/webui/common/backend/plural_string_handler_unittest.cc b/ash/webui/common/backend/plural_string_handler_unittest.cc
index 4ce248b..b15935d 100644
--- a/ash/webui/common/backend/plural_string_handler_unittest.cc
+++ b/ash/webui/common/backend/plural_string_handler_unittest.cc
@@ -25,8 +25,8 @@
 
 class PluralStringHandlerTest : public testing::Test {
  public:
-  PluralStringHandlerTest() : task_environment_(), web_ui_() {
-    plural_string_handler_ = std::make_unique<PluralStringHandler>();
+  PluralStringHandlerTest()
+      : plural_string_handler_(std::make_unique<PluralStringHandler>()) {
     plural_string_handler_->SetWebUIForTest(&web_ui_);
     plural_string_handler_->RegisterMessages();
     // Add edit button label to plural map for testing purposes.
@@ -43,12 +43,11 @@
  protected:
   base::test::TaskEnvironment task_environment_;
   content::TestWebUI web_ui_;
-  std::unique_ptr<PluralStringHandler> plural_string_handler_;
+  const std::unique_ptr<PluralStringHandler> plural_string_handler_;
 };
 
 TEST_F(PluralStringHandlerTest, PluralString) {
-  // base::RunLoop run_loop;
-  const int call_data_count_before_call = web_ui_.call_data().size();
+  const size_t call_data_count_before_call = web_ui_.call_data().size();
   base::Value::List args;
   args.Append(kHandlerFunctionName);
   args.Append("editButtonLabel");
@@ -56,7 +55,7 @@
   web_ui_.HandleReceivedMessage("getPluralString", args);
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ(call_data_count_before_call + 1u, web_ui_.call_data().size());
+  ASSERT_EQ(call_data_count_before_call + 1, web_ui_.call_data().size());
   const content::TestWebUI::CallData& call_data =
       CallDataAtIndex(call_data_count_before_call);
   EXPECT_EQ("cr.webUIResponse", call_data.function_name());
@@ -66,7 +65,7 @@
 }
 
 TEST_F(PluralStringHandlerTest, SingularString) {
-  const int call_data_count_before_call = web_ui_.call_data().size();
+  const size_t call_data_count_before_call = web_ui_.call_data().size();
   base::Value::List args;
   args.Append(kHandlerFunctionName);
   args.Append("editButtonLabel");
@@ -74,7 +73,7 @@
   web_ui_.HandleReceivedMessage("getPluralString", args);
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ(call_data_count_before_call + 1u, web_ui_.call_data().size());
+  ASSERT_EQ(call_data_count_before_call + 1, web_ui_.call_data().size());
   const content::TestWebUI::CallData& call_data =
       CallDataAtIndex(call_data_count_before_call);
   EXPECT_EQ("cr.webUIResponse", call_data.function_name());
diff --git a/ash/webui/common/resources/cr_elements/cr_drawer/cr_drawer.html b/ash/webui/common/resources/cr_elements/cr_drawer/cr_drawer.html
index 244ac75f..a423608 100644
--- a/ash/webui/common/resources/cr_elements/cr_drawer/cr_drawer.html
+++ b/ash/webui/common/resources/cr_elements/cr_drawer/cr_drawer.html
@@ -69,9 +69,14 @@
     border-bottom: var(--cr-separator-line);
     color: var(--cr-drawer-header-color, inherit);
     display: flex;
+
+    /* Declare "font" property before more granular font properties like
+     * "font-weight", etc. to properly compute font styles.
+     */
+    font: var(--cr-drawer-header-font, inherit);
     font-size: 123.08%;  /* go to 16px from 13px */
     font-weight: var(--cr-drawer-header-font-weight, inherit);
-    font: var(--cr-drawer-header-font, inherit);
+
     min-height: 56px;
     padding-inline-start: var(--cr-drawer-header-padding, 24px);
   }
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc
index 72eb294..9bfb323 100644
--- a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc
+++ b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.cc
@@ -51,6 +51,7 @@
 #include "ui/events/keycodes/dom/dom_key.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
 #include "ui/events/keycodes/keyboard_codes_posix.h"
+#include "ui/events/types/event_type.h"
 
 namespace ash {
 
@@ -371,6 +372,35 @@
     return AcceleratorConfigResult::kReservedKeyNotAllowed;
   }
 
+  // Case: A function key accelerator cannot have the meta key modifier.
+  if ((modifiers & ui::EF_COMMAND_DOWN) != 0 &&
+      ui::KeyboardCapability::IsFunctionKey(accelerator.key_code())) {
+    VLOG(1) << "Failed to validate accelerator: "
+            << accelerator.GetShortcutText() << " with error: "
+            << static_cast<int>(AcceleratorConfigResult::kKeyNotAllowed)
+            << ". Accelerator has meta key with Function key.";
+    return AcceleratorConfigResult::kSearchWithFunctionKeyNotAllowed;
+  }
+
+  // Case: Non-standard keys cannot have search as a modifier.
+  absl::optional<AcceleratorKeycodeLookupCache::KeyCodeLookupEntry>
+      key_code_entry = FindKeyCodeEntry(accelerator.key_code());
+  if (key_code_entry.has_value()) {
+    const ui::KeyEvent key_event(
+        ui::ET_KEY_PRESSED, key_code_entry->resulting_key_code,
+        key_code_entry->dom_code, accelerator.modifiers());
+    const AcceleratorKeyInputType input_type =
+        GetKeyInputTypeFromKeyEvent(key_event);
+    if ((input_type == AcceleratorKeyInputType::kMisc ||
+         input_type == AcceleratorKeyInputType::kTopRow) &&
+        (modifiers & ui::EF_COMMAND_DOWN) != 0) {
+      VLOG(1) << "Failed to validate accelerator: "
+              << accelerator.GetShortcutText() << " with error: "
+              << " Cannot have search with non-standard key.";
+      return AcceleratorConfigResult::kNonStandardWithSearch;
+    }
+  }
+
   // Case: Top-row action keys cannot be part of the accelerator.
   std::optional<ui::TopRowActionKey> top_row_action_key =
       ui::KeyboardCapability::ConvertToTopRowActionKey(accelerator.key_code());
@@ -392,16 +422,6 @@
     return AcceleratorConfigResult::kShiftOnlyNotAllowed;
   }
 
-  // Case: A function key accelerator cannot have the meta key modifier.
-  if ((modifiers & ui::EF_COMMAND_DOWN) != 0 &&
-      ui::KeyboardCapability::IsFunctionKey(accelerator.key_code())) {
-    VLOG(1) << "Failed to validate accelerator: "
-            << accelerator.GetShortcutText() << " with error: "
-            << static_cast<int>(AcceleratorConfigResult::kKeyNotAllowed)
-            << ". Accelerator has meta key with Function key.";
-    return AcceleratorConfigResult::kSearchWithFunctionKeyNotAllowed;
-  }
-
   // No errors with the accelerator.
   return std::nullopt;
 }
diff --git a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc
index 572fc00..7a53a3c 100644
--- a/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc
+++ b/ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider_unittest.cc
@@ -1676,6 +1676,26 @@
                           search_function_accelerator, &result);
   EXPECT_EQ(mojom::AcceleratorConfigResult::kSearchWithFunctionKeyNotAllowed,
             result->result);
+
+  // Brightness down key, typically in top-row.
+  const ui::Accelerator brightness_down_accelerator(ui::VKEY_BRIGHTNESS_DOWN,
+                                                    ui::EF_COMMAND_DOWN);
+  ash::shortcut_customization::mojom::
+      AcceleratorConfigurationProviderAsyncWaiter(provider_.get())
+          .AddAccelerator(mojom::AcceleratorSource::kAsh, kToggleMirrorMode,
+                          brightness_down_accelerator, &result);
+  EXPECT_EQ(mojom::AcceleratorConfigResult::kNonStandardWithSearch,
+            result->result);
+
+  // Calculator key, typically not in top-row.
+  const ui::Accelerator mail_accelerator(ui::VKEY_MEDIA_LAUNCH_MAIL,
+                                         ui::EF_COMMAND_DOWN);
+  ash::shortcut_customization::mojom::
+      AcceleratorConfigurationProviderAsyncWaiter(provider_.get())
+          .AddAccelerator(mojom::AcceleratorSource::kAsh, kToggleMirrorMode,
+                          mail_accelerator, &result);
+  EXPECT_EQ(mojom::AcceleratorConfigResult::kNonStandardWithSearch,
+            result->result);
 }
 
 TEST_F(AcceleratorConfigurationProviderTest, AddAcceleratorExceedsMaximum) {
diff --git a/ash/webui/shortcut_customization_ui/resources/js/accelerator_view.ts b/ash/webui/shortcut_customization_ui/resources/js/accelerator_view.ts
index 13b9f078..9dcbd25 100644
--- a/ash/webui/shortcut_customization_ui/resources/js/accelerator_view.ts
+++ b/ash/webui/shortcut_customization_ui/resources/js/accelerator_view.ts
@@ -447,6 +447,15 @@
         this.makeA11yAnnouncement(this.statusMessage);
         return;
       }
+      // TODO(b/286268215): Localize this string.
+      case AcceleratorConfigResult.kNonStandardWithSearch: {
+        this.statusMessage = this.i18n(
+            'nonStandardNotAllowedWithSearchMessage',
+            this.lastPendingKeyEvent!.keyDisplay, this.getMetaKeyDisplay());
+        this.hasError = true;
+        this.makeA11yAnnouncement(this.statusMessage);
+        return;
+      }
       case AcceleratorConfigResult.kSuccess: {
         this.fireEditCompletedActionEvent(this.editAction);
         getShortcutProvider().recordAddOrEditSubactions(
diff --git a/ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.cc b/ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.cc
index f7045a8..9b84fac 100644
--- a/ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.cc
+++ b/ash/webui/shortcut_customization_ui/shortcut_customization_app_ui.cc
@@ -103,6 +103,8 @@
        IDS_SHORTCUT_CUSTOMIZATION_NON_SEARCH_SHORTCUT_WARNING},
       {"reservedKeyNotAllowedStatusMessage",
        IDS_SHORTCUT_CUSTOMIZATION_RESERVED_KEY_NOT_ALLOWED_STATUS_MESSAGE},
+      {"nonStandardNotAllowedWithSearchMessage",
+       IDS_SHORTCUT_CUSTOMIZATION_NON_STANDARD_KEY_WITH_SEARCH_MODIFIER},
       {"searchNoResults", IDS_SHORTCUT_CUSTOMIZATION_SEARCH_NO_RESULTS},
       {"searchClearQueryLabel",
        IDS_SHORTCUT_CUSTOMIZATION_SEARCH_CLEAR_QUERY_LABEL},
diff --git a/ash/wm/desks/desk_button/desk_button.cc b/ash/wm/desks/desk_button/desk_button.cc
index becc7b8..280d439 100644
--- a/ash/wm/desks/desk_button/desk_button.cc
+++ b/ash/wm/desks/desk_button/desk_button.cc
@@ -194,14 +194,6 @@
   UpdateShelfAutoHideDisabler(disable_shelf_auto_hide_hover_, !GetHovered());
 }
 
-views::View* DeskButton::GetTooltipHandlerForPoint(const gfx::Point& point) {
-  // We override this function so that the tooltip manager ignores disabled desk
-  // switch buttons when creating tooltips.
-  views::View* tooltip_handler = Button::GetTooltipHandlerForPoint(point);
-  return tooltip_handler && tooltip_handler->GetEnabled() ? tooltip_handler
-                                                          : this;
-}
-
 void DeskButton::AboutToRequestFocusFromTabTraversal(bool reverse) {
   desk_button_container_->desk_button_widget()->MaybeFocusOut(reverse);
 }
diff --git a/ash/wm/desks/desk_button/desk_button.h b/ash/wm/desks/desk_button/desk_button.h
index fd2829e..9ac1d7f 100644
--- a/ash/wm/desks/desk_button/desk_button.h
+++ b/ash/wm/desks/desk_button/desk_button.h
@@ -51,7 +51,6 @@
   void OnMouseEvent(ui::MouseEvent* event) override;
   void OnGestureEvent(ui::GestureEvent* event) override;
   void StateChanged(ButtonState old_state) override;
-  View* GetTooltipHandlerForPoint(const gfx::Point& point) override;
   void AboutToRequestFocusFromTabTraversal(bool reverse) override;
 
   // Initializes the view. Must be called before any meaningful UIs can be laid
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index f2926620..0fd5b91 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -25,6 +25,7 @@
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_id.h"
 #include "ash/style/icon_button.h"
+#include "ash/style/system_toast_style.h"
 #include "ash/system/toast/toast_manager_impl.h"
 #include "ash/wallpaper/wallpaper_controller_impl.h"
 #include "ash/wm/desks/default_desk_button.h"
@@ -98,6 +99,7 @@
 #include "ui/gfx/geometry/transform_util.h"
 #include "ui/gfx/geometry/vector2d_f.h"
 #include "ui/views/animation/animation_builder.h"
+#include "ui/views/highlight_border.h"
 #include "ui/views/view_utils.h"
 #include "ui/views/widget/widget.h"
 #include "ui/wm/core/coordinate_conversion.h"
@@ -2032,16 +2034,17 @@
   // 2. In faster split screen setup, the `no_windows_widget_` show to indicate
   // either no windows available to pair or select a window to complete the
   // window layout.
-  // TODO(b/307812315): Consider separating the widgets i.e. one
-  // `no_windows_widget_` and one `faster_splitscreen_widget_`.
-  const bool in_faster_split_screen_setup_session =
-      window_util::IsInFasterSplitScreenSetupSession(root_window_);
-  if ((!in_faster_split_screen_setup_session &&
-       (!no_items || IsShowingSavedDeskLibrary())) ||
+  // TODO(b/323199185): Move this to its own function.
+  if (window_util::IsInFasterSplitScreenSetupSession(root_window_)) {
+    UpdateFasterSplitViewWidget();
+    return;
+  }
+
+  if (!no_items || IsShowingSavedDeskLibrary() ||
       overview_session_->enter_exit_overview_type() ==
           OverviewEnterExitType::kPine) {
     no_windows_widget_.reset();
-    settings_widget_.reset();
+    faster_splitview_widget_.reset();
     return;
   }
 
@@ -2053,12 +2056,7 @@
     params.vertical_padding = kNoItemsIndicatorVerticalPaddingDp;
     params.rounding_dp = kNoItemsIndicatorRoundingDp;
     params.preferred_height = kNoItemsIndicatorHeightDp;
-    if (in_faster_split_screen_setup_session) {
-      params.message =
-          no_items ? kFasterSplitScreenToastNoWindows : kFasterSplitScreenToast;
-    } else {
-      params.message = IDS_ASH_OVERVIEW_NO_RECENT_ITEMS;
-    }
+    params.message = IDS_ASH_OVERVIEW_NO_RECENT_ITEMS;
 
     params.parent =
         root_window_->GetChildById(desks_util::GetActiveDeskContainerId());
@@ -2080,10 +2078,6 @@
   }
 
   RefreshNoWindowsWidgetBounds(/*animate=*/false);
-
-  // This must be done after we set the no windows widget bounds.
-  // TODO(b/323199185): Refactor all these UI component updates.
-  UpdateSettingsButton();
 }
 
 void OverviewGrid::RefreshNoWindowsWidgetBounds(bool animate) {
@@ -2092,25 +2086,6 @@
 
   const gfx::Rect grid_bounds(GetGridEffectiveBounds());
   no_windows_widget_->SetBoundsCenteredIn(grid_bounds, animate);
-
-  if (window_util::IsInFasterSplitScreenSetupSession(root_window_)) {
-    // If there are no windows, set it in the center of the grid.
-    if (item_list_.empty()) {
-      return;
-    }
-    // Position the widget under the bottom of the last overview item, but
-    // centered horizontally.
-    const gfx::RectF last_overview_item_bounds =
-        item_list_.back()->target_bounds();
-    const int center_x =
-        no_windows_widget_->GetBoundsCenteredIn(grid_bounds).x();
-    const gfx::Point available_origin(
-        center_x,
-        last_overview_item_bounds.bottom() + kFasterSplitScreenToastSpacingDp);
-    no_windows_widget_->SetBounds(
-        gfx::Rect(available_origin,
-                  no_windows_widget_->GetContentsView()->GetPreferredSize()));
-  }
 }
 
 void OverviewGrid::RefreshGridBounds(bool animate) {
@@ -2447,12 +2422,6 @@
              : nullptr;
 }
 
-const IconButton* OverviewGrid::GetSettingsButtonForTesting() const {
-  return settings_widget_ ? views::AsViewClass<IconButton>(
-                                settings_widget_->GetContentsView())
-                          : nullptr;
-}
-
 void OverviewGrid::MaybeInitDesksWidget() {
   TRACE_EVENT0("ui", "OverviewGrid::MaybeInitDesksWidget");
   if (!desks_util::ShouldDesksBarBeCreated() || desks_widget_)
@@ -2930,47 +2899,86 @@
   OverviewController::Get()->OnPineWidgetShown();
 }
 
+void OverviewGrid::OnSkipButtonPressed() {
+  // Destroys `this`.
+  // TODO(sophiewen): Consider adding another exit point metric.
+  OverviewController::Get()->EndOverview(OverviewEndAction::kKeyEscapeOrBack);
+}
+
 void OverviewGrid::OnSettingsButtonPressed() {
   // Opens the OS Settings page, which causes a window activation change and
   // `EndOverview()` and destroys `this`.
   Shell::Get()->shell_delegate()->OpenMultitaskingSettings();
 }
 
-void OverviewGrid::UpdateSettingsButton() {
+void OverviewGrid::UpdateFasterSplitViewWidget() {
   if (!window_util::IsInFasterSplitScreenSetupSession(root_window_)) {
-    // If we weren't started by partial overview, don't show the settings
-    // button.
+    // If we weren't started by faster splitview, don't show the widget.
+    faster_splitview_widget_.reset();
     return;
   }
 
-  if (!settings_widget_) {
+  if (!faster_splitview_widget_) {
     views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
     params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
     params.parent = desks_util::GetActiveDeskContainerForRoot(root_window_);
-    params.name = "OverviewSettingsWidget";
+    params.name = "FasterSplitViewWidget";
     params.init_properties_container.SetProperty(kHideInDeskMiniViewKey, true);
     params.init_properties_container.SetProperty(kOverviewUiKey, true);
-    settings_widget_ = std::make_unique<views::Widget>(std::move(params));
+    faster_splitview_widget_ =
+        std::make_unique<views::Widget>(std::move(params));
+    auto* box_layout_view = faster_splitview_widget_->SetContentsView(
+        std::make_unique<views::BoxLayoutView>());
+    box_layout_view->SetOrientation(views::BoxLayout::Orientation::kHorizontal);
+    box_layout_view->SetBetweenChildSpacing(kSettingsButtonSpacingDp);
+
+    box_layout_view->AddChildView(std::make_unique<SystemToastStyle>(
+        base::BindRepeating(&OverviewGrid::OnSkipButtonPressed,
+                            weak_ptr_factory_.GetWeakPtr()),
+        l10n_util::GetStringUTF16(IDS_ASH_OVERVIEW_FASTER_SPLITSCREEN_TOAST),
+        l10n_util::GetStringUTF16(
+            IDS_ASH_OVERVIEW_FASTER_SPLITSCREEN_TOAST_SKIP)));
+
     auto* settings_button =
-        settings_widget_->SetContentsView(std::make_unique<IconButton>(
+        box_layout_view->AddChildView(std::make_unique<IconButton>(
             base::BindRepeating(&OverviewGrid::OnSettingsButtonPressed,
                                 weak_ptr_factory_.GetWeakPtr()),
             IconButton::Type::kLarge, &kOverviewSettingsIcon,
             IDS_ASH_OVERVIEW_SETTINGS_BUTTON_LABEL));
+
+    // TODO(b/323199185): Consider refactoring this from `SystemToastStyle`.
+    const int toast_height = settings_button->GetPreferredSize().height();
+    const float toast_corner_radius = toast_height / 2.0f;
+    settings_button->SetBorder(std::make_unique<views::HighlightBorder>(
+        toast_corner_radius,
+        views::HighlightBorder::Type::kHighlightBorderOnShadow));
     settings_button->SetBackgroundColor(kColorAshShieldAndBase80);
+
+    faster_splitview_widget_->Show();
   }
 
-  // Align the settings button with the no windows widget.
-  // TODO(b/323199185): Move the faster splitscreen toast to this widget.
+  // TODO(b/323199185): UX needs to decide where to position this.
+
+  gfx::Rect centered_bounds(GetGridEffectiveBounds());
+  const gfx::Size preferred_size =
+      faster_splitview_widget_->GetContentsView()->GetPreferredSize();
+  centered_bounds.ClampToCenteredSize(preferred_size);
+
+  // If there are no windows, set it in the center of the grid.
+  if (item_list_.empty()) {
+    faster_splitview_widget_->SetBounds(centered_bounds);
+    return;
+  }
+
+  // Position the widget under the bottom of the last overview item, but
+  // centered horizontally.
+  const gfx::RectF last_overview_item_bounds =
+      item_list_.back()->target_bounds();
+  centered_bounds.set_y(last_overview_item_bounds.bottom() +
+                        kFasterSplitScreenToastSpacingDp);
+  faster_splitview_widget_->SetBounds(centered_bounds);
+
   // TODO(b/323409897): Add a11y focus traversal and Chromevox support.
-  CHECK(no_windows_widget_);
-  const gfx::Rect no_windows_widget_bounds(
-      no_windows_widget_->GetWindowBoundsInScreen());
-  settings_widget_->SetBounds(
-      gfx::Rect(no_windows_widget_bounds.right() + kSettingsButtonSpacingDp,
-                no_windows_widget_bounds.y(), no_windows_widget_bounds.height(),
-                no_windows_widget_bounds.height()));
-  settings_widget_->Show();
 }
 
 }  // namespace ash
diff --git a/ash/wm/overview/overview_grid.h b/ash/wm/overview/overview_grid.h
index de81b3b..2244721 100644
--- a/ash/wm/overview/overview_grid.h
+++ b/ash/wm/overview/overview_grid.h
@@ -41,7 +41,6 @@
 
 namespace ash {
 
-class IconButton;
 class LegacyDeskBarView;
 class OverviewDropTarget;
 class OverviewGridEventHandler;
@@ -474,7 +473,9 @@
   const gfx::Rect bounds_for_testing() const { return bounds_; }
   float scroll_offset_for_testing() const { return scroll_offset_; }
   views::Widget* pine_widget_for_testing() const { return pine_widget_.get(); }
-  const IconButton* GetSettingsButtonForTesting() const;
+  views::Widget* faster_splitview_widget_for_testing() {
+    return faster_splitview_widget_.get();
+  }
 
  private:
   friend class DesksTemplatesTest;
@@ -590,12 +591,15 @@
   // instead.
   void CreateAndShowPine(const gfx::ImageSkia& pine_image);
 
-  // Called when the partial overview settings button is pressed.
+  // Called when the faster splitview toast skip button is pressed.
+  void OnSkipButtonPressed();
+
+  // Called when the faster splitview settings button is pressed.
   void OnSettingsButtonPressed();
 
-  // Updates the visibility of `settings_widget_`. The widget will only be shown
-  // if automatic partial overview was started.
-  void UpdateSettingsButton();
+  // Updates the visibility of `faster_splitview_widget_`. The widget will
+  // only be shown if faster splitview setup is in session.
+  void UpdateFasterSplitViewWidget();
 
   // The drop target is created when a window or overview item is being dragged,
   // and is destroyed when the drag ends or overview mode is ended. The drop
@@ -628,8 +632,9 @@
   // The contents view of the above |desks_widget_| if created.
   raw_ptr<LegacyDeskBarView, DanglingUntriaged> desks_bar_view_ = nullptr;
 
-  // Faster splitscreen settings widget.
-  std::unique_ptr<views::Widget> settings_widget_;
+  // Widget that appears during faster splitview setup. Contains the faster
+  // splitview toast and the overview settings button.
+  std::unique_ptr<views::Widget> faster_splitview_widget_;
 
   // True if the overview grid should animate when exiting overview mode. Note
   // even if it's true, it doesn't mean all window items in the grid should
diff --git a/ash/wm/overview/overview_session.cc b/ash/wm/overview/overview_session.cc
index c2bbb54..9dc7767 100644
--- a/ash/wm/overview/overview_session.cc
+++ b/ash/wm/overview/overview_session.cc
@@ -1345,15 +1345,11 @@
 }
 
 void OverviewSession::OnMouseEvent(ui::MouseEvent* event) {
-  for (auto& grid : grid_list_) {
-    if (auto* split_view_overview_session =
-            RootWindowController::ForWindow(grid->root_window())
-                ->split_view_overview_session();
-        split_view_overview_session) {
-      split_view_overview_session->OnMouseEvent(*event);
-      return;
-    }
-  }
+  MaybeDelegateEventToSplitViewOverviewSession(event);
+}
+
+void OverviewSession::OnTouchEvent(ui::TouchEvent* event) {
+  MaybeDelegateEventToSplitViewOverviewSession(event);
 }
 
 void OverviewSession::OnKeyEvent(ui::KeyEvent* event) {
@@ -1694,4 +1690,17 @@
   return size;
 }
 
+void OverviewSession::MaybeDelegateEventToSplitViewOverviewSession(
+    ui::LocatedEvent* event) {
+  for (auto& grid : grid_list_) {
+    if (auto* split_view_overview_session =
+            RootWindowController::ForWindow(grid->root_window())
+                ->split_view_overview_session();
+        split_view_overview_session) {
+      split_view_overview_session->HandleClickOrTap(*event);
+      return;
+    }
+  }
+}
+
 }  // namespace ash
diff --git a/ash/wm/overview/overview_session.h b/ash/wm/overview/overview_session.h
index c891b68..cd9123ce 100644
--- a/ash/wm/overview/overview_session.h
+++ b/ash/wm/overview/overview_session.h
@@ -344,6 +344,7 @@
 
   // ui::EventHandler:
   void OnMouseEvent(ui::MouseEvent* event) override;
+  void OnTouchEvent(ui::TouchEvent* event) override;
   void OnKeyEvent(ui::KeyEvent* event) override;
 
   // ShellObserver:
@@ -449,6 +450,9 @@
 
   size_t GetNumWindows() const;
 
+  // Let `SplitViewOverviewSession` handle the `event` if it is alive.
+  void MaybeDelegateEventToSplitViewOverviewSession(ui::LocatedEvent* event);
+
   // Weak pointer to the overview delegate which will be called when a selection
   // is made.
   raw_ptr<OverviewDelegate, DanglingUntriaged> delegate_;
diff --git a/ash/wm/snap_group/snap_group_unittest.cc b/ash/wm/snap_group/snap_group_unittest.cc
index 2bee80f4..37302be 100644
--- a/ash/wm/snap_group/snap_group_unittest.cc
+++ b/ash/wm/snap_group/snap_group_unittest.cc
@@ -18,6 +18,7 @@
 #include "ash/screen_util.h"
 #include "ash/shell.h"
 #include "ash/style/close_button.h"
+#include "ash/style/system_toast_style.h"
 #include "ash/system/toast/toast_manager_impl.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_util.h"
@@ -68,6 +69,7 @@
 #include "chromeos/ui/base/window_state_type.h"
 #include "chromeos/ui/frame/caption_buttons/snap_controller.h"
 #include "ui/aura/client/aura_constants.h"
+#include "ui/aura/test/test_window_delegate.h"
 #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
 #include "ui/base/hit_test.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
@@ -174,8 +176,9 @@
   EXPECT_TRUE(work_area_bounds().Contains(expected_grid_bounds));
 
   if (!Shell::Get()->IsInTabletMode() && faster_split_screen_setup) {
-    EXPECT_TRUE(
-        GetOverviewGridForRoot(window->GetRootWindow())->no_windows_widget());
+    auto* overview_grid = GetOverviewGridForRoot(window->GetRootWindow());
+    EXPECT_TRUE(overview_grid->faster_splitview_widget_for_testing());
+    EXPECT_FALSE(overview_grid->no_windows_widget());
   }
 
   return split_view_overview_session;
@@ -326,8 +329,9 @@
 
   // Enter overview normally. Test no widget.
   ToggleOverview();
-  EXPECT_FALSE(
-      GetOverviewGridForRoot(w1->GetRootWindow())->no_windows_widget());
+  auto* overview_grid = GetOverviewGridForRoot(w1->GetRootWindow());
+  EXPECT_FALSE(overview_grid->no_windows_widget());
+  EXPECT_FALSE(overview_grid->faster_splitview_widget_for_testing());
 }
 
 TEST_F(FasterSplitScreenTest, CycleSnap) {
@@ -465,9 +469,11 @@
   EXPECT_FALSE(OverviewController::Get()->InOverviewSession());
 }
 
-TEST_F(FasterSplitScreenTest, SkipPairingInOverviewOnMouseEvent) {
-  std::unique_ptr<aura::Window> w1(CreateTestWindow());
-  std::unique_ptr<aura::Window> w2(CreateTestWindow());
+// Tests that when clicking or tapping on the empty area during faster split
+// screen setup session, overview will end.
+TEST_F(FasterSplitScreenTest, SkipPairingInOverviewWhenActivatingTheEmptyArea) {
+  std::unique_ptr<aura::Window> w1(CreateAppWindow());
+  std::unique_ptr<aura::Window> w2(CreateAppWindow());
 
   SnapOneTestWindow(w1.get(), chromeos::WindowStateType::kPrimarySnapped);
   VerifySplitViewOverviewSession(w1.get());
@@ -484,25 +490,68 @@
   auto* event_generator = GetEventGenerator();
   event_generator->MoveMouseTo(outside_point);
   event_generator->ClickLeftButton();
-  OverviewController* overview_controller = OverviewController::Get();
-  EXPECT_FALSE(overview_controller->InOverviewSession());
+  EXPECT_FALSE(IsInOverviewSession());
   EXPECT_EQ(WindowState::Get(w1.get())->GetStateType(),
             chromeos::WindowStateType::kPrimarySnapped);
 
-  // Snap `w1`. Test that clicking on `w1` again exits overview.
+  // Verify that tapping on an empty area in overview will exit the paring.
+  MaximizeToClearTheSession(w1.get());
   SnapOneTestWindow(w1.get(), chromeos::WindowStateType::kPrimarySnapped);
   VerifySplitViewOverviewSession(w1.get());
-
-  // Moving the mouse around won't end overview.
-  event_generator->MoveMouseTo(w1->GetBoundsInScreen().CenterPoint());
-  EXPECT_TRUE(overview_controller->InOverviewSession());
-
-  // Clicking on `w1` again exits overview.
-  event_generator->ClickLeftButton();
-  EXPECT_FALSE(overview_controller->InOverviewSession());
+  event_generator->MoveTouch(outside_point);
+  event_generator->PressTouch();
+  event_generator->ReleaseTouch();
+  EXPECT_FALSE(IsInOverviewSession());
+  EXPECT_EQ(WindowState::Get(w1.get())->GetStateType(),
+            chromeos::WindowStateType::kPrimarySnapped);
 }
 
-TEST_F(FasterSplitScreenTest, SkipPairingInOverviewOnKeyEvent) {
+// Tests that when clicking or tapping on the snapped window on the `HTCLIENT`
+// or `HTCAPTION` area during faster split screen setup session, overview will
+// end.
+TEST_F(FasterSplitScreenTest, SkipPairingWhenActivatingTheSnappedWindow) {
+  UpdateDisplay("800x600");
+  std::unique_ptr<aura::Window> w1(CreateAppWindow());
+  std::unique_ptr<aura::Window> w2(CreateAppWindow());
+  aura::test::TestWindowDelegate delegate;
+
+  auto* event_generator = GetEventGenerator();
+
+  // Snap `w1`. Test that moving the mouse around won't end overview
+  SnapOneTestWindow(w1.get(), chromeos::WindowStateType::kPrimarySnapped);
+  VerifySplitViewOverviewSession(w1.get());
+  event_generator->MoveMouseTo(w1->GetBoundsInScreen().CenterPoint());
+  EXPECT_TRUE(IsInOverviewSession());
+  MaximizeToClearTheSession(w1.get());
+
+  // Build test cases to verify that overview will end when clicking or tapping
+  // on the window caption or client area.
+  struct {
+    int window_component;
+    bool is_click_event;
+  } kTestCases[]{
+      {/*window_component*/ HTCLIENT, /*is_click_event=*/true},
+      {/*window_component*/ HTCAPTION, /*is_click_event=*/true},
+      {/*window_component*/ HTCLIENT, /*is_click_event=*/false},
+      {/*window_component*/ HTCAPTION, /*is_click_event=*/false},
+  };
+
+  for (const auto& test_case : kTestCases) {
+    SnapOneTestWindow(w1.get(), chromeos::WindowStateType::kPrimarySnapped);
+    VerifySplitViewOverviewSession(w1.get());
+    delegate.set_window_component(test_case.window_component);
+    if (test_case.is_click_event) {
+      event_generator->ClickLeftButton();
+    } else {
+      event_generator->PressTouch();
+      event_generator->ReleaseTouch();
+    }
+    EXPECT_FALSE(IsInOverviewSession());
+    MaximizeToClearTheSession(w1.get());
+  }
+}
+
+TEST_F(FasterSplitScreenTest, SkipPairingOnKeyEvent) {
   std::unique_ptr<aura::Window> w1(CreateTestWindow());
   std::unique_ptr<aura::Window> w2(CreateTestWindow());
 
@@ -527,6 +576,25 @@
   EXPECT_TRUE(Shell::Get()->window_cycle_controller()->IsCycling());
 }
 
+TEST_F(FasterSplitScreenTest, SkipPairingToast) {
+  std::unique_ptr<aura::Window> w1(CreateAppWindow());
+  std::unique_ptr<aura::Window> w2(CreateAppWindow());
+  SnapOneTestWindow(w1.get(), chromeos::WindowStateType::kPrimarySnapped);
+  VerifySplitViewOverviewSession(w1.get());
+
+  auto* overview_grid = GetOverviewGridForRoot(w1->GetRootWindow());
+  ASSERT_TRUE(overview_grid);
+  auto* faster_splitview_widget =
+      overview_grid->faster_splitview_widget_for_testing();
+  ASSERT_TRUE(faster_splitview_widget);
+  auto* toast_view = views::AsViewClass<SystemToastStyle>(
+      faster_splitview_widget->GetContentsView()->children()[0]);
+  ASSERT_TRUE(toast_view);
+  LeftClickOn(toast_view->dismiss_button());
+
+  EXPECT_FALSE(OverviewController::Get()->InOverviewSession());
+}
+
 TEST_F(FasterSplitScreenTest, DontStartPartialOverviewAfterSkippingPairing) {
   std::unique_ptr<aura::Window> w1(CreateAppWindow());
   std::unique_ptr<aura::Window> w2(CreateAppWindow());
diff --git a/ash/wm/splitview/split_view_overview_session.cc b/ash/wm/splitview/split_view_overview_session.cc
index 94f3dc51..b699a4ea 100644
--- a/ash/wm/splitview/split_view_overview_session.cc
+++ b/ash/wm/splitview/split_view_overview_session.cc
@@ -98,17 +98,16 @@
                    OverviewEnterExitType::kImmediateExit);
 }
 
-void SplitViewOverviewSession::OnMouseEvent(const ui::MouseEvent& event) {
-  aura::Window* target = static_cast<aura::Window*>(event.target());
-  if (event.type() != ui::ET_MOUSE_PRESSED ||
-      window_util::GetNonClientComponent(target, event.location()) !=
-          HTCLIENT) {
-    // Only MOUSE_PRESSED events in the client hit area will end overview.
-    return;
-  }
+void SplitViewOverviewSession::HandleClickOrTap(const ui::LocatedEvent& event) {
   gfx::Point location_in_screen = event.location();
+  aura::Window* target = static_cast<aura::Window*>(event.target());
   wm::ConvertPointToScreen(target, &location_in_screen);
-  if (window_->GetBoundsInScreen().Contains(location_in_screen)) {
+  const int client_component =
+      window_util::GetNonClientComponent(target, event.location());
+  if ((event.type() == ui::ET_MOUSE_PRESSED ||
+       event.type() == ui::ET_TOUCH_RELEASED) &&
+      window_->GetBoundsInScreen().Contains(location_in_screen) &&
+      (client_component == HTCLIENT || client_component == HTCAPTION)) {
     MaybeEndOverview(SplitViewOverviewSessionExitPoint::kSkip,
                      OverviewEnterExitType::kNormal);
   }
diff --git a/ash/wm/splitview/split_view_overview_session.h b/ash/wm/splitview/split_view_overview_session.h
index 86d36a2..cebe8d0 100644
--- a/ash/wm/splitview/split_view_overview_session.h
+++ b/ash/wm/splitview/split_view_overview_session.h
@@ -14,7 +14,10 @@
 #include "base/scoped_observation.h"
 #include "ui/aura/window_observer.h"
 #include "ui/compositor/presentation_time_recorder.h"
-#include "ui/events/event_handler.h"
+
+namespace ui {
+class LocatedEvent;
+}  // namespace ui
 
 namespace ash {
 
@@ -79,7 +82,7 @@
   // Called by `OverviewSession` on a key or mouse event that isn't processed by
   // overview session.
   void OnKeyEvent();
-  void OnMouseEvent(const ui::MouseEvent& event);
+  void HandleClickOrTap(const ui::LocatedEvent& event);
 
   // aura::WindowObserver:
   void OnResizeLoopStarted(aura::Window* window) override;
diff --git a/base/allocator/partition_allocator/src/partition_alloc/page_allocator_internals_posix.cc b/base/allocator/partition_allocator/src/partition_alloc/page_allocator_internals_posix.cc
index 9d66f0c..7053f69 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/page_allocator_internals_posix.cc
+++ b/base/allocator/partition_allocator/src/partition_alloc/page_allocator_internals_posix.cc
@@ -1,13 +1,13 @@
 // Copyright 2021 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+#include <sys/mman.h>
 
+#include "build/build_config.h"
 #include "partition_alloc/page_allocator.h"
 #include "partition_alloc/partition_alloc_base/cpu.h"
 #include "partition_alloc/partition_alloc_base/notreached.h"
 
-#include <sys/mman.h>
-
 // PA_PROT_BTI requests a page that supports BTI landing pads.
 #define PA_PROT_BTI 0x10
 
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/memory/ref_counted.cc b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/memory/ref_counted.cc
index 8bbff1c6..ba9426e 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/memory/ref_counted.cc
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/memory/ref_counted.cc
@@ -8,6 +8,7 @@
 #include <ostream>
 #include <type_traits>
 
+#include "build/build_config.h"
 #include "partition_alloc/partition_alloc_base/debug/debugging_buildflags.h"
 
 namespace partition_alloc::internal::base::subtle {
diff --git a/build_overrides/build.gni b/build_overrides/build.gni
index 16767dc..619e86da 100644
--- a/build_overrides/build.gni
+++ b/build_overrides/build.gni
@@ -40,7 +40,7 @@
   # TODO(crbug/1006541): Switch to perfetto's client library on all platforms.
   use_perfetto_client_library =
       (is_linux || is_android || (use_blink && is_ios) || is_win ||
-       is_chromeos || is_mac) && !is_castos
+       is_chromeos) && !is_castos
 
   # Limits the defined //third_party/android_deps targets to only "buildCompile"
   # and "buildCompileNoDeps" targets. This is useful for third-party
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorUnitTest.java
index 0c18f2a..3b49d19d 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorUnitTest.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorUnitTest.java
@@ -42,6 +42,7 @@
 import org.chromium.base.supplier.OneshotSupplierImpl;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.HistogramWatcher;
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
@@ -196,6 +197,7 @@
 
     @Test
     @SmallTest
+    @DisabledTest(message = "https://crbug.com/1524084")
     public void testShowTabListEditor() {
         ObservableSupplier<Boolean> handlesBackPressSupplier =
                 mCoordinator.getHandleBackPressChangedSupplier();
@@ -244,6 +246,7 @@
 
     @Test
     @SmallTest
+    @DisabledTest(message = "https://crbug.com/1524084")
     public void testTabGridDialogVisibilitySupplier() {
         Supplier<Boolean> tabGridDialogVisibilitySupplier =
                 mCoordinator.getTabGridDialogVisibilitySupplier();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
index e70a278..c7b2212 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
@@ -3698,7 +3698,8 @@
                             mToolbarContainerView,
                             tabBeingDragged,
                             dragStartPointF,
-                            clickedTab.getDrawX());
+                            clickedTab.getDrawX(),
+                            clickedTab.getWidth());
             if (dragStarted) {
                 mActiveClickedTab = clickedTab;
                 mLastOffsetX = 0.f;
@@ -3763,20 +3764,21 @@
         StripLayoutTab draggedTab = getSelectedStripTab();
         assert draggedTab != null;
 
+        // Store reorder state, then exit reorder mode.
         mLastOffsetX = draggedTab.getOffsetX();
         onUpOrCancel(time);
         finishAnimationsAndPushTabUpdates();
 
-        runTabRemovalAnimation(
-                draggedTab,
-                new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        draggedTab.setIsDraggedOffStrip(true);
-                        draggedTab.setDrawX(draggedTab.getIdealX());
-                        resizeStripOnTabClose();
-                    }
-                });
+        // Immediately hide the dragged tab container, as if it were being translated off like a
+        // closed tab.
+        draggedTab.setIsDraggedOffStrip(true);
+        draggedTab.setDrawX(draggedTab.getIdealX());
+        draggedTab.setDrawY(mHeight);
+        draggedTab.setOffsetY(mHeight);
+        mMultiStepTabCloseAnimRunning = true;
+
+        // Resize the tab strip accordingly.
+        resizeStripOnTabClose();
     }
 
     void sendMoveWindowBroadcast(View view, float startXInView, float startYInView) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripTabDragShadowView.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripTabDragShadowView.java
index 016ed2c..8cae533 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripTabDragShadowView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripTabDragShadowView.java
@@ -4,10 +4,14 @@
 
 package org.chromium.chrome.browser.compositor.overlays.strip;
 
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.util.AttributeSet;
+import android.util.FloatProperty;
 import android.util.Size;
 import android.view.View;
 import android.view.ViewGroup;
@@ -32,11 +36,26 @@
 import org.chromium.chrome.browser.tasks.tab_management.TabThumbnailView;
 import org.chromium.chrome.browser.tasks.tab_management.TabUiThemeProvider;
 import org.chromium.chrome.browser.tasks.tab_management.TabUiThemeUtil;
+import org.chromium.ui.interpolators.Interpolators;
 import org.chromium.url.GURL;
 
 public class StripTabDragShadowView extends FrameLayout {
+    private static final FloatProperty<StripTabDragShadowView> PROGRESS =
+            new FloatProperty<>("progress") {
+                @Override
+                public void setValue(StripTabDragShadowView object, float v) {
+                    object.setProgress(v);
+                }
+
+                @Override
+                public Float get(StripTabDragShadowView object) {
+                    return object.getProgress();
+                }
+            };
+
     // Constants
     @VisibleForTesting protected static final int WIDTH_DP = 264;
+    private static final long ANIM_EXPAND_MS = 200L;
 
     // Children Views
     private View mCardView;
@@ -46,7 +65,12 @@
 
     // Internal State
     private Boolean mIncognito;
+    private int mTabWidthPx;
+    private int mTabHeightPx;
     private int mWidthPx;
+    private int mHeightPx;
+    private float mProgress;
+    private Animator mRunningAnimator;
 
     // External Dependencies
     private BrowserControlsStateProvider mBrowserControlStateProvider;
@@ -68,7 +92,11 @@
     public StripTabDragShadowView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        mWidthPx = (int) (context.getResources().getDisplayMetrics().density * WIDTH_DP);
+        Resources resources = context.getResources();
+        mWidthPx = (int) (resources.getDisplayMetrics().density * WIDTH_DP);
+        mTabHeightPx =
+                resources.getDimensionPixelSize(R.dimen.tab_grid_card_header_height)
+                        + (2 * resources.getDimensionPixelSize(R.dimen.tab_grid_card_margin));
     }
 
     @Override
@@ -127,10 +155,12 @@
      * Set state on tab drag start.
      *
      * @param tab The {@link Tab} being dragged.
+     * @param tabWidthPx Width of the source strip tab container in px.
      */
-    public void setTab(Tab tab) {
+    public void prepareForDrag(Tab tab, int tabWidthPx) {
         mTab = tab;
         mTab.addObserver(mFaviconUpdateTabObserver);
+        mTabWidthPx = tabWidthPx;
 
         update();
     }
@@ -141,22 +171,33 @@
         mTab = null;
     }
 
+    /** Run the expand animation. */
+    public void expand() {
+        if (mRunningAnimator != null && mRunningAnimator.isRunning()) mRunningAnimator.end();
+
+        setProgress(0.f);
+        mRunningAnimator = ObjectAnimator.ofFloat(this, PROGRESS, 1.f);
+        mRunningAnimator.setInterpolator(Interpolators.EMPHASIZED);
+        mRunningAnimator.setDuration(ANIM_EXPAND_MS);
+        mRunningAnimator.start();
+    }
+
     private void update() {
         // TODO(https://crbug.com/1499119): Unify the shared code for creating the GTS-style card.
         // Set to final size. Even though the size will be animated, we need to initially set to the
         // final size, so that we allocate the appropriate amount of space when
         // #onProvideShadowMetrics is called on drag start.
-        int heightPx =
+        mHeightPx =
                 TabUtils.deriveGridCardHeight(mWidthPx, getContext(), mBrowserControlStateProvider);
 
         ViewGroup.LayoutParams layoutParams = getLayoutParams();
         layoutParams.width = mWidthPx;
-        layoutParams.height = heightPx;
+        layoutParams.height = mHeightPx;
         setLayoutParams(layoutParams);
-        this.layout(0, 0, mWidthPx, heightPx);
+        this.layout(0, 0, mWidthPx, mHeightPx);
 
         // Request the thumbnail.
-        Size cardSize = new Size(mWidthPx, heightPx);
+        Size cardSize = new Size(mWidthPx, mHeightPx);
         Size thumbnailSize = TabUtils.deriveThumbnailSize(cardSize, getContext());
         mTabContentManagerSupplier
                 .get()
@@ -227,7 +268,31 @@
         }
     }
 
+    private void setProgress(float progress) {
+        assert progress >= 0.f && progress <= 1.f : "Invalid animation progress value.";
+        mProgress = progress;
+
+        ViewGroup.LayoutParams layoutParams = getLayoutParams();
+        layoutParams.width = (int) lerp(mTabWidthPx, mWidthPx, progress);
+        layoutParams.height = (int) lerp(mTabHeightPx, mHeightPx, progress);
+        setLayoutParams(layoutParams);
+        post(() -> mShadowUpdateHost.requestUpdate());
+    }
+
+    private float getProgress() {
+        return mProgress;
+    }
+
+    /** Linear interpolate from start value to stop value by amount [0..1] */
+    private float lerp(float start, float stop, float amount) {
+        return start + ((stop - start) * amount);
+    }
+
     protected Tab getTabForTesting() {
         return mTab;
     }
+
+    protected Animator getRunningAnimatorForTesting() {
+        return mRunningAnimator;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java
index f6116ef8..3d1ddf7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSource.java
@@ -63,6 +63,7 @@
  */
 public class TabDragSource implements View.OnDragListener {
     private static final String TAG = "TabDragSource";
+
     private final WindowAndroid mWindowAndroid;
     private MultiInstanceManager mMultiInstanceManager;
     private DragAndDropDelegate mDragAndDropDelegate;
@@ -149,13 +150,15 @@
      * @param startPoint Position of the drag start point in view coordinates.
      * @param tabPositionX Horizontal position of the dragged tab in view coordinates. Used to
      *     calculate the relative position of the touch point in the tab strip.
+     * @param tabWidthDp Width of the source strip tab container in dp.
      * @return true if the drag action was initiated successfully.
      */
     public boolean startTabDragAction(
             @NonNull View dragSourceView,
             @NonNull Tab tabBeingDragged,
             @NonNull PointF startPoint,
-            float tabPositionX) {
+            float tabPositionX,
+            float tabWidthDp) {
         // Return false when FF is disabled or another drag in progress.
         if (!TabUiFeatureUtilities.isTabDragEnabled() || DragDropGlobalState.hasValue()) {
             return false;
@@ -182,7 +185,7 @@
         // Build shared state with all info.
         ChromeDropDataAndroid dropData =
                 new ChromeDropDataAndroid.Builder().withTab(tabBeingDragged).build();
-        updateShadowView(tabBeingDragged, dragSourceView);
+        updateShadowView(tabBeingDragged, dragSourceView, (int) (tabWidthDp / mPxToDp));
         DragShadowBuilder builder =
                 createDragShadowBuilder(dragSourceView, startPoint, tabPositionX);
         sDragTrackerToken =
@@ -206,7 +209,8 @@
     }
 
     @VisibleForTesting
-    void updateShadowView(@NonNull Tab tabBeingDragged, @NonNull View dragSourceView) {
+    void updateShadowView(
+            @NonNull Tab tabBeingDragged, @NonNull View dragSourceView, int tabWidthPx) {
         // Shadow view is unused for drag as window.
         if (TabUiFeatureUtilities.isTabDragAsWindowEnabled()) return;
         if (mShadowView == null) {
@@ -231,7 +235,7 @@
                         }
                     });
         }
-        mShadowView.setTab(tabBeingDragged);
+        mShadowView.prepareForDrag(tabBeingDragged, tabWidthPx);
     }
 
     @Override
@@ -454,8 +458,16 @@
         if (!isDragSource()) {
             mUmaState.mTabLeavingDestStripSystemElapsedTime = SystemClock.elapsedRealtime();
         }
-        // Show drag shadow when drag exits strip.
-        showDragShadow(true);
+        if (TabUiFeatureUtilities.isTabDragAsWindowEnabled()) {
+            showDragShadow(true);
+        } else if (isDragSource()) {
+            TabDragShadowBuilder builder =
+                    (TabDragShadowBuilder) DragDropGlobalState.getDragShadowBuilder();
+            if (builder != null) {
+                builder.mShowDragShadow = true;
+                mShadowView.expand();
+            }
+        }
         mStripLayoutHelperSupplier
                 .get()
                 .clearForTabDrop(LayoutManagerImpl.time(), isDragSource(), isDraggedTabIncognito());
@@ -543,7 +555,6 @@
         }
 
         public void update(boolean show) {
-            if (show == mShowDragShadow) return;
             mShowDragShadow = show;
             mDragSourceView.updateDragShadow(this);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
index 7fae822..0207d88 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -430,7 +430,7 @@
                     public void run() {
                         SigninCheckerProvider.get(Profile.getLastUsedRegularProfile())
                                 .onMainActivityStart();
-                        RevenueStats.getInstance();
+                        RevenueStats.getInstance().retrieveAndApplyTrackingIds();
                     }
                 });
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/rlz/RevenueStats.java b/chrome/android/java/src/org/chromium/chrome/browser/rlz/RevenueStats.java
index 83c20e4d4..bc15e211 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/rlz/RevenueStats.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/rlz/RevenueStats.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.rlz;
 
+import androidx.annotation.VisibleForTesting;
+
 import org.jni_zero.JNINamespace;
 import org.jni_zero.NativeMethods;
 
@@ -16,7 +18,6 @@
 /** Utility class for managing revenue sharing information. */
 @JNINamespace("chrome::android")
 public class RevenueStats {
-
     private static RevenueStats sInstance;
 
     /** Returns the singleton instance of ExternalAuthUtils, creating it if needed. */
@@ -32,6 +33,9 @@
     /** Notifies tab creation event. */
     public void tabCreated(Tab tab) {}
 
+    /** Read and apply RLZ and ClientID values. */
+    public void retrieveAndApplyTrackingIds() {}
+
     /** Returns whether the RLZ provider has been notified that the first search has occurred. */
     protected static boolean getRlzNotified() {
         return ChromeSharedPreferences.getInstance()
@@ -54,9 +58,9 @@
     }
 
     @NativeMethods
-    interface Natives {
+    @VisibleForTesting
+    public interface Natives {
         void setSearchClient(String client);
-
         void setRlzParameterValue(String rlz);
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
index 1b7cd11f..a0db6160 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
@@ -1352,7 +1352,7 @@
         setTabDragSourceMock();
         onLongPress_OnTab();
         // Verify drag invoked
-        verify(mTabDragSource).startTabDragAction(any(), any(), any(), anyFloat());
+        verify(mTabDragSource).startTabDragAction(any(), any(), any(), anyFloat(), anyFloat());
     }
 
     private void onLongPress_OnTab() {
@@ -2604,7 +2604,8 @@
     }
 
     private void setTabDragSourceMock() {
-        when(mTabDragSource.startTabDragAction(any(), any(), any(), anyFloat())).thenReturn(true);
+        when(mTabDragSource.startTabDragAction(any(), any(), any(), anyFloat(), anyFloat()))
+                .thenReturn(true);
         MultiWindowTestUtils.enableMultiInstance();
     }
 
@@ -2631,7 +2632,8 @@
         // Act and verify.
         mStripLayoutHelper.allowMovingTabOutOfStripLayout(theClickedTab, DRAG_START_POINT);
 
-        verify(mTabDragSource, times(1)).startTabDragAction(any(), any(), any(), anyFloat());
+        verify(mTabDragSource, times(1))
+                .startTabDragAction(any(), any(), any(), anyFloat(), anyFloat());
         assertTrue(
                 "Tab being dragged should exist during drag action.",
                 mStripLayoutHelper.getActiveClickedTabForTesting() != null);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripTabDragShadowViewUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripTabDragShadowViewUnitTest.java
index 72d3b1e..738769b 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripTabDragShadowViewUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripTabDragShadowViewUnitTest.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.compositor.overlays.strip;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
@@ -12,6 +13,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.Activity;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.util.Size;
@@ -124,7 +126,7 @@
 
     @Test
     public void testSetTab() {
-        mStripTabDragShadowView.setTab(mMockTab);
+        mStripTabDragShadowView.prepareForDrag(mMockTab, 0);
 
         assertEquals(
                 "Should have set Tab on drag start.",
@@ -135,7 +137,7 @@
 
     @Test
     public void testClear() {
-        mStripTabDragShadowView.setTab(mMockTab);
+        mStripTabDragShadowView.prepareForDrag(mMockTab, 0);
 
         mStripTabDragShadowView.clear();
 
@@ -147,7 +149,7 @@
 
     @Test
     public void testUpdate_LayoutSize() {
-        mStripTabDragShadowView.setTab(mMockTab);
+        mStripTabDragShadowView.prepareForDrag(mMockTab, 0);
 
         int expectedWidth = StripTabDragShadowView.WIDTH_DP;
         int expectedHeight =
@@ -159,8 +161,28 @@
     }
 
     @Test
+    public void testUpdate_LayoutSize_Expand() {
+        mStripTabDragShadowView.prepareForDrag(mMockTab, 0);
+        assertNull(
+                "Should not be animating.", mStripTabDragShadowView.getRunningAnimatorForTesting());
+
+        mStripTabDragShadowView.expand();
+
+        Resources resources = mActivity.getResources();
+        int expectedWidth = 0;
+        int expectedHeight =
+                resources.getDimensionPixelSize(R.dimen.tab_grid_card_header_height)
+                        + (2 * resources.getDimensionPixelSize(R.dimen.tab_grid_card_margin));
+        LayoutParams layoutParams = mStripTabDragShadowView.getLayoutParams();
+        assertEquals("Unexpected view width.", expectedWidth, layoutParams.width);
+        assertEquals("Unexpected view height.", expectedHeight, layoutParams.height);
+        assertNotNull(
+                "Should be animating.", mStripTabDragShadowView.getRunningAnimatorForTesting());
+    }
+
+    @Test
     public void testUpdate_ThumbnailRequestSuccess() {
-        mStripTabDragShadowView.setTab(mMockTab);
+        mStripTabDragShadowView.prepareForDrag(mMockTab, 0);
 
         verify(mMockTabContentManager)
                 .getTabThumbnailWithCallback(
@@ -179,7 +201,7 @@
 
     @Test
     public void testUpdate_ThumbnailRequestFailure() {
-        mStripTabDragShadowView.setTab(mMockTab);
+        mStripTabDragShadowView.prepareForDrag(mMockTab, 0);
         verify(mMockTabContentManager)
                 .getTabThumbnailWithCallback(
                         eq(TAB_ID),
@@ -201,7 +223,7 @@
         when(mMockLayerTitleCache.getOriginalFavicon(any(Tab.class)))
                 .thenReturn(mMockOriginalFaviconBitmap);
 
-        mStripTabDragShadowView.setTab(mMockTab);
+        mStripTabDragShadowView.prepareForDrag(mMockTab, 0);
 
         assertEquals(
                 "Should be using original favicon.",
@@ -214,7 +236,7 @@
         when(mMockLayerTitleCache.getOriginalFavicon(any(Tab.class)))
                 .thenReturn(mMockOriginalFaviconBitmap);
 
-        mStripTabDragShadowView.setTab(mMockTab);
+        mStripTabDragShadowView.prepareForDrag(mMockTab, 0);
         verify(mMockLayerTitleCache)
                 .fetchFaviconWithCallback(eq(mMockTab), mGetFaviconCallbackCaptor.capture());
         mGetFaviconCallbackCaptor
@@ -232,7 +254,7 @@
         boolean incognito = true;
         when(mMockTab.isIncognito()).thenReturn(incognito);
 
-        mStripTabDragShadowView.setTab(mMockTab);
+        mStripTabDragShadowView.prepareForDrag(mMockTab, 0);
 
         @ColorRes
         int expectedBackgroundColor =
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java
index ec80836..be9ffc3 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabDragSourceTest.java
@@ -215,7 +215,11 @@
         // Act and verify.
         boolean res =
                 mSourceInstance.startTabDragAction(
-                        mTabsToolbarView, mTabBeingDragged, DRAG_START_POINT, TAB_POSITION_X);
+                        mTabsToolbarView,
+                        mTabBeingDragged,
+                        DRAG_START_POINT,
+                        TAB_POSITION_X,
+                        TAB_WIDTH);
         assertTrue("startTabDragAction returned false.", res);
         verify(mDragDropDelegate)
                 .startDragAndDrop(
@@ -239,7 +243,11 @@
         // Act and verify.
         boolean res =
                 mSourceInstance.startTabDragAction(
-                        mTabsToolbarView, mTabBeingDragged, DRAG_START_POINT, TAB_POSITION_X);
+                        mTabsToolbarView,
+                        mTabBeingDragged,
+                        DRAG_START_POINT,
+                        TAB_POSITION_X,
+                        TAB_WIDTH);
         assertTrue("startTabDragAction returned false.", res);
         verify(mDragDropDelegate)
                 .startDragAndDrop(
@@ -263,7 +271,11 @@
                 NullPointerException.class,
                 () ->
                         mSourceInstance.startTabDragAction(
-                                mTabsToolbarView, null, DRAG_START_POINT, TAB_POSITION_X));
+                                mTabsToolbarView,
+                                null,
+                                DRAG_START_POINT,
+                                TAB_POSITION_X,
+                                TAB_WIDTH));
     }
 
     @Test
@@ -274,7 +286,11 @@
         assertFalse(
                 "Tab drag should not start",
                 mSourceInstance.startTabDragAction(
-                        mTabsToolbarView, mTabBeingDragged, DRAG_START_POINT, TAB_POSITION_X));
+                        mTabsToolbarView,
+                        mTabBeingDragged,
+                        DRAG_START_POINT,
+                        TAB_POSITION_X,
+                        TAB_WIDTH));
     }
 
     @EnableFeatures({ChromeFeatureList.TAB_DRAG_DROP_ANDROID})
@@ -285,7 +301,11 @@
         assertFalse(
                 "Should not startTabDragAction since last tab with homepage enabled.",
                 mSourceInstance.startTabDragAction(
-                        mTabsToolbarView, mTabBeingDragged, DRAG_START_POINT, TAB_POSITION_X));
+                        mTabsToolbarView,
+                        mTabBeingDragged,
+                        DRAG_START_POINT,
+                        TAB_POSITION_X,
+                        TAB_WIDTH));
     }
 
     @Test
@@ -299,7 +319,11 @@
         assertFalse(
                 "Tab drag should not start",
                 mSourceInstance.startTabDragAction(
-                        mTabsToolbarView, mTabBeingDragged, DRAG_START_POINT, TAB_POSITION_X));
+                        mTabsToolbarView,
+                        mTabBeingDragged,
+                        DRAG_START_POINT,
+                        TAB_POSITION_X,
+                        TAB_WIDTH));
         assertFalse("Global state should not be set", DragDropGlobalState.hasValue());
     }
 
@@ -315,7 +339,11 @@
         assertFalse(
                 "Tab drag should not start",
                 mSourceInstance.startTabDragAction(
-                        mTabsToolbarView, mTabBeingDragged, DRAG_START_POINT, TAB_POSITION_X));
+                        mTabsToolbarView,
+                        mTabBeingDragged,
+                        DRAG_START_POINT,
+                        TAB_POSITION_X,
+                        TAB_WIDTH));
     }
 
     @Test
@@ -334,7 +362,11 @@
         assertTrue(
                 "Tab drag should start",
                 spySource.startTabDragAction(
-                        mTabsToolbarView, mTabBeingDragged, DRAG_START_POINT, TAB_POSITION_X));
+                        mTabsToolbarView,
+                        mTabBeingDragged,
+                        DRAG_START_POINT,
+                        TAB_POSITION_X,
+                        TAB_WIDTH));
     }
 
     @Test
@@ -347,7 +379,7 @@
         final PointF dragStartPoint = new PointF(dragStartXPosition, dragStartYPosition);
         // Call startDrag to set class variables.
         mSourceInstance.startTabDragAction(
-                mTabsToolbarView, mTabBeingDragged, dragStartPoint, TAB_POSITION_X);
+                mTabsToolbarView, mTabBeingDragged, dragStartPoint, TAB_POSITION_X, TAB_WIDTH);
 
         View.DragShadowBuilder tabDragShadowBuilder =
                 mSourceInstance.createDragShadowBuilder(
@@ -375,7 +407,7 @@
     public void test_onProvideShadowMetrics_withTabLinkDragDropFF() {
         // Call startDrag to set class variables.
         mSourceInstance.startTabDragAction(
-                mTabsToolbarView, mTabBeingDragged, DRAG_START_POINT, TAB_POSITION_X);
+                mTabsToolbarView, mTabBeingDragged, DRAG_START_POINT, TAB_POSITION_X, TAB_WIDTH);
         TabDragShadowBuilder tabDragShadowBuilder =
                 (TabDragShadowBuilder) DragDropGlobalState.getDragShadowBuilder();
         Resources resources = ContextUtils.getApplicationContext().getResources();
@@ -786,7 +818,11 @@
 
         // Start tab drag action.
         mSourceInstance.startTabDragAction(
-                mTabsToolbarView, mTabBeingDragged, new PointF(POS_X, mPosY), TAB_POSITION_X);
+                mTabsToolbarView,
+                mTabBeingDragged,
+                new PointF(POS_X, mPosY),
+                TAB_POSITION_X,
+                TAB_WIDTH);
 
         boolean res =
                 mDestInstance.onDrag(
@@ -802,7 +838,11 @@
 
         // Start tab drag action.
         mSourceInstance.startTabDragAction(
-                mTabsToolbarView, mTabBeingDragged, new PointF(POS_X, mPosY), TAB_POSITION_X);
+                mTabsToolbarView,
+                mTabBeingDragged,
+                new PointF(POS_X, mPosY),
+                TAB_POSITION_X,
+                TAB_WIDTH);
 
         boolean res =
                 mDestInstance.onDrag(
@@ -833,7 +873,11 @@
         DragEventInvoker() {
             // Start tab drag action.
             mSourceInstance.startTabDragAction(
-                    mTabsToolbarView, mTabBeingDragged, new PointF(POS_X, mPosY), TAB_POSITION_X);
+                    mTabsToolbarView,
+                    mTabBeingDragged,
+                    new PointF(POS_X, mPosY),
+                    TAB_POSITION_X,
+                    TAB_WIDTH);
             // drag invokes DRAG_START and DRAG_ENTER on source and DRAG_START on destination.
             mSourceInstance.onDrag(
                     mTabsToolbarView, mockDragEvent(DragEvent.ACTION_DRAG_STARTED, POS_X, mPosY));
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index 98bd8bf..e1ba510 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -6573,14 +6573,14 @@
   <message name="IDS_OS_SETTINGS_SYSTEM_PREFERENCES_MENU_ITEM_DESCRIPTION" desc="Description for the System Preferences menu item in the left menu. This static list describes device storage, battery/energy saver, and language settings.">
     Storage, power, language
   </message>
-  <message name="IDS_OS_SETTINGS_SYSTEM_PREFERENCES_MULTITASKING_TITLE" desc="The title of the Multitasking settings card in the System Preferences page." translateable="false">
-    Multitasking
+  <message name="IDS_OS_SETTINGS_SYSTEM_PREFERENCES_MULTITASKING_TITLE" desc="The title of the Multitasking settings card in the System Preferences page.">
+    Windows and desks
   </message>
-  <message name="IDS_OS_SETTINGS_SYSTEM_PREFERENCES_MULTITASKING_SNAP_WINDOW_LABEL" desc="The title of the Multitasking settings card in the System Preferences page." translateable="false">
-    Show window snap suggestions
+  <message name="IDS_OS_SETTINGS_SYSTEM_PREFERENCES_MULTITASKING_SNAP_WINDOW_LABEL" desc="The title of the Multitasking settings card in the System Preferences page.">
+    Show window suggestions when starting split-screen
   </message>
-  <message name="IDS_OS_SETTINGS_SYSTEM_PREFERENCES_MULTITASKING_SNAP_WINDOW_DESCRIPTION" desc="The title of the Multitasking settings card in the System Preferences page." translateable="false">
-    If you snap a window, you'll see window suggestions for the other side
+  <message name="IDS_OS_SETTINGS_SYSTEM_PREFERENCES_MULTITASKING_SNAP_WINDOW_DESCRIPTION" desc="The title of the Multitasking settings card in the System Preferences page.">
+    If you snap a window to one side to use split-screen, you'll see window suggestions for the other side
   </message>
   <message name="IDS_OS_SETTINGS_SYSTEM_PREFERENCES_STORAGE_AND_POWER_TITLE" desc="The title of the Storage and Power settings card in the System Preferences page.">
     Storage and power
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SYSTEM_PREFERENCES_MULTITASKING_SNAP_WINDOW_DESCRIPTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SYSTEM_PREFERENCES_MULTITASKING_SNAP_WINDOW_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..f52a0bdd2
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SYSTEM_PREFERENCES_MULTITASKING_SNAP_WINDOW_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+77bb47f618c7d934add9a71f3f412c3a4935a762
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SYSTEM_PREFERENCES_MULTITASKING_SNAP_WINDOW_LABEL.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SYSTEM_PREFERENCES_MULTITASKING_SNAP_WINDOW_LABEL.png.sha1
new file mode 100644
index 0000000..8dfce7a
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SYSTEM_PREFERENCES_MULTITASKING_SNAP_WINDOW_LABEL.png.sha1
@@ -0,0 +1 @@
+55afd3c86b0df62b2408a5edb45f0bc435ebbd7f
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SYSTEM_PREFERENCES_MULTITASKING_TITLE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SYSTEM_PREFERENCES_MULTITASKING_TITLE.png.sha1
new file mode 100644
index 0000000..adfa98d
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_SYSTEM_PREFERENCES_MULTITASKING_TITLE.png.sha1
@@ -0,0 +1 @@
+06549d41465f8fbd4c7cdff46ead9e66a8368178
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index bab513f3..1cf122a4 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2908,6 +2908,17 @@
     {"with no offer", kEolIncentiveNoOffer, std::size(kEolIncentiveNoOffer),
      nullptr}};
 
+const FeatureEntry::FeatureParam kCampbell9dot[] = {{"icon", "9dot"}};
+const FeatureEntry::FeatureParam kCampbellHero[] = {{"icon", "hero"}};
+const FeatureEntry::FeatureParam kCampbellAction[] = {{"icon", "action"}};
+const FeatureEntry::FeatureParam kCampbellText[] = {{"icon", "text"}};
+
+const FeatureEntry::FeatureVariation kCampbellGlyphVariations[] = {
+    {"9dot", kCampbell9dot, std::size(kCampbell9dot), nullptr},
+    {"hero", kCampbellHero, std::size(kCampbellHero), nullptr},
+    {"action", kCampbellAction, std::size(kCampbellAction), nullptr},
+    {"text", kCampbellText, std::size(kCampbellText), nullptr}};
+
 const FeatureEntry::FeatureParam kCaptureModeEducationShortcutNudge[] = {
     {"CaptureModeEducationParam", "ShortcutNudge"}};
 const FeatureEntry::FeatureParam kCaptureModeEducationShortcutTutorial[] = {
@@ -4137,6 +4148,14 @@
     {"bluetooth-use-llprivacy", flag_descriptions::kBluetoothUseLLPrivacyName,
      flag_descriptions::kBluetoothUseLLPrivacyDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(bluez::features::kLinkLayerPrivacy)},
+    {"campbell-glyph", flag_descriptions::kCampbellGlyphName,
+     flag_descriptions::kCampbellGlyphDescription, kOsCrOS,
+     FEATURE_WITH_PARAMS_VALUE_TYPE(ash::features::kCampbellGlyph,
+                                    kCampbellGlyphVariations,
+                                    "GampbellGlyph")},
+    {"campbell-key", flag_descriptions::kCampbellKeyName,
+     flag_descriptions::kCampbellKeyDescription, kOsCrOS,
+     STRING_VALUE_TYPE(ash::switches::kCampbellKey, "")},
     {"cellular-bypass-esim-installation-connectivity-check",
      flag_descriptions::kCellularBypassESimInstallationConnectivityCheckName,
      flag_descriptions::
@@ -9079,6 +9098,10 @@
      FEATURE_VALUE_TYPE(features::kPrivacyGuidePreloadAndroid)},
 #endif
 
+    {"prerender2", flag_descriptions::kPrerender2Name,
+     flag_descriptions::kPrerender2Description, kOsAll,
+     FEATURE_VALUE_TYPE(blink::features::kPrerender2)},
+
     {"tab-search-fuzzy-search", flag_descriptions::kTabSearchFuzzySearchName,
      flag_descriptions::kTabSearchFuzzySearchDescription, kOsDesktop,
      FEATURE_WITH_PARAMS_VALUE_TYPE(features::kTabSearchFuzzySearch,
@@ -9905,6 +9928,10 @@
      kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kContextMenuPopupForAllScreenSizes)},
 
+    {"data-sharing-android", flag_descriptions::kDataSharingAndroidName,
+     flag_descriptions::kDataSharingAndroidDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kDataSharingAndroid)},
+
     {"tab-group-parity-android", flag_descriptions::kTabGroupParityAndroidName,
      flag_descriptions::kTabGroupParityAndroidDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kTabGroupParityAndroid)},
diff --git a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
index 6876596..24676148 100644
--- a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
+++ b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
@@ -47,19 +47,6 @@
                           base::CompareCase::SENSITIVE);
 }
 
-constexpr char kGotUpdateManifestHistogramName[] =
-    "WebApk.Update.DidGetInstallableData";
-
-// These values are logged to UMA. Entries should not be renumbered and
-// numeric values should never be reused. Please keep in sync with
-// "WebApkUpdateManifestResult" in src/tools/metrics/histograms/enums.xml.
-enum class ManifestResult {
-  kDifferent = 0,
-  kDifferentLegacyId = 1,
-  kFound = 2,
-  kMaxValue = kFound,
-};
-
 }  // anonymous namespace
 
 jlong JNI_WebApkUpdateDataFetcher_Initialize(
@@ -177,29 +164,23 @@
     return;
   }
 
-  if (web_manifest_id_.is_empty()) {
-    // Don't have an existing manifest ID, check if either manifest URL or
-    // start URL are the same. If neither of them are the same, we treat the
-    // manifest as one of another WebAPK.
-    if (web_manifest_url_ != *data.manifest_url &&
-        start_url_ != data.manifest->start_url) {
-      UMA_HISTOGRAM_ENUMERATION(kGotUpdateManifestHistogramName,
-                                ManifestResult::kDifferentLegacyId,
-                                ManifestResult::kMaxValue);
-      return;
-    }
-  } else if (web_manifest_id_ != data.manifest->id) {
-    // If the fetched manifest id is different from the current one,
-    // continue observing as the id is the identity for the application. We
-    // will treat the manifest with different id as the one of another WebAPK.
-    UMA_HISTOGRAM_ENUMERATION(kGotUpdateManifestHistogramName,
-                              ManifestResult::kDifferent,
-                              ManifestResult::kMaxValue);
+  CHECK(!data.manifest->id.is_empty());
+
+  // If there isn't an existing manifest ID, check if either manifest URL or
+  // start URL are the same. If neither of them are the same, we treat the
+  // manifest as one of another WebAPK.
+  if (web_manifest_id_.is_empty() && web_manifest_url_ != *data.manifest_url &&
+      start_url_ != data.manifest->start_url) {
     return;
   }
 
-  UMA_HISTOGRAM_ENUMERATION(kGotUpdateManifestHistogramName,
-                            ManifestResult::kFound, ManifestResult::kMaxValue);
+  // If there is an existing manifest ID, but the fetched manifest id is
+  // different from the current one, continue observing as the id is the
+  // identity for the application. We will treat the manifest with different id
+  // as the one of another WebAPK.
+  if (!web_manifest_id_.is_empty() && web_manifest_id_ != data.manifest->id) {
+    return;
+  }
 
   info_.UpdateFromManifest(*data.manifest);
   info_.manifest_url = *data.manifest_url;
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index b196459..d08c0de2 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -1529,8 +1529,8 @@
     "input_method/editor_switch.h",
     "input_method/editor_system_actuator.cc",
     "input_method/editor_system_actuator.h",
-    "input_method/editor_text_inserter.cc",
-    "input_method/editor_text_inserter.h",
+    "input_method/editor_text_insertion.cc",
+    "input_method/editor_text_insertion.h",
     "input_method/editor_text_query_provider.cc",
     "input_method/editor_text_query_provider.h",
     "input_method/editor_text_query_provider_for_testing.cc",
@@ -1594,8 +1594,10 @@
     "input_method/text_field_contextual_info_fetcher.h",
     "input_method/text_utils.cc",
     "input_method/text_utils.h",
-    "input_method/ui/assistive_accessibility_view.cc",
-    "input_method/ui/assistive_accessibility_view.h",
+    "input_method/ui/announcement_label.cc",
+    "input_method/ui/announcement_label.h",
+    "input_method/ui/announcement_view.cc",
+    "input_method/ui/announcement_view.h",
     "input_method/ui/assistive_delegate.h",
     "input_method/ui/border_factory.cc",
     "input_method/ui/border_factory.h",
@@ -1620,8 +1622,6 @@
     "input_method/ui/input_method_menu_item.h",
     "input_method/ui/input_method_menu_manager.cc",
     "input_method/ui/input_method_menu_manager.h",
-    "input_method/ui/suggestion_accessibility_label.cc",
-    "input_method/ui/suggestion_accessibility_label.h",
     "input_method/ui/suggestion_details.h",
     "input_method/ui/suggestion_window_view.cc",
     "input_method/ui/suggestion_window_view.h",
@@ -5609,7 +5609,7 @@
     "input_method/suggestions_collector_unittest.cc",
     "input_method/suggestions_service_client_unittest.cc",
     "input_method/text_utils_unittest.cc",
-    "input_method/ui/assistive_accessibility_view_unittest.cc",
+    "input_method/ui/announcement_view_unittest.cc",
     "input_method/ui/candidate_view_unittest.cc",
     "input_method/ui/candidate_window_view_unittest.cc",
     "input_method/ui/completion_suggestion_label_view_unittest.cc",
diff --git a/chrome/browser/ash/extensions/accessibility_features_apitest.cc b/chrome/browser/ash/extensions/accessibility_features_apitest.cc
index c082e64..b26f5926 100644
--- a/chrome/browser/ash/extensions/accessibility_features_apitest.cc
+++ b/chrome/browser/ash/extensions/accessibility_features_apitest.cc
@@ -10,6 +10,7 @@
 #include "ash/constants/ash_pref_names.h"
 #include "base/json/json_writer.h"
 #include "base/values.h"
+#include "chrome/browser/ash/accessibility/api_test_config.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/test/browser_test.h"
@@ -37,16 +38,38 @@
 // permission.
 const char kTestExtensionPathReadPermission[] =
     "accessibility_features/read_permission/";
+
+// A test extension path. The extension has only |accessibilityFeatures.read|
+// permission and has manifest v3.
+const char kTestExtensionPathReadPermissionV3[] =
+    "accessibility_features/mv3/read_permission/";
+
 // A test extension path. The extension has only |accessibilityFeatures.modify|
 // permission.
 const char kTestExtensionPathModifyPermission[] =
     "accessibility_features/modify_permission/";
 
+// A test extension path. The extension has only |accessibilityFeatures.modify|
+// permission and has manifest v3.
+const char kTestExtensionPathModifyPermissionV3[] =
+    "accessibility_features/mv3/modify_permission/";
+
+using ManifestVersion = ash::ManifestVersion;
+
+enum class Permission { kWriteOnly, kReadOnly };
+
+// A class used to define the parameters of a test case.
+struct TestConfig {
+  Permission permission;
+  ManifestVersion version;
+};
+
 // Accessibility features API test.
-// Tests are parameterized by whether the test extension is write-only (the
-// parameter value is true) or read-only (the parameter value is false).
-class AccessibilityFeaturesApiTest : public ExtensionApiTest,
-                                     public testing::WithParamInterface<bool> {
+// Tests are parameterized by the permission (write-only or read-only), as well
+// as the manifest version (v2 or v3).
+class AccessibilityFeaturesApiTest
+    : public ExtensionApiTest,
+      public testing::WithParamInterface<TestConfig> {
  public:
   AccessibilityFeaturesApiTest() {}
   virtual ~AccessibilityFeaturesApiTest() {}
@@ -59,14 +82,31 @@
   // Returns the path of the extension that should be used in a parameterized
   // test.
   const char* GetTestExtensionPath() const {
-    if (GetParam())
+    Permission permission = GetParam().permission;
+    ManifestVersion version = GetParam().version;
+    if (version == ManifestVersion::kTwo &&
+        permission == Permission::kWriteOnly) {
       return kTestExtensionPathModifyPermission;
-    return kTestExtensionPathReadPermission;
+    } else if (version == ManifestVersion::kTwo &&
+               permission == Permission::kReadOnly) {
+      return kTestExtensionPathReadPermission;
+    } else if (version == ManifestVersion::kThree &&
+               permission == Permission::kWriteOnly) {
+      return kTestExtensionPathModifyPermissionV3;
+    } else if (version == ManifestVersion::kThree &&
+               permission == Permission::kReadOnly) {
+      return kTestExtensionPathReadPermissionV3;
+    }
+
+    NOTREACHED();
+    return "";
   }
 
   // Whether a parameterized test should have been able to modify accessibility
   // preferences (i.e. whether the test extension had modify permission).
-  bool ShouldModifyingFeatureSucceed() const { return GetParam(); }
+  bool ShouldModifyingFeatureSucceed() const {
+    return GetParam().permission == Permission::kWriteOnly;
+  }
 
   // Returns preference path for accessibility features as defined by the API.
   const char* GetPrefForFeature(const std::string& feature) {
@@ -180,9 +220,15 @@
   }
 };
 
-INSTANTIATE_TEST_SUITE_P(AccessibilityFeaturesApiTestInstantiatePermission,
+INSTANTIATE_TEST_SUITE_P(AccessibilityFeaturesApiTestWritePermission,
                          AccessibilityFeaturesApiTest,
-                         testing::Bool());
+                         ::testing::Values(TestConfig{Permission::kWriteOnly,
+                                                      ManifestVersion::kTwo}));
+
+INSTANTIATE_TEST_SUITE_P(AccessibilityFeaturesApiTestReadPermission,
+                         AccessibilityFeaturesApiTest,
+                         ::testing::Values(TestConfig{Permission::kReadOnly,
+                                                      ManifestVersion::kTwo}));
 
 // Tests that an extension with read permission can read accessibility features
 // state, while an extension that doesn't have the permission cannot.
@@ -324,7 +370,7 @@
 
 // Tests that an extension with read permission is notified when accessibility
 // features change.
-IN_PROC_BROWSER_TEST_F(AccessibilityFeaturesApiTest, ObserveFeatures) {
+IN_PROC_BROWSER_TEST_P(AccessibilityFeaturesApiTest, ObserveFeatures) {
   // WARNING: Make sure that features which load Chrome extension are not among
   // enabled_features (see |Set| test for the reason).
   std::vector<std::string> enabled_features = {
diff --git a/chrome/browser/ash/file_suggest/drive_recent_file_suggestion_provider.cc b/chrome/browser/ash/file_suggest/drive_recent_file_suggestion_provider.cc
index cb54b3c..d877ec0 100644
--- a/chrome/browser/ash/file_suggest/drive_recent_file_suggestion_provider.cc
+++ b/chrome/browser/ash/file_suggest/drive_recent_file_suggestion_provider.cc
@@ -13,6 +13,7 @@
 #include "base/files/file_path.h"
 #include "base/functional/callback.h"
 #include "base/i18n/time_formatting.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/ranges/algorithm.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
@@ -30,6 +31,8 @@
 
 constexpr base::TimeDelta kMaxLastModifiedOrViewedTime = base::Days(8);
 
+constexpr char kBaseHistogramName[] = "Ash.Search.FileSuggestions.DriveRecents";
+
 drivefs::mojom::QueryParametersPtr CreateRecentlyModifiedQuery() {
   auto query = drivefs::mojom::QueryParameters::New();
   query->modified_time = base::Time::Now() - kMaxLastModifiedOrViewedTime;
@@ -96,7 +99,7 @@
       primary_timestamp, secondary_timestamp, /*new_score=*/std::nullopt);
 }
 
-FileSuggestData CreateFileSuggestion(
+std::optional<FileSuggestData> CreateFileSuggestion(
     const base::FilePath& path,
     const drivefs::mojom::FileMetadata& file_metadata) {
   const base::Time& modified_time = file_metadata.modification_time;
@@ -107,6 +110,11 @@
   if (const absl::optional<base::Time>& shared_time =
           file_metadata.shared_with_me_time;
       shared_time && !shared_time->is_null() && viewed_time.is_null()) {
+    if ((base::Time::Now() - *shared_time).magnitude() >
+        kMaxLastModifiedOrViewedTime) {
+      return std::nullopt;
+    }
+
     return CreateFileSuggestionWithJustification(
         path, app_list::JustificationType::kShared, *shared_time,
         features::IsShowSharingUserInLauncherContinueSectionEnabled()
@@ -121,6 +129,11 @@
         /*user_info=*/nullptr);
   }
 
+  base::UmaHistogramBoolean(
+      base::JoinString({kBaseHistogramName, "ModifyingUserMetadataPresent"},
+                       "."),
+      !!file_metadata.last_modifying_user);
+
   // Last modification was by the user.
   if (file_metadata.modified_by_me_time &&
       !file_metadata.modified_by_me_time->is_null() &&
@@ -171,16 +184,35 @@
     return;
   }
 
+  search_start_time_ = base::Time::Now();
+
   base::RepeatingClosure search_callback = base::BarrierClosure(
       3, base::BindOnce(
              &DriveRecentFileSuggestionProvider::OnRecentFilesSearchesCompleted,
              weak_factory_.GetWeakPtr()));
-  PerformSearch(CreateRecentlyModifiedQuery(), drive_service, search_callback);
-  PerformSearch(CreateRecentlyViewedQuery(), drive_service, search_callback);
-  PerformSearch(CreateSharedWithMeQuery(), drive_service, search_callback);
+  PerformSearch(SearchType::kLastModified, CreateRecentlyModifiedQuery(),
+                drive_service, search_callback);
+  PerformSearch(SearchType::kLastViewed, CreateRecentlyViewedQuery(),
+                drive_service, search_callback);
+  PerformSearch(SearchType::kSharedWithUser, CreateSharedWithMeQuery(),
+                drive_service, search_callback);
+}
+
+// static
+std::string DriveRecentFileSuggestionProvider::GetHistogramSuffix(
+    SearchType search_type) {
+  switch (search_type) {
+    case SearchType::kLastViewed:
+      return "Viewed";
+    case SearchType::kLastModified:
+      return "Modified";
+    case SearchType::kSharedWithUser:
+      return "Shared";
+  }
 }
 
 void DriveRecentFileSuggestionProvider::PerformSearch(
+    SearchType search_type,
     drivefs::mojom::QueryParametersPtr query,
     drive::DriveIntegrationService* drive_service,
     base::RepeatingClosure callback) {
@@ -189,7 +221,7 @@
       mojo::WrapCallbackWithDefaultInvokeIfNotRun(
           base::BindOnce(
               &DriveRecentFileSuggestionProvider::OnSearchRequestComplete,
-              weak_factory_.GetWeakPtr(), std::move(callback)),
+              weak_factory_.GetWeakPtr(), search_type, std::move(callback)),
           drive::FileError::FILE_ERROR_ABORT, /*items=*/std::nullopt));
 }
 
@@ -197,14 +229,40 @@
     base::PassKey<FileSuggestKeyedService>) {}
 
 void DriveRecentFileSuggestionProvider::OnSearchRequestComplete(
+    SearchType search_type,
     base::RepeatingClosure callback,
     drive::FileError error,
     std::optional<std::vector<drivefs::mojom::QueryItemPtr>> items) {
+  // `error` is an enum, but has negative values, so UmaEnumeration does not
+  // work - record it as a count instead.
+  base::UmaHistogramCounts100(
+      base::JoinString(
+          {kBaseHistogramName, "QueryResult", GetHistogramSuffix(search_type)},
+          "."),
+      std::abs(error));
+
   if (error == drive::FileError::FILE_ERROR_OK && items) {
+    base::UmaHistogramTimes(
+        base::JoinString({kBaseHistogramName, "DurationOnSuccess",
+                          GetHistogramSuffix(search_type)},
+                         "."),
+        base::Time::Now() - search_start_time_);
+    base::UmaHistogramCounts100(
+        base::JoinString(
+            {kBaseHistogramName, "ItemCount", GetHistogramSuffix(search_type)},
+            "."),
+        items->size());
+
     for (auto& item : *items) {
       query_result_files_by_path_.emplace(item->path,
                                           std::move(item->metadata));
     }
+  } else {
+    base::UmaHistogramTimes(
+        base::JoinString({kBaseHistogramName, "DurationOnError",
+                          GetHistogramSuffix(search_type)},
+                         "."),
+        base::Time::Now() - search_start_time_);
   }
   callback.Run();
 }
@@ -227,7 +285,11 @@
       continue;
     }
 
-    results.push_back(CreateFileSuggestion(path, *item.second));
+    std::optional<FileSuggestData> suggestion =
+        CreateFileSuggestion(path, *item.second);
+    if (suggestion) {
+      results.push_back(*suggestion);
+    }
   }
 
   query_result_files_by_path_.clear();
@@ -240,6 +302,24 @@
     return lhs.timestamp.value_or(base::Time()) >
            rhs.timestamp.value_or(base::Time());
   });
+
+  base::UmaHistogramTimes(
+      base::JoinString({kBaseHistogramName, "DurationOnSuccess.Total"}, "."),
+      base::Time::Now() - search_start_time_);
+  base::UmaHistogramCounts100(
+      base::JoinString({kBaseHistogramName, "ItemCount.Total"}, "."),
+      results.size());
+
+  for (size_t i = 0; i < results.size(); ++i) {
+    if (!results[i].timestamp) {
+      base::UmaHistogramCounts100(
+          base::JoinString({kBaseHistogramName, "FirstSharedSuggestionIndex"},
+                           "."),
+          i);
+      break;
+    }
+  }
+
   on_drive_results_ready_callback_list_.Notify(results);
 }
 
diff --git a/chrome/browser/ash/file_suggest/drive_recent_file_suggestion_provider.h b/chrome/browser/ash/file_suggest/drive_recent_file_suggestion_provider.h
index adb907d..9b2a986 100644
--- a/chrome/browser/ash/file_suggest/drive_recent_file_suggestion_provider.h
+++ b/chrome/browser/ash/file_suggest/drive_recent_file_suggestion_provider.h
@@ -40,10 +40,21 @@
       base::PassKey<FileSuggestKeyedService>) override;
 
  private:
+  enum class SearchType {
+    kLastViewed,
+    kLastModified,
+    kSharedWithUser,
+  };
+
+  // Returns a suffix to be used in histogram names when reporting UMA about a
+  // search request.
+  static std::string GetHistogramSuffix(SearchType search_type);
+
   // Runs Drive FS search using the provided query parameters.
   // `callback` gets run when the search completes. The search results are added
   // to `pending_results_`.
-  void PerformSearch(drivefs::mojom::QueryParametersPtr query,
+  void PerformSearch(SearchType search_type,
+                     drivefs::mojom::QueryParametersPtr query,
                      drive::DriveIntegrationService* drive_service,
                      base::RepeatingClosure callback);
 
@@ -55,6 +66,7 @@
   // Callback for a single Drive FS search query. Saves the returned results in
   // `pending_results_`, and runs `callback`.
   void OnSearchRequestComplete(
+      SearchType search_type,
       base::RepeatingClosure callback,
       drive::FileError error,
       std::optional<std::vector<drivefs::mojom::QueryItemPtr>> items);
@@ -71,6 +83,9 @@
   std::map<base::FilePath, drivefs::mojom::FileMetadataPtr>
       query_result_files_by_path_;
 
+  // Timestamp for when search requests were issued. Used to collect UMA.
+  base::Time search_start_time_;
+
   // Used to guard the calling to get drive suggestion results.
   base::WeakPtrFactory<DriveRecentFileSuggestionProvider> weak_factory_{this};
 };
diff --git a/chrome/browser/ash/fileapi/diversion_backend_delegate.cc b/chrome/browser/ash/fileapi/diversion_backend_delegate.cc
index 1704feb93..88ca95a 100644
--- a/chrome/browser/ash/fileapi/diversion_backend_delegate.cc
+++ b/chrome/browser/ash/fileapi/diversion_backend_delegate.cc
@@ -495,7 +495,7 @@
         }
       };
 
-  static constexpr auto on_ensure_file_exists =
+  static constexpr auto on_truncated =
       [](base::WeakPtr<DiversionBackendDelegate> weak_ptr,
          OnDiversionFinishedCallSite call_site,
          std::unique_ptr<storage::FileSystemOperationContext> context,
@@ -503,7 +503,7 @@
          const storage::FileSystemURL& dest_url,
          storage::AsyncFileUtil::StatusCallback callback,
          DiversionFileManager::StoppedReason stopped_reason, int64_t file_size,
-         base::File::Error result, bool created) {
+         base::File::Error result) {
         if (result != base::File::FILE_OK) {
           if (callback) {
             std::move(callback).Run(result);
@@ -542,6 +542,48 @@
                            std::move(callback), stopped_reason, file_size));
       };
 
+  static constexpr auto on_ensure_file_exists =
+      [](base::WeakPtr<DiversionBackendDelegate> weak_ptr,
+         OnDiversionFinishedCallSite call_site,
+         std::unique_ptr<storage::FileSystemOperationContext> context,
+         base::ScopedFD scoped_fd, const storage::FileSystemURL& src_url,
+         const storage::FileSystemURL& dest_url,
+         storage::AsyncFileUtil::StatusCallback callback,
+         DiversionFileManager::StoppedReason stopped_reason, int64_t file_size,
+         base::File::Error result, bool created) {
+        if (result != base::File::FILE_OK) {
+          if (callback) {
+            std::move(callback).Run(result);
+          }
+          return;
+        } else if (!weak_ptr) {
+          if (callback) {
+            std::move(callback).Run(base::File::FILE_ERROR_FAILED);
+          }
+          return;
+        } else if (created) {
+          on_truncated(std::move(weak_ptr), call_site, std::move(context),
+                       std::move(scoped_fd), src_url, dest_url,
+                       std::move(callback), stopped_reason, file_size,
+                       base::File::FILE_OK);
+          return;
+        }
+
+        std::unique_ptr<storage::FileSystemOperationContext> fsoc0 =
+            DuplicateFileSystemOperationContext(*context);
+        std::unique_ptr<storage::FileSystemOperationContext> fsoc1 =
+            std::move(context);
+
+        FileSystemBackendDelegate* wrappee = weak_ptr->wrappee_.get();
+        wrappee->GetAsyncFileUtil(dest_url.type())
+            ->Truncate(
+                std::move(fsoc0), dest_url, 0,
+                base::BindOnce(on_truncated, std::move(weak_ptr), call_site,
+                               std::move(fsoc1), std::move(scoped_fd), src_url,
+                               dest_url, std::move(callback), stopped_reason,
+                               file_size));
+      };
+
   std::unique_ptr<storage::FileSystemOperationContext> fsoc0 =
       DuplicateFileSystemOperationContext(*context);
   std::unique_ptr<storage::FileSystemOperationContext> fsoc1 =
diff --git a/chrome/browser/ash/fileapi/diversion_backend_delegate_unittest.cc b/chrome/browser/ash/fileapi/diversion_backend_delegate_unittest.cc
index ab138078..1822c10 100644
--- a/chrome/browser/ash/fileapi/diversion_backend_delegate_unittest.cc
+++ b/chrome/browser/ash/fileapi/diversion_backend_delegate_unittest.cc
@@ -117,16 +117,18 @@
                           base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
 
   // The int returned by GetParam() ranges from 0 to (1 << kNumParamBits).
-  static constexpr int kNumParamBits = 2;
+  static constexpr int kNumParamBits = 3;
   bool ShouldCopy() const { return (1 << 0) & GetParam(); }
-  bool ShouldDivert() const { return (1 << 1) & GetParam(); }
+  bool ShouldDestExists() const { return (1 << 1) & GetParam(); }
+  bool ShouldDivert() const { return (1 << 2) & GetParam(); }
 
   static std::string DescribeParams(
       const testing::TestParamInfo<ParamType>& info) {
     return base::StrCat({
         "Should",
         (((1 << 0) & info.param) ? "CopyAnd" : "MoveAnd"),
-        (((1 << 1) & info.param) ? "Divert" : "NotDivert"),
+        (((1 << 1) & info.param) ? "DestExistsAnd" : "NotDestExistsAnd"),
+        (((1 << 2) & info.param) ? "Divert" : "NotDivert"),
     });
   }
 
@@ -214,6 +216,12 @@
   storage::FileSystemURL fs_url1 = CreateFSURL("diversion.dat");
   ASSERT_EQ(ShouldDivert(), delegate.ShouldDivertForTesting(fs_url0));
 
+  // The final state should be indifferent to whether or not fs_url1 already
+  // exists and, if it does, whether it's longer than expected_contents.
+  if (ShouldDestExists()) {
+    ASSERT_TRUE(base::WriteFile(fs_url1.path(), std::string(100, 'x')));
+  }
+
   // The storage backends are generally happier, when calling
   // CreateFileStreamWriter, if the file already 'exists'. This doesn't
   // necessarily mean existence from the kernel's point of view, just from the
@@ -282,7 +290,7 @@
   // (instead of passing through) that FileSystemURL.
   {
     EXPECT_NE(ShouldDivert(), base::PathExists(fs_url0.path()));
-    EXPECT_FALSE(base::PathExists(fs_url1.path()));
+    EXPECT_EQ(ShouldDestExists(), base::PathExists(fs_url1.path()));
   }
 
   // Copying or moving that fs_url0 file to fs_url1 should materialize it (if
diff --git a/chrome/browser/ash/input_method/assistive_window_controller.cc b/chrome/browser/ash/input_method/assistive_window_controller.cc
index 5ba72a4..c868370 100644
--- a/chrome/browser/ash/input_method/assistive_window_controller.cc
+++ b/chrome/browser/ash/input_method/assistive_window_controller.cc
@@ -42,8 +42,8 @@
 AssistiveWindowController::AssistiveWindowController(
     AssistiveWindowControllerDelegate* delegate,
     Profile* profile,
-    ui::ime::AssistiveAccessibilityView* accessibility_view)
-    : delegate_(delegate), accessibility_view_(accessibility_view) {}
+    ui::ime::AnnouncementView* announcement_view)
+    : delegate_(delegate), announcement_view_(announcement_view) {}
 
 AssistiveWindowController::~AssistiveWindowController() {
   ClearPendingSuggestionTimer();
@@ -53,8 +53,9 @@
     undo_window_->GetWidget()->RemoveObserver(this);
   if (grammar_suggestion_window_ && grammar_suggestion_window_->GetWidget())
     grammar_suggestion_window_->GetWidget()->RemoveObserver(this);
-  if (accessibility_view_ && accessibility_view_->GetWidget())
-    accessibility_view_->GetWidget()->RemoveObserver(this);
+  if (announcement_view_ && announcement_view_->GetWidget()) {
+    announcement_view_->GetWidget()->RemoveObserver(this);
+  }
   CHECK(!IsInObserverList());
 }
 
@@ -92,14 +93,14 @@
   widget->Show();
 }
 
-void AssistiveWindowController::InitAccessibilityView() {
-  if (accessibility_view_)
+void AssistiveWindowController::InitAnnouncementView() {
+  if (announcement_view_) {
     return;
+  }
 
   // accessibility_view_ is deleted by DialogDelegateView::DeleteDelegate.
-  accessibility_view_ =
-      new ui::ime::AssistiveAccessibilityView(GetParentView());
-  accessibility_view_->GetWidget()->AddObserver(this);
+  announcement_view_ = new ui::ime::AnnouncementView(GetParentView());
+  announcement_view_->GetWidget()->AddObserver(this);
 }
 
 void AssistiveWindowController::OnWidgetDestroying(views::Widget* widget) {
@@ -118,17 +119,18 @@
     widget->RemoveObserver(this);
     grammar_suggestion_window_ = nullptr;
   }
-  if (accessibility_view_ && widget == accessibility_view_->GetWidget()) {
+  if (announcement_view_ && widget == announcement_view_->GetWidget()) {
     widget->RemoveObserver(this);
-    accessibility_view_ = nullptr;
+    announcement_view_ = nullptr;
   }
 }
 
 void AssistiveWindowController::Announce(const std::u16string& message) {
-  if (!accessibility_view_)
-    InitAccessibilityView();
+  if (!announcement_view_) {
+    InitAnnouncementView();
+  }
 
-  accessibility_view_->Announce(message);
+  announcement_view_->Announce(message);
 }
 
 // TODO(crbug/1119570): Update AcceptSuggestion signature (either use
diff --git a/chrome/browser/ash/input_method/assistive_window_controller.h b/chrome/browser/ash/input_method/assistive_window_controller.h
index 91bc5fb..5698db5 100644
--- a/chrome/browser/ash/input_method/assistive_window_controller.h
+++ b/chrome/browser/ash/input_method/assistive_window_controller.h
@@ -12,7 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/ash/input_method/assistive_window_properties.h"
-#include "chrome/browser/ash/input_method/ui/assistive_accessibility_view.h"
+#include "chrome/browser/ash/input_method/ui/announcement_view.h"
 #include "chrome/browser/ash/input_method/ui/assistive_delegate.h"
 #include "chrome/browser/ash/input_method/ui/grammar_suggestion_window.h"
 #include "chrome/browser/ash/input_method/ui/suggestion_window_view.h"
@@ -40,7 +40,7 @@
   explicit AssistiveWindowController(
       AssistiveWindowControllerDelegate* delegate,
       Profile* profile,
-      ui::ime::AssistiveAccessibilityView* accessibility_view = nullptr);
+      ui::ime::AnnouncementView* announcement_view = nullptr);
 
   AssistiveWindowController(const AssistiveWindowController&) = delete;
   AssistiveWindowController& operator=(const AssistiveWindowController&) =
@@ -79,7 +79,7 @@
       ui::ime::SuggestionWindowView::Orientation orientation);
   void InitUndoWindow();
   void InitGrammarSuggestionWindow();
-  void InitAccessibilityView();
+  void InitAnnouncementView();
   void DisplayCompletionSuggestion(const ui::ime::SuggestionDetails& details);
   void ClearPendingSuggestionTimer();
 
@@ -89,7 +89,7 @@
   raw_ptr<ui::ime::UndoWindow> undo_window_ = nullptr;
   raw_ptr<ui::ime::GrammarSuggestionWindow> grammar_suggestion_window_ =
       nullptr;
-  raw_ptr<ui::ime::AssistiveAccessibilityView> accessibility_view_ = nullptr;
+  raw_ptr<ui::ime::AnnouncementView> announcement_view_ = nullptr;
   std::u16string suggestion_text_;
   size_t confirmed_length_ = 0;
   Bounds bounds_;
diff --git a/chrome/browser/ash/input_method/assistive_window_controller_unittest.cc b/chrome/browser/ash/input_method/assistive_window_controller_unittest.cc
index 28ca4af3..9c1f0b8 100644
--- a/chrome/browser/ash/input_method/assistive_window_controller_unittest.cc
+++ b/chrome/browser/ash/input_method/assistive_window_controller_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "chrome/browser/ash/input_method/assistive_window_controller_delegate.h"
-#include "chrome/browser/ash/input_method/ui/assistive_accessibility_view.h"
+#include "chrome/browser/ash/input_method/ui/announcement_view.h"
 #include "chrome/browser/ash/input_method/ui/suggestion_details.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/test/base/chrome_ash_test_base.h"
@@ -44,9 +44,9 @@
       const ash::ime::AssistiveWindow& window) const override {}
 };
 
-class TestAccessibilityView : public ui::ime::AssistiveAccessibilityView {
+class TestAnnouncementView : public ui::ime::AnnouncementView {
  public:
-  TestAccessibilityView() = default;
+  TestAnnouncementView() = default;
   void VerifyAnnouncement(const std::u16string& expected_text) {
     EXPECT_EQ(text_, expected_text);
   }
@@ -71,9 +71,9 @@
     wm::ActivateWindow(window.get());
 
     profile_ = std::make_unique<TestingProfile>();
-    accessibility_view_ = std::make_unique<TestAccessibilityView>();
+    announcement_view_ = std::make_unique<TestAnnouncementView>();
     controller_ = std::make_unique<AssistiveWindowController>(
-        delegate_.get(), profile_.get(), accessibility_view_.get());
+        delegate_.get(), profile_.get(), announcement_view_.get());
     IMEBridge::Get()->SetAssistiveWindowHandler(controller_.get());
 
     // TODO(crbug/1102283): Create MockSuggestionWindowView to be independent of
@@ -126,7 +126,7 @@
   const std::u16string suggestion_ = u"test";
   ui::ime::AssistiveWindowButton emoji_button_;
   AssistiveWindowProperties emoji_window_;
-  std::unique_ptr<TestAccessibilityView> accessibility_view_;
+  std::unique_ptr<TestAnnouncementView> announcement_view_;
 };
 
 TEST_F(AssistiveWindowControllerTest, ShowSuggestionDelaysWindowDisplay) {
@@ -433,7 +433,7 @@
   controller_->SetButtonHighlighted(emoji_button_, true);
   task_environment()->RunUntilIdle();
 
-  accessibility_view_->VerifyAnnouncement(kAnnounceString);
+  announcement_view_->VerifyAnnouncement(kAnnounceString);
 }
 
 TEST_F(
@@ -449,7 +449,7 @@
   controller_->SetButtonHighlighted(emoji_button_, true);
   task_environment()->RunUntilIdle();
 
-  accessibility_view_->VerifyAnnouncement(std::u16string());
+  announcement_view_->VerifyAnnouncement(std::u16string());
 }
 
 TEST_F(AssistiveWindowControllerTest,
@@ -467,7 +467,7 @@
   controller_->SetButtonHighlighted(button, true);
   task_environment()->RunUntilIdle();
 
-  accessibility_view_->VerifyAnnouncement(kAnnounceString);
+  announcement_view_->VerifyAnnouncement(kAnnounceString);
 }
 
 TEST_F(
@@ -480,7 +480,7 @@
   controller_->SetButtonHighlighted(emoji_button_, true);
   task_environment()->RunUntilIdle();
 
-  accessibility_view_->VerifyAnnouncement(std::u16string());
+  announcement_view_->VerifyAnnouncement(std::u16string());
 }
 
 }  // namespace input_method
diff --git a/chrome/browser/ash/input_method/editor_mediator.cc b/chrome/browser/ash/input_method/editor_mediator.cc
index 7884437..112bcea 100644
--- a/chrome/browser/ash/input_method/editor_mediator.cc
+++ b/chrome/browser/ash/input_method/editor_mediator.cc
@@ -114,10 +114,6 @@
       panel_manager_.IsEditorMenuVisible()) {
     return;
   }
-
-  if (system_actuator_ != nullptr) {
-    system_actuator_->OnBlur();
-  }
 }
 
 void EditorMediator::OnActivateIme(std::string_view engine_id) {
diff --git a/chrome/browser/ash/input_method/editor_system_actuator.cc b/chrome/browser/ash/input_method/editor_system_actuator.cc
index df1fe85..a72fdbe 100644
--- a/chrome/browser/ash/input_method/editor_system_actuator.cc
+++ b/chrome/browser/ash/input_method/editor_system_actuator.cc
@@ -4,10 +4,13 @@
 
 #include "chrome/browser/ash/input_method/editor_system_actuator.h"
 
+#include <memory>
+
 #include "ash/public/cpp/new_window_delegate.h"
 #include "chrome/browser/ash/input_method/editor_feedback.h"
 #include "chrome/browser/ash/input_method/editor_metrics_enums.h"
 #include "chrome/browser/ash/input_method/editor_metrics_recorder.h"
+#include "chrome/browser/ash/input_method/editor_text_insertion.h"
 #include "url/url_constants.h"
 
 namespace ash::input_method {
@@ -39,7 +42,7 @@
   // The text cannot be immediately inserted as the target input is not focused
   // at this point, the WebUI is focused. After closing the WebUI focus will
   // return to the original text input.
-  inserter_.InsertTextOnNextFocus(text);
+  queued_text_insertion_ = std::make_unique<EditorTextInsertion>(text);
   system_->CloseUI();
 }
 
@@ -76,11 +79,10 @@
 }
 
 void EditorSystemActuator::OnFocus(int context_id) {
-  inserter_.OnFocus(context_id);
-}
-
-void EditorSystemActuator::OnBlur() {
-  inserter_.OnBlur();
+  if (queued_text_insertion_ && (queued_text_insertion_->HasTimedOut() ||
+                                 queued_text_insertion_->Commit())) {
+    queued_text_insertion_ = nullptr;
+  }
 }
 
 }  // namespace ash::input_method
diff --git a/chrome/browser/ash/input_method/editor_system_actuator.h b/chrome/browser/ash/input_method/editor_system_actuator.h
index 439c7bd..7ebfca9 100644
--- a/chrome/browser/ash/input_method/editor_system_actuator.h
+++ b/chrome/browser/ash/input_method/editor_system_actuator.h
@@ -5,11 +5,12 @@
 #ifndef CHROME_BROWSER_ASH_INPUT_METHOD_EDITOR_SYSTEM_ACTUATOR_H_
 #define CHROME_BROWSER_ASH_INPUT_METHOD_EDITOR_SYSTEM_ACTUATOR_H_
 
+#include <memory>
 #include <string>
 
 #include "chrome/browser/ash/input_method/editor_consent_enums.h"
 #include "chrome/browser/ash/input_method/editor_metrics_recorder.h"
-#include "chrome/browser/ash/input_method/editor_text_inserter.h"
+#include "chrome/browser/ash/input_method/editor_text_insertion.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chromeos/ash/services/orca/public/mojom/orca_service.mojom.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
@@ -45,8 +46,8 @@
   void CloseUI() override;
   void SubmitFeedback(const std::string& description) override;
 
+  // Relevant input events
   void OnFocus(int context_id);
-  void OnBlur();
 
  private:
   raw_ptr<Profile> profile_;
@@ -55,7 +56,12 @@
 
   // Not owned by this class.
   raw_ptr<System> system_;
-  EditorTextInserter inserter_;
+
+  // Possibly holds a queued text insertion operation. If a text insertion op
+  // has been queued, then it will be inserted in the next focused text field.
+  // Only one text insertion can be queued at a time, with new text insertions
+  // overwriting previously queued insertions.
+  std::unique_ptr<EditorTextInsertion> queued_text_insertion_;
 };
 
 }  // namespace ash::input_method
diff --git a/chrome/browser/ash/input_method/editor_text_inserter.cc b/chrome/browser/ash/input_method/editor_text_inserter.cc
deleted file mode 100644
index dc602df..0000000
--- a/chrome/browser/ash/input_method/editor_text_inserter.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/input_method/editor_text_inserter.h"
-
-#include "base/strings/utf_string_conversions.h"
-#include "ui/base/ime/ash/ime_bridge.h"
-#include "ui/base/ime/ash/text_input_target.h"
-#include "ui/base/ime/text_input_client.h"
-
-namespace ash {
-namespace input_method {
-namespace {
-
-constexpr base::TimeDelta kInsertionTimeout = base::Seconds(1);
-
-void InsertText(std::string_view text) {
-  TextInputTarget* input = IMEBridge::Get()->GetInputContextHandler();
-  if (!input) {
-    return;
-  }
-  input->CommitText(
-      base::UTF8ToUTF16(text),
-      ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
-}
-
-}  // namespace
-
-EditorTextInserter::EditorTextInserter() = default;
-EditorTextInserter::~EditorTextInserter() = default;
-
-void EditorTextInserter::InsertTextOnNextFocus(std::string_view text) {
-  pending_text_insert_ = PendingTextInsert{std::string(text)};
-
-  // Starts the timer and if the text field is not re-focused after the timer
-  // expires, do not insert the text.
-  text_insertion_timer_.Start(
-      FROM_HERE, kInsertionTimeout,
-      base::BindOnce(&EditorTextInserter::CancelTextInsertion,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void EditorTextInserter::OnFocus(int context_id) {
-  if (focused_client_.has_value() && focused_client_->id == context_id) {
-    return;
-  }
-  focused_client_ = TextClientContext{context_id};
-  if (pending_text_insert_) {
-    InsertText(pending_text_insert_->text);
-    pending_text_insert_ = std::nullopt;
-    text_insertion_timer_.Reset();
-  }
-}
-
-void EditorTextInserter::OnBlur() {
-  focused_client_ = std::nullopt;
-}
-
-void EditorTextInserter::CancelTextInsertion() {
-  pending_text_insert_ = std::nullopt;
-}
-
-}  // namespace input_method
-}  // namespace ash
diff --git a/chrome/browser/ash/input_method/editor_text_inserter.h b/chrome/browser/ash/input_method/editor_text_inserter.h
deleted file mode 100644
index fdd9aad..0000000
--- a/chrome/browser/ash/input_method/editor_text_inserter.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ASH_INPUT_METHOD_EDITOR_TEXT_INSERTER_H_
-#define CHROME_BROWSER_ASH_INPUT_METHOD_EDITOR_TEXT_INSERTER_H_
-
-#include <optional>
-#include <string>
-
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-
-namespace ash {
-namespace input_method {
-
-class EditorTextInserter {
- public:
-  EditorTextInserter();
-  ~EditorTextInserter();
-
-  // Enqueues some text to be inserted in the next text client to be focused.
-  void InsertTextOnNextFocus(std::string_view text);
-
-  // Text input event handlers.
-  void OnFocus(int context_id);
-  void OnBlur();
-
- private:
-  // Holds the details of the currently focused text input's context.
-  struct TextClientContext {
-    int id;
-  };
-
-  // Represents a pending text insertion command.
-  struct PendingTextInsert {
-    std::string text;
-  };
-
-  void CancelTextInsertion();
-
-  // Holds any pending text insertions. It is assumed that only one text
-  // insertion will be requested at any given time.
-  std::optional<PendingTextInsert> pending_text_insert_;
-
-  // Holds the context of a focused text client.
-  std::optional<TextClientContext> focused_client_;
-
-  base::OneShotTimer text_insertion_timer_;
-
-  base::WeakPtrFactory<EditorTextInserter> weak_ptr_factory_{this};
-};
-
-}  // namespace input_method
-}  // namespace ash
-
-#endif  // CHROME_BROWSER_ASH_INPUT_METHOD_EDITOR_TEXT_INSERTER_H_
diff --git a/chrome/browser/ash/input_method/editor_text_insertion.cc b/chrome/browser/ash/input_method/editor_text_insertion.cc
new file mode 100644
index 0000000..be291fe
--- /dev/null
+++ b/chrome/browser/ash/input_method/editor_text_insertion.cc
@@ -0,0 +1,54 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/input_method/editor_text_insertion.h"
+
+#include "base/memory/weak_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "ui/base/ime/ash/ime_bridge.h"
+#include "ui/base/ime/ash/text_input_target.h"
+#include "ui/base/ime/text_input_client.h"
+
+namespace ash {
+namespace input_method {
+namespace {
+
+constexpr base::TimeDelta kInsertionTimeout = base::Seconds(1);
+
+}  // namespace
+
+EditorTextInsertion::EditorTextInsertion(const std::string& text)
+    : pending_text_(text), state_(State::kPending) {
+  text_insertion_timeout_.Start(
+      FROM_HERE, kInsertionTimeout,
+      base::BindOnce(&EditorTextInsertion::CancelTextInsertion,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+EditorTextInsertion::~EditorTextInsertion() = default;
+
+bool EditorTextInsertion::HasTimedOut() {
+  return state_ == State::kTimedOut;
+}
+
+bool EditorTextInsertion::Commit() {
+  TextInputTarget* input = IMEBridge::Get()->GetInputContextHandler();
+  if (HasTimedOut() || !input) {
+    return false;
+  }
+  text_insertion_timeout_.Stop();
+  input->CommitText(
+      base::UTF8ToUTF16(pending_text_),
+      ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
+  return true;
+}
+
+void EditorTextInsertion::CancelTextInsertion() {
+  state_ = State::kTimedOut;
+}
+
+}  // namespace input_method
+}  // namespace ash
diff --git a/chrome/browser/ash/input_method/editor_text_insertion.h b/chrome/browser/ash/input_method/editor_text_insertion.h
new file mode 100644
index 0000000..b59940f
--- /dev/null
+++ b/chrome/browser/ash/input_method/editor_text_insertion.h
@@ -0,0 +1,51 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_INPUT_METHOD_EDITOR_TEXT_INSERTION_H_
+#define CHROME_BROWSER_ASH_INPUT_METHOD_EDITOR_TEXT_INSERTION_H_
+
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+
+namespace ash {
+namespace input_method {
+
+class EditorTextInsertion {
+ public:
+  EditorTextInsertion(const std::string& text);
+  ~EditorTextInsertion();
+
+  // To help ensure that we do not insert the pending text in text fields other
+  // then the target text input, we set a timeout for the text insertion
+  // operation to occur within otherwise it is cancelled. This method returns
+  // the state of that timeout.
+  bool HasTimedOut();
+
+  // Attempts to commit the pending text into the currently focused text input.
+  bool Commit();
+
+ private:
+  enum State {
+    kPending,
+    kTimedOut,
+  };
+
+  // This method is invoked after the text insertion timeout has elapsed, and
+  // it renders this operation inert. Consumers of this class can no longer
+  // commit the pending text once this method has been called.
+  void CancelTextInsertion();
+
+  const std::string pending_text_;
+  State state_;
+  base::OneShotTimer text_insertion_timeout_;
+  base::WeakPtrFactory<EditorTextInsertion> weak_ptr_factory_{this};
+};
+
+}  // namespace input_method
+}  // namespace ash
+
+#endif  // CHROME_BROWSER_ASH_INPUT_METHOD_EDITOR_TEXT_INSERTION_H_
diff --git a/chrome/browser/ash/input_method/ui/suggestion_accessibility_label.cc b/chrome/browser/ash/input_method/ui/announcement_label.cc
similarity index 65%
rename from chrome/browser/ash/input_method/ui/suggestion_accessibility_label.cc
rename to chrome/browser/ash/input_method/ui/announcement_label.cc
index c1ac804a..e4a8752e 100644
--- a/chrome/browser/ash/input_method/ui/suggestion_accessibility_label.cc
+++ b/chrome/browser/ash/input_method/ui/announcement_label.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/input_method/ui/suggestion_accessibility_label.h"
+#include "chrome/browser/ash/input_method/ui/announcement_label.h"
 
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
@@ -12,11 +12,11 @@
 
 constexpr base::TimeDelta kAnnouncementDelayMs = base::Milliseconds(100);
 
-SuggestionAccessibilityLabel::SuggestionAccessibilityLabel() = default;
+AnnouncementLabel::AnnouncementLabel() = default;
 
-SuggestionAccessibilityLabel::~SuggestionAccessibilityLabel() = default;
+AnnouncementLabel::~AnnouncementLabel() = default;
 
-void SuggestionAccessibilityLabel::GetAccessibleNodeData(
+void AnnouncementLabel::GetAccessibleNodeData(
     ui::AXNodeData* node_data) {
   node_data->role = ax::mojom::Role::kImeCandidate;
   node_data->SetName(GetAccessibleName());
@@ -24,23 +24,23 @@
       ax::mojom::StringAttribute::kContainerLiveStatus, "polite");
 }
 
-void SuggestionAccessibilityLabel::Announce(const std::u16string& text) {
+void AnnouncementLabel::Announce(const std::u16string& text) {
   if (text.empty())
     return;
   SetAccessibleName(text);
   delay_timer_ = std::make_unique<base::OneShotTimer>();
   delay_timer_->Start(
       FROM_HERE, kAnnouncementDelayMs,
-      base::BindOnce(&SuggestionAccessibilityLabel::DoAnnouncement,
+      base::BindOnce(&AnnouncementLabel::DoAnnouncement,
                      base::Unretained(this)));
 }
 
-void SuggestionAccessibilityLabel::DoAnnouncement() {
+void AnnouncementLabel::DoAnnouncement() {
   NotifyAccessibilityEvent(ax::mojom::Event::kLiveRegionChanged,
                            /*send_native_event=*/true);
 }
 
-BEGIN_METADATA(SuggestionAccessibilityLabel)
+BEGIN_METADATA(AnnouncementLabel)
 END_METADATA
 
 }  // namespace ime
diff --git a/chrome/browser/ash/input_method/ui/suggestion_accessibility_label.h b/chrome/browser/ash/input_method/ui/announcement_label.h
similarity index 72%
rename from chrome/browser/ash/input_method/ui/suggestion_accessibility_label.h
rename to chrome/browser/ash/input_method/ui/announcement_label.h
index 4d79373..999eef14 100644
--- a/chrome/browser/ash/input_method/ui/suggestion_accessibility_label.h
+++ b/chrome/browser/ash/input_method/ui/announcement_label.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_INPUT_METHOD_UI_SUGGESTION_ACCESSIBILITY_LABEL_H_
-#define CHROME_BROWSER_ASH_INPUT_METHOD_UI_SUGGESTION_ACCESSIBILITY_LABEL_H_
+#ifndef CHROME_BROWSER_ASH_INPUT_METHOD_UI_ANNOUNCEMENT_LABEL_H_
+#define CHROME_BROWSER_ASH_INPUT_METHOD_UI_ANNOUNCEMENT_LABEL_H_
 
 #include <memory>
 #include "base/timer/timer.h"
@@ -15,12 +15,12 @@
 namespace ime {
 
 // Label used for ChromeVox announcements via live regions.
-class SuggestionAccessibilityLabel : public views::Label {
-  METADATA_HEADER(SuggestionAccessibilityLabel, views::Label)
+class AnnouncementLabel : public views::Label {
+  METADATA_HEADER(AnnouncementLabel, views::Label)
 
  public:
-  SuggestionAccessibilityLabel();
-  ~SuggestionAccessibilityLabel() override;
+  AnnouncementLabel();
+  ~AnnouncementLabel() override;
 
   // views::Label overrides
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
@@ -44,4 +44,4 @@
 }  // namespace ime
 }  // namespace ui
 
-#endif  // CHROME_BROWSER_ASH_INPUT_METHOD_UI_SUGGESTION_ACCESSIBILITY_LABEL_H_
+#endif  // CHROME_BROWSER_ASH_INPUT_METHOD_UI_ANNOUNCEMENT_LABEL_H_
diff --git a/chrome/browser/ash/input_method/ui/announcement_view.cc b/chrome/browser/ash/input_method/ui/announcement_view.cc
new file mode 100644
index 0000000..e0713d9d
--- /dev/null
+++ b/chrome/browser/ash/input_method/ui/announcement_view.cc
@@ -0,0 +1,49 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/input_method/ui/announcement_view.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+
+namespace ui {
+namespace ime {
+
+const gfx::Rect kWindowAnchorRect = gfx::Rect(-100000, -100000, 0, 0);
+
+AnnouncementView::AnnouncementView(gfx::NativeView parent) {
+  DialogDelegate::SetButtons(ui::DIALOG_BUTTON_NONE);
+  SetCanActivate(false);
+  DCHECK(parent);
+  set_parent_window(parent);
+  set_margins(gfx::Insets());
+  set_title_margins(gfx::Insets());
+  set_shadow(views::BubbleBorder::NO_SHADOW);
+
+  announcement_label_ =
+      AddChildView(std::make_unique<AnnouncementLabel>());
+  announcement_label_->SetLineHeight(0);
+
+  views::Widget* const widget =
+      BubbleDialogDelegate::CreateBubble(base::WrapUnique(this));
+  // Set the window size to 0 and put it outside screen to make sure users don't
+  // see it.
+  widget->SetSize(gfx::Size(0, 0));
+  SetAnchorRect(kWindowAnchorRect);
+  widget->Show();
+}
+
+AnnouncementView::AnnouncementView() = default;
+AnnouncementView::~AnnouncementView() = default;
+
+void AnnouncementView::Announce(const std::u16string& message) {
+  DCHECK(announcement_label_);
+  if (message.empty())
+    return;
+  announcement_label_->Announce(message);
+}
+
+BEGIN_METADATA(AnnouncementView)
+END_METADATA
+
+}  // namespace ime
+}  // namespace ui
diff --git a/chrome/browser/ash/input_method/ui/announcement_view.h b/chrome/browser/ash/input_method/ui/announcement_view.h
new file mode 100644
index 0000000..5748270f
--- /dev/null
+++ b/chrome/browser/ash/input_method/ui/announcement_view.h
@@ -0,0 +1,49 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_INPUT_METHOD_UI_ANNOUNCEMENT_VIEW_H_
+#define CHROME_BROWSER_ASH_INPUT_METHOD_UI_ANNOUNCEMENT_VIEW_H_
+
+#include "base/memory/raw_ptr.h"
+#include "chrome/browser/ash/input_method/ui/announcement_label.h"
+#include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/chromeos/ui_chromeos_export.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
+#include "ui/views/metadata/view_factory.h"
+
+namespace ui {
+namespace ime {
+
+// This is en empty view box holding an accessibility label, through which we
+// can make ChromeVox announcement incurred by assistive features.
+class UI_CHROMEOS_EXPORT AnnouncementView
+    : public views::BubbleDialogDelegateView {
+  METADATA_HEADER(AnnouncementView, views::BubbleDialogDelegateView)
+
+ public:
+  explicit AnnouncementView(gfx::NativeView parent);
+  AnnouncementView(const AnnouncementView&) = delete;
+  AnnouncementView& operator=(const AnnouncementView&) = delete;
+  ~AnnouncementView() override;
+
+  virtual void Announce(const std::u16string& message);
+
+ protected:
+  AnnouncementView();
+
+ private:
+  raw_ptr<AnnouncementLabel> announcement_label_ = nullptr;
+};
+
+BEGIN_VIEW_BUILDER(UI_CHROMEOS_EXPORT,
+                   AnnouncementView,
+                   views::BubbleDialogDelegateView)
+END_VIEW_BUILDER
+
+}  // namespace ime
+}  // namespace ui
+
+DEFINE_VIEW_BUILDER(UI_CHROMEOS_EXPORT, ui::ime::AnnouncementView)
+
+#endif  // CHROME_BROWSER_ASH_INPUT_METHOD_UI_ANNOUNCEMENT_VIEW_H_
diff --git a/chrome/browser/ash/input_method/ui/assistive_accessibility_view_unittest.cc b/chrome/browser/ash/input_method/ui/announcement_view_unittest.cc
similarity index 62%
rename from chrome/browser/ash/input_method/ui/assistive_accessibility_view_unittest.cc
rename to chrome/browser/ash/input_method/ui/announcement_view_unittest.cc
index 325c711..ae3f2d3 100644
--- a/chrome/browser/ash/input_method/ui/assistive_accessibility_view_unittest.cc
+++ b/chrome/browser/ash/input_method/ui/announcement_view_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/input_method/ui/assistive_accessibility_view.h"
+#include "chrome/browser/ash/input_method/ui/announcement_view.h"
 
 #include "base/memory/raw_ptr.h"
 #include "chrome/test/views/chrome_views_test_base.h"
@@ -15,32 +15,31 @@
 namespace ui {
 namespace ime {
 
-class AssistiveAccessiblityViewTest : public ChromeViewsTestBase {
+class AnnouncementViewTest : public ChromeViewsTestBase {
  public:
-  AssistiveAccessiblityViewTest() {}
-  ~AssistiveAccessiblityViewTest() override {}
+  AnnouncementViewTest() {}
+  ~AnnouncementViewTest() override {}
 
  protected:
   void SetUp() override {
     ChromeViewsTestBase::SetUp();
 
-    assistive_accessibility_view_ =
-        new AssistiveAccessibilityView(GetContext());
+    announcement_view_ = new AnnouncementView(GetContext());
   }
 
   void TearDown() override {
-    assistive_accessibility_view_->GetWidget()->CloseNow();
+    announcement_view_->GetWidget()->CloseNow();
     ChromeViewsTestBase::TearDown();
   }
 
-  raw_ptr<AssistiveAccessibilityView, DanglingUntriaged>
-      assistive_accessibility_view_;
+  raw_ptr<AnnouncementView, DanglingUntriaged>
+      announcement_view_;
 };
 
-TEST_F(AssistiveAccessiblityViewTest, MakesAnnouncement) {
+TEST_F(AnnouncementViewTest, MakesAnnouncement) {
   views::test::AXEventCounter counter(views::AXEventManager::Get());
   EXPECT_EQ(0, counter.GetCount(ax::mojom::Event::kLiveRegionChanged));
-  assistive_accessibility_view_->Announce(u"test");
+  announcement_view_->Announce(u"test");
   task_environment()->FastForwardBy(base::Milliseconds(200));
   EXPECT_EQ(1, counter.GetCount(ax::mojom::Event::kLiveRegionChanged));
 }
diff --git a/chrome/browser/ash/input_method/ui/assistive_accessibility_view.cc b/chrome/browser/ash/input_method/ui/assistive_accessibility_view.cc
deleted file mode 100644
index 11d795f..0000000
--- a/chrome/browser/ash/input_method/ui/assistive_accessibility_view.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/input_method/ui/assistive_accessibility_view.h"
-#include "ui/base/metadata/metadata_impl_macros.h"
-
-namespace ui {
-namespace ime {
-
-const gfx::Rect kWindowAnchorRect = gfx::Rect(-100000, -100000, 0, 0);
-
-AssistiveAccessibilityView::AssistiveAccessibilityView(gfx::NativeView parent) {
-  DialogDelegate::SetButtons(ui::DIALOG_BUTTON_NONE);
-  SetCanActivate(false);
-  DCHECK(parent);
-  set_parent_window(parent);
-  set_margins(gfx::Insets());
-  set_title_margins(gfx::Insets());
-  set_shadow(views::BubbleBorder::NO_SHADOW);
-
-  accessibility_label_ =
-      AddChildView(std::make_unique<SuggestionAccessibilityLabel>());
-  accessibility_label_->SetLineHeight(0);
-
-  views::Widget* const widget =
-      BubbleDialogDelegate::CreateBubble(base::WrapUnique(this));
-  // Set the window size to 0 and put it outside screen to make sure users don't
-  // see it.
-  widget->SetSize(gfx::Size(0, 0));
-  SetAnchorRect(kWindowAnchorRect);
-  widget->Show();
-}
-
-AssistiveAccessibilityView::AssistiveAccessibilityView() = default;
-AssistiveAccessibilityView::~AssistiveAccessibilityView() = default;
-
-void AssistiveAccessibilityView::Announce(const std::u16string& message) {
-  DCHECK(accessibility_label_);
-  if (message.empty())
-    return;
-  accessibility_label_->Announce(message);
-}
-
-BEGIN_METADATA(AssistiveAccessibilityView)
-END_METADATA
-
-}  // namespace ime
-}  // namespace ui
diff --git a/chrome/browser/ash/input_method/ui/assistive_accessibility_view.h b/chrome/browser/ash/input_method/ui/assistive_accessibility_view.h
deleted file mode 100644
index 74dfbca..0000000
--- a/chrome/browser/ash/input_method/ui/assistive_accessibility_view.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ASH_INPUT_METHOD_UI_ASSISTIVE_ACCESSIBILITY_VIEW_H_
-#define CHROME_BROWSER_ASH_INPUT_METHOD_UI_ASSISTIVE_ACCESSIBILITY_VIEW_H_
-
-#include "base/memory/raw_ptr.h"
-#include "chrome/browser/ash/input_method/ui/suggestion_accessibility_label.h"
-#include "ui/base/metadata/metadata_header_macros.h"
-#include "ui/chromeos/ui_chromeos_export.h"
-#include "ui/views/bubble/bubble_dialog_delegate_view.h"
-#include "ui/views/metadata/view_factory.h"
-
-namespace ui {
-namespace ime {
-
-// This is en empty view box holding an accessibility label, through which we
-// can make ChromeVox announcement incurred by assistive features.
-class UI_CHROMEOS_EXPORT AssistiveAccessibilityView
-    : public views::BubbleDialogDelegateView {
-  METADATA_HEADER(AssistiveAccessibilityView, views::BubbleDialogDelegateView)
-
- public:
-  explicit AssistiveAccessibilityView(gfx::NativeView parent);
-  AssistiveAccessibilityView(const AssistiveAccessibilityView&) = delete;
-  AssistiveAccessibilityView& operator=(const AssistiveAccessibilityView&) =
-      delete;
-  ~AssistiveAccessibilityView() override;
-
-  virtual void Announce(const std::u16string& message);
-
- protected:
-  AssistiveAccessibilityView();
-
- private:
-  raw_ptr<SuggestionAccessibilityLabel> accessibility_label_ = nullptr;
-};
-
-BEGIN_VIEW_BUILDER(UI_CHROMEOS_EXPORT,
-                   AssistiveAccessibilityView,
-                   views::BubbleDialogDelegateView)
-END_VIEW_BUILDER
-
-}  // namespace ime
-}  // namespace ui
-
-DEFINE_VIEW_BUILDER(UI_CHROMEOS_EXPORT, ui::ime::AssistiveAccessibilityView)
-
-#endif  // CHROME_BROWSER_ASH_INPUT_METHOD_UI_ASSISTIVE_ACCESSIBILITY_VIEW_H_
diff --git a/chrome/browser/ash/input_method/ui/suggestion_window_view.h b/chrome/browser/ash/input_method/ui/suggestion_window_view.h
index e1e468d..ea24a345 100644
--- a/chrome/browser/ash/input_method/ui/suggestion_window_view.h
+++ b/chrome/browser/ash/input_method/ui/suggestion_window_view.h
@@ -11,8 +11,8 @@
 
 #include "base/containers/flat_map.h"
 #include "base/memory/raw_ptr.h"
+#include "chrome/browser/ash/input_method/ui/announcement_label.h"
 #include "chrome/browser/ash/input_method/ui/indexed_suggestion_candidate_button.h"
-#include "chrome/browser/ash/input_method/ui/suggestion_accessibility_label.h"
 #include "chromeos/ash/services/ime/public/cpp/assistive_suggestions.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/chromeos/ui_chromeos_export.h"
diff --git a/chrome/browser/background/background_contents.cc b/chrome/browser/background/background_contents.cc
index 7191d23d..0cbd83ea 100644
--- a/chrome/browser/background/background_contents.cc
+++ b/chrome/browser/background/background_contents.cc
@@ -49,7 +49,6 @@
       opener ? opener->GetProcess()->GetID() : MSG_ROUTING_NONE;
   create_params.opener_render_frame_id =
       opener ? opener->GetRoutingID() : MSG_ROUTING_NONE;
-  create_params.is_never_visible = true;
 
   if (session_storage_namespace) {
     content::SessionStorageNamespaceMap session_storage_namespace_map;
diff --git a/chrome/browser/extensions/active_install_data.cc b/chrome/browser/extensions/active_install_data.cc
index 1d26452..c7c936f 100644
--- a/chrome/browser/extensions/active_install_data.cc
+++ b/chrome/browser/extensions/active_install_data.cc
@@ -4,9 +4,11 @@
 
 #include "chrome/browser/extensions/active_install_data.h"
 
+#include "extensions/common/extension_id.h"
+
 namespace extensions {
 
-ActiveInstallData::ActiveInstallData(const std::string& extension_id)
+ActiveInstallData::ActiveInstallData(const ExtensionId& extension_id)
     : extension_id(extension_id) {}
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/active_install_data.h b/chrome/browser/extensions/active_install_data.h
index b9dd6de..895159ef 100644
--- a/chrome/browser/extensions/active_install_data.h
+++ b/chrome/browser/extensions/active_install_data.h
@@ -5,16 +5,16 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_ACTIVE_INSTALL_DATA_H_
 #define CHROME_BROWSER_EXTENSIONS_ACTIVE_INSTALL_DATA_H_
 
-#include <string>
+#include "extensions/common/extension_id.h"
 
 namespace extensions {
 
 // Details of an active extension install.
 struct ActiveInstallData {
   ActiveInstallData() = default;
-  explicit ActiveInstallData(const std::string& extension_id);
+  explicit ActiveInstallData(const ExtensionId& extension_id);
 
-  std::string extension_id;
+  ExtensionId extension_id;
   int percent_downloaded = 0;
 };
 
diff --git a/chrome/browser/extensions/active_tab_permission_granter.cc b/chrome/browser/extensions/active_tab_permission_granter.cc
index 82f164e8..7d8f6729 100644
--- a/chrome/browser/extensions/active_tab_permission_granter.cc
+++ b/chrome/browser/extensions/active_tab_permission_granter.cc
@@ -25,6 +25,7 @@
 #include "extensions/browser/process_manager.h"
 #include "extensions/browser/renderer_startup_helper.h"
 #include "extensions/common/extension.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/manifest_handlers/incognito_info.h"
 #include "extensions/common/mojom/renderer.mojom.h"
 #include "extensions/common/permissions/permission_set.h"
@@ -40,7 +41,7 @@
 using RendererMessageFunction =
     base::RepeatingCallback<void(bool, content::RenderProcessHost*)>;
 
-void UpdateTabSpecificPermissions(const std::string& extension_id,
+void UpdateTabSpecificPermissions(const ExtensionId& extension_id,
                                   const extensions::URLPatternSet& new_hosts,
                                   int tab_id,
                                   bool update_origin_allowlist,
@@ -55,7 +56,7 @@
   }
 }
 
-void ClearTabSpecificPermissions(const std::vector<std::string>& extension_ids,
+void ClearTabSpecificPermissions(const std::vector<ExtensionId>& extension_ids,
                                  int tab_id,
                                  bool update_origin_allowlist,
                                  content::RenderProcessHost* process) {
@@ -246,7 +247,7 @@
   }
 
   std::set<content::RenderFrameHost*> frame_hosts;
-  std::vector<std::string> extension_ids;
+  std::vector<ExtensionId> extension_ids;
   content::BrowserContext* browser_context =
       web_contents()->GetBrowserContext();
   ProcessManager* process_manager = ProcessManager::Get(browser_context);
diff --git a/chrome/browser/extensions/api/cookies/cookies_api.cc b/chrome/browser/extensions/api/cookies/cookies_api.cc
index 8d8fe69..3770485 100644
--- a/chrome/browser/extensions/api/cookies/cookies_api.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_api.cc
@@ -279,9 +279,10 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   for (const net::CookieWithAccessResult& cookie_with_access_result :
        cookie_list) {
-    if (!cookies_helpers::CookieMatchesPartitionKeyInDetails(
-            parsed_args_->details.partition_key,
-            cookie_with_access_result.cookie)) {
+    if (!cookies_helpers::
+            CanonicalCookiePartitionKeyMatchesApiCookiePartitionKey(
+                parsed_args_->details.partition_key,
+                cookie_with_access_result.cookie.PartitionKey())) {
       continue;
     }
 
@@ -560,9 +561,10 @@
     // CookieMonster returns them in canonical order (longest path, then
     // earliest creation time).
 
-    if (!extensions::cookies_helpers::CookieMatchesPartitionKeyInDetails(
-            parsed_args_->details.partition_key,
-            cookie_with_access_result.cookie)) {
+    if (!extensions::cookies_helpers::
+            CanonicalCookiePartitionKeyMatchesApiCookiePartitionKey(
+                parsed_args_->details.partition_key,
+                cookie_with_access_result.cookie.PartitionKey())) {
       continue;
     }
 
diff --git a/chrome/browser/extensions/api/cookies/cookies_helpers.cc b/chrome/browser/extensions/api/cookies/cookies_helpers.cc
index e6cfffe..d9ecab9 100644
--- a/chrome/browser/extensions/api/cookies/cookies_helpers.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_helpers.cc
@@ -248,22 +248,29 @@
   return cookie_partition_key_collection.Contains(*cookie.PartitionKey());
 }
 
-bool CookieMatchesPartitionKeyInDetails(
+bool CanonicalCookiePartitionKeyMatchesApiCookiePartitionKey(
     const std::optional<extensions::api::cookies::CookiePartitionKey>&
-        partition_key,
-    const net::CanonicalCookie& cookie) {
-  if (!partition_key) {
-    return !cookie.IsPartitioned();
+        api_partition_key,
+    const absl::optional<net::CookiePartitionKey>& net_partition_key) {
+  if (!api_partition_key.has_value()) {
+    return !net_partition_key.has_value();
   }
 
-  if (cookie.IsPartitioned() && !cookie.PartitionKey()->IsSerializeable()) {
+  if (!net_partition_key.has_value()) {
     return false;
   }
 
-  std::string serialized_partition_key;
-  return net::CookiePartitionKey::Serialize(cookie.PartitionKey(),
-                                            serialized_partition_key) &&
-         serialized_partition_key == partition_key->top_level_site.value();
+  // If both keys are present, they both must be serializable for a match.
+  if (!net_partition_key->IsSerializeable() ||
+      !api_partition_key->top_level_site.has_value()) {
+    return false;
+  }
+
+  std::string serialized_net_partition_key;
+  return net::CookiePartitionKey::Serialize(net_partition_key,
+                                            serialized_net_partition_key) &&
+         serialized_net_partition_key ==
+             api_partition_key->top_level_site.value();
 }
 
 net::CookiePartitionKeyCollection
diff --git a/chrome/browser/extensions/api/cookies/cookies_helpers.h b/chrome/browser/extensions/api/cookies/cookies_helpers.h
index 45e93ae..f591ab6f 100644
--- a/chrome/browser/extensions/api/cookies/cookies_helpers.h
+++ b/chrome/browser/extensions/api/cookies/cookies_helpers.h
@@ -115,18 +115,19 @@
     const std::optional<extensions::api::cookies::CookiePartitionKey>&
         partition_key);
 
-// returns true if cookie_partition_key_collection::ContainsAll
-// calls CookieMatchesPartitionKeyInDetails if the collection is not empty
+// Returns true for unpartitioned cookies if the collection is empty.
+// Otherwise returns true if the collection contains the cookie's partition key.
 bool CookieMatchesPartitionKeyCollection(
     const net::CookiePartitionKeyCollection& cookie_partition_key_collection,
     const net::CanonicalCookie& cookie);
 
-// Returns true if the top_level_site values match or the optional does not
-// contain a value.
-bool CookieMatchesPartitionKeyInDetails(
+// Returns true if the top_level_site values match or both optionals do not
+// contain a value. For match to occur both partition keys must be serializable
+// if they are present.
+bool CanonicalCookiePartitionKeyMatchesApiCookiePartitionKey(
     const std::optional<extensions::api::cookies::CookiePartitionKey>&
-        partition_key,
-    const net::CanonicalCookie& cookie);
+        api_partition_key,
+    const absl::optional<net::CookiePartitionKey>& net_partition_key);
 
 // A class representing the cookie filter parameters passed into
 // cookies.getAll().
diff --git a/chrome/browser/extensions/api/cookies/cookies_unittest.cc b/chrome/browser/extensions/api/cookies/cookies_unittest.cc
index 573f3a45..ce83858 100644
--- a/chrome/browser/extensions/api/cookies/cookies_unittest.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_unittest.cc
@@ -215,6 +215,11 @@
   partition_key_for_nonce_and_regular->top_level_site = top_level_site;
   partition_key_for_opaque->top_level_site = "";
 
+  // Partition key to confirm crbug.com/1522601 is addressed.
+  std::optional<extensions::api::cookies::CookiePartitionKey>
+      partition_key_with_no_top_level_site_set =
+          extensions::api::cookies::CookiePartitionKey();
+
   // Make a CanonicalCookie with a opaque top_level_site or nonce in partition
   // key.
   auto cookie = net::CanonicalCookie::CreateUnsafeCookieForTesting(
@@ -253,12 +258,26 @@
 
   // Confirm that to be matchable, the partition key
   // must be serializable.
-  EXPECT_TRUE(cookies_helpers::CookieMatchesPartitionKeyInDetails(
-      partition_key_for_nonce_and_regular, *cookie));
-  EXPECT_FALSE(cookies_helpers::CookieMatchesPartitionKeyInDetails(
-      partition_key_for_nonce_and_regular, *nonce_cookie));
-  EXPECT_FALSE(cookies_helpers::CookieMatchesPartitionKeyInDetails(
-      partition_key_for_opaque, *opaque_cookie));
+  EXPECT_TRUE(
+      cookies_helpers::CanonicalCookiePartitionKeyMatchesApiCookiePartitionKey(
+          partition_key_for_nonce_and_regular, *cookie->PartitionKey()));
+  EXPECT_FALSE(
+      cookies_helpers::CanonicalCookiePartitionKeyMatchesApiCookiePartitionKey(
+          partition_key_for_nonce_and_regular, *nonce_cookie->PartitionKey()));
+  EXPECT_FALSE(
+      cookies_helpers::CanonicalCookiePartitionKeyMatchesApiCookiePartitionKey(
+          partition_key_for_opaque, *opaque_cookie->PartitionKey()));
+  EXPECT_FALSE(
+      cookies_helpers::CanonicalCookiePartitionKeyMatchesApiCookiePartitionKey(
+          partition_key_with_no_top_level_site_set, *cookie->PartitionKey()));
+  EXPECT_FALSE(
+      cookies_helpers::CanonicalCookiePartitionKeyMatchesApiCookiePartitionKey(
+          partition_key_with_no_top_level_site_set,
+          *nonce_cookie->PartitionKey()));
+  EXPECT_FALSE(
+      cookies_helpers::CanonicalCookiePartitionKeyMatchesApiCookiePartitionKey(
+          partition_key_with_no_top_level_site_set,
+          *opaque_cookie->PartitionKey()));
 
   // Confirm that a CanonicalCookie with serializable partition key
   // can be used to create a cookie.
diff --git a/chrome/browser/extensions/ash_extension_keeplist_manager.cc b/chrome/browser/extensions/ash_extension_keeplist_manager.cc
index b075e88..3aec5af 100644
--- a/chrome/browser/extensions/ash_extension_keeplist_manager.cc
+++ b/chrome/browser/extensions/ash_extension_keeplist_manager.cc
@@ -16,6 +16,7 @@
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension.h"
+#include "extensions/common/extension_id.h"
 
 namespace extensions {
 
@@ -73,7 +74,7 @@
   return false;
 }
 
-void AshExtensionKeeplistManager::Disable(const std::string& extension_id) {
+void AshExtensionKeeplistManager::Disable(const ExtensionId& extension_id) {
   DCHECK(should_enforce_keeplist_);
 
   extension_service_->DisableExtension(
diff --git a/chrome/browser/extensions/ash_extension_keeplist_manager.h b/chrome/browser/extensions/ash_extension_keeplist_manager.h
index 91155253..68ef83b 100644
--- a/chrome/browser/extensions/ash_extension_keeplist_manager.h
+++ b/chrome/browser/extensions/ash_extension_keeplist_manager.h
@@ -5,12 +5,11 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_ASH_EXTENSION_KEEPLIST_MANAGER_H_
 #define CHROME_BROWSER_EXTENSIONS_ASH_EXTENSION_KEEPLIST_MANAGER_H_
 
-#include <string>
-
 #include "base/memory/raw_ptr.h"
 #include "base/scoped_observation.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_observer.h"
+#include "extensions/common/extension_id.h"
 
 class Profile;
 
@@ -44,7 +43,7 @@
   bool ShouldDisable(const Extension* extension) const;
 
   // Disables the extension with 'DISABLE_NOT_ASH_KEEPLISTED'.
-  void Disable(const std::string& extension_id);
+  void Disable(const ExtensionId& extension_id);
 
   // Blocks all extensions not on the keeplist by disabling them with
   // 'DISABLE_NOT_ASH_KEEPLISTED'.
diff --git a/chrome/browser/extensions/blocklist.cc b/chrome/browser/extensions/blocklist.cc
index 2aa0e7d..64639b2 100644
--- a/chrome/browser/extensions/blocklist.cc
+++ b/chrome/browser/extensions/blocklist.cc
@@ -27,6 +27,7 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/browser/extension_prefs.h"
+#include "extensions/common/extension_id.h"
 
 using content::BrowserThread;
 using safe_browsing::SafeBrowsingDatabaseManager;
@@ -78,14 +79,14 @@
       public base::RefCountedThreadSafe<SafeBrowsingClientImpl> {
  public:
   using OnResultCallback =
-      base::OnceCallback<void(const std::set<std::string>&)>;
+      base::OnceCallback<void(const std::set<ExtensionId>&)>;
 
   SafeBrowsingClientImpl(const SafeBrowsingClientImpl&) = delete;
   SafeBrowsingClientImpl& operator=(const SafeBrowsingClientImpl&) = delete;
 
   // Constructs a client to query the database manager for |extension_ids| and
   // run |callback| with the IDs of those which have been blocklisted.
-  static void Start(const std::set<std::string>& extension_ids,
+  static void Start(const std::set<ExtensionId>& extension_ids,
                     OnResultCallback callback) {
     auto safe_browsing_client = base::WrapRefCounted(
         new SafeBrowsingClientImpl(extension_ids, std::move(callback)));
@@ -104,7 +105,7 @@
  private:
   friend class base::RefCountedThreadSafe<SafeBrowsingClientImpl>;
 
-  SafeBrowsingClientImpl(const std::set<std::string>& extension_ids,
+  SafeBrowsingClientImpl(const std::set<ExtensionId>& extension_ids,
                          OnResultCallback callback)
       : callback_task_runner_(
             base::SingleThreadTaskRunner::GetCurrentDefault()),
@@ -115,7 +116,7 @@
   // Pass |database_manager| as a parameter to avoid touching
   // SafeBrowsingService on the IO thread.
   void StartCheck(scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
-                  const std::set<std::string>& extension_ids) {
+                  const std::set<ExtensionId>& extension_ids) {
     DCHECK_CURRENTLY_ON(
         base::FeatureList::IsEnabled(safe_browsing::kSafeBrowsingOnUIThread)
             ? content::BrowserThread::UI
@@ -124,7 +125,7 @@
       // Definitely not blocklisted. Callback immediately.
       callback_task_runner_->PostTask(
           FROM_HERE,
-          base::BindOnce(std::move(callback_), std::set<std::string>()));
+          base::BindOnce(std::move(callback_), std::set<ExtensionId>()));
       return;
     }
     // Something might be blocklisted, response will come in
@@ -132,7 +133,7 @@
     AddRef();  // Balanced in OnCheckExtensionsResult
   }
 
-  void OnCheckExtensionsResult(const std::set<std::string>& hits) override {
+  void OnCheckExtensionsResult(const std::set<ExtensionId>& hits) override {
     DCHECK_CURRENTLY_ON(
         base::FeatureList::IsEnabled(safe_browsing::kSafeBrowsingOnUIThread)
             ? content::BrowserThread::UI
@@ -159,7 +160,7 @@
 void GetMalwareFromBlocklistStateMap(
     Blocklist::GetMalwareIDsCallback callback,
     const Blocklist::BlocklistStateMap& state_map) {
-  std::set<std::string> malware;
+  std::set<ExtensionId> malware;
   for (const auto& state_pair : state_map) {
     // TODO(oleg): UNKNOWN is treated as MALWARE for backwards compatibility.
     // In future GetMalwareIDs will be removed and the caller will have to
@@ -200,7 +201,7 @@
   return BlocklistFactory::GetForBrowserContext(context);
 }
 
-void Blocklist::GetBlocklistedIDs(const std::set<std::string>& ids,
+void Blocklist::GetBlocklistedIDs(const std::set<ExtensionId>& ids,
                                   GetBlocklistedIDsCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
@@ -219,15 +220,15 @@
                           weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
 
-void Blocklist::GetMalwareIDs(const std::set<std::string>& ids,
+void Blocklist::GetMalwareIDs(const std::set<ExtensionId>& ids,
                               GetMalwareIDsCallback callback) {
   GetBlocklistedIDs(ids, base::BindOnce(&GetMalwareFromBlocklistStateMap,
                                         std::move(callback)));
 }
 
-void Blocklist::IsBlocklisted(const std::string& extension_id,
+void Blocklist::IsBlocklisted(const ExtensionId& extension_id,
                               IsBlocklistedCallback callback) {
-  std::set<std::string> check;
+  std::set<ExtensionId> check;
   check.insert(extension_id);
   GetBlocklistedIDs(
       check, base::BindOnce(&CheckOneExtensionState, std::move(callback)));
@@ -235,10 +236,10 @@
 
 void Blocklist::GetBlocklistStateForIDs(
     GetBlocklistedIDsCallback callback,
-    const std::set<std::string>& blocklisted_ids) {
+    const std::set<ExtensionId>& blocklisted_ids) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  std::set<std::string> ids_unknown_state;
+  std::set<ExtensionId> ids_unknown_state;
   BlocklistStateMap extensions_state;
   for (const auto& blocklisted_id : blocklisted_ids) {
     auto cache_it = blocklist_state_cache_.find(blocklisted_id);
@@ -269,7 +270,7 @@
 
 void Blocklist::ReturnBlocklistStateMap(
     GetBlocklistedIDsCallback callback,
-    const std::set<std::string>& blocklisted_ids) {
+    const std::set<ExtensionId>& blocklisted_ids) {
   BlocklistStateMap extensions_state;
   for (const auto& blocklisted_id : blocklisted_ids) {
     auto cache_it = blocklist_state_cache_.find(blocklisted_id);
@@ -283,13 +284,13 @@
 }
 
 void Blocklist::RequestExtensionsBlocklistState(
-    const std::set<std::string>& ids,
+    const std::set<ExtensionId>& ids,
     base::OnceClosure callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!state_fetcher_)
     state_fetcher_ = std::make_unique<BlocklistStateFetcher>();
 
-  state_requests_.emplace_back(std::vector<std::string>(ids.begin(), ids.end()),
+  state_requests_.emplace_back(std::vector<ExtensionId>(ids.begin(), ids.end()),
                                std::move(callback));
   for (const auto& id : ids) {
     state_fetcher_->Request(id,
@@ -298,7 +299,7 @@
   }
 }
 
-void Blocklist::OnBlocklistStateReceived(const std::string& id,
+void Blocklist::OnBlocklistStateReceived(const ExtensionId& id,
                                          BlocklistState state) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   blocklist_state_cache_[id] = state;
@@ -307,7 +308,7 @@
   // for which we already got all the required blocklist states.
   auto requests_it = state_requests_.begin();
   while (requests_it != state_requests_.end()) {
-    const std::vector<std::string>& ids = requests_it->first;
+    const std::vector<ExtensionId>& ids = requests_it->first;
 
     bool have_all_in_cache = true;
     for (const auto& id_str : ids) {
diff --git a/chrome/browser/extensions/blocklist.h b/chrome/browser/extensions/blocklist.h
index 3e45689..90ea5399 100644
--- a/chrome/browser/extensions/blocklist.h
+++ b/chrome/browser/extensions/blocklist.h
@@ -19,6 +19,7 @@
 #include "base/observer_list.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "extensions/browser/blocklist_state.h"
+#include "extensions/common/extension_id.h"
 
 namespace content {
 class BrowserContext;
@@ -49,13 +50,13 @@
     raw_ptr<Blocklist> blocklist_;
   };
 
-  using BlocklistStateMap = std::map<std::string, BlocklistState>;
+  using BlocklistStateMap = std::map<ExtensionId, BlocklistState>;
 
   using GetBlocklistedIDsCallback =
       base::OnceCallback<void(const BlocklistStateMap&)>;
 
   using GetMalwareIDsCallback =
-      base::OnceCallback<void(const std::set<std::string>&)>;
+      base::OnceCallback<void(const std::set<ExtensionId>&)>;
 
   using IsBlocklistedCallback = base::OnceCallback<void(BlocklistState)>;
 
@@ -78,18 +79,18 @@
   //
   // For a synchronous version which ONLY CHECKS CURRENTLY INSTALLED EXTENSIONS
   // see ExtensionPrefs::IsExtensionBlocklisted.
-  void GetBlocklistedIDs(const std::set<std::string>& ids,
+  void GetBlocklistedIDs(const std::set<ExtensionId>& ids,
                          GetBlocklistedIDsCallback callback);
 
   // From the subset of extension IDs passed in via |ids|, select the ones
   // marked in the blocklist as BLOCKLISTED_MALWARE and asynchronously pass
   // to |callback|. Basically, will call GetBlocklistedIDs and filter its
   // results.
-  void GetMalwareIDs(const std::set<std::string>& ids,
+  void GetMalwareIDs(const std::set<ExtensionId>& ids,
                      GetMalwareIDsCallback callback);
 
   // More convenient form of GetBlocklistedIDs for checking a single extension.
-  void IsBlocklisted(const std::string& extension_id,
+  void IsBlocklisted(const ExtensionId& extension_id,
                      IsBlocklistedCallback callback);
 
   // Used to mock BlocklistStateFetcher in unit tests. Blocklist owns the
@@ -130,15 +131,15 @@
   void NotifyObservers();
 
   void GetBlocklistStateForIDs(GetBlocklistedIDsCallback callback,
-                               const std::set<std::string>& blocklisted_ids);
+                               const std::set<ExtensionId>& blocklisted_ids);
 
-  void RequestExtensionsBlocklistState(const std::set<std::string>& ids,
+  void RequestExtensionsBlocklistState(const std::set<ExtensionId>& ids,
                                        base::OnceClosure callback);
 
-  void OnBlocklistStateReceived(const std::string& id, BlocklistState state);
+  void OnBlocklistStateReceived(const ExtensionId& id, BlocklistState state);
 
   void ReturnBlocklistStateMap(GetBlocklistedIDsCallback callback,
-                               const std::set<std::string>& blocklisted_ids);
+                               const std::set<ExtensionId>& blocklisted_ids);
 
   base::ObserverList<Observer>::Unchecked observers_;
 
diff --git a/chrome/browser/extensions/blocklist_states_interaction_unittest.cc b/chrome/browser/extensions/blocklist_states_interaction_unittest.cc
index f83ebe7..d861d30 100644
--- a/chrome/browser/extensions/blocklist_states_interaction_unittest.cc
+++ b/chrome/browser/extensions/blocklist_states_interaction_unittest.cc
@@ -10,6 +10,7 @@
 #include "components/safe_browsing/buildflags.h"
 #include "extensions/browser/blocklist_extension_prefs.h"
 #include "extensions/browser/blocklist_state.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/test/extension_state_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -46,7 +47,7 @@
 
  protected:
   void SetSafeBrowsingBlocklistStateForExtension(
-      const std::string& extension_id,
+      const ExtensionId& extension_id,
       BlocklistState state) {
     // Reset cache in blocklist to make sure the latest blocklist state is
     // fetched.
@@ -55,7 +56,7 @@
     task_environment()->RunUntilIdle();
   }
 
-  void SetOmahaBlocklistStateForExtension(const std::string& extension_id,
+  void SetOmahaBlocklistStateForExtension(const ExtensionId& extension_id,
                                           const std::string& omaha_attribute,
                                           bool value) {
     auto attributes = base::Value::Dict().Set(omaha_attribute, value);
diff --git a/chrome/browser/extensions/blocklist_unittest.cc b/chrome/browser/extensions/blocklist_unittest.cc
index 5f79f23..22385587 100644
--- a/chrome/browser/extensions/blocklist_unittest.cc
+++ b/chrome/browser/extensions/blocklist_unittest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/extensions/test_extension_prefs.h"
 #include "content/public/test/browser_task_environment.h"
 #include "extensions/browser/extension_prefs.h"
+#include "extensions/common/extension_id.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace extensions {
@@ -26,7 +27,7 @@
       : test_prefs_(base::SingleThreadTaskRunner::GetCurrentDefault()) {}
 
  protected:
-  std::string AddExtension(const std::string& id) {
+  ExtensionId AddExtension(const ExtensionId& id) {
     return test_prefs_.AddExtension(id)->id();
   }
 
@@ -44,9 +45,9 @@
 }  // namespace
 
 TEST_F(BlocklistTest, OnlyIncludesRequestedIDs) {
-  std::string a = AddExtension("a");
-  std::string b = AddExtension("b");
-  std::string c = AddExtension("c");
+  ExtensionId a = AddExtension("a");
+  ExtensionId b = AddExtension("b");
+  ExtensionId c = AddExtension("c");
 
   Blocklist blocklist;
   TestBlocklist tester(&blocklist);
@@ -57,16 +58,16 @@
   EXPECT_EQ(BLOCKLISTED_MALWARE, tester.GetBlocklistState(b));
   EXPECT_EQ(NOT_BLOCKLISTED, tester.GetBlocklistState(c));
 
-  std::set<std::string> blocklisted_ids;
+  std::set<ExtensionId> blocklisted_ids;
   blocklist.GetMalwareIDs(
-      {a, c}, base::BindOnce(&Assign<std::set<std::string>>, &blocklisted_ids));
+      {a, c}, base::BindOnce(&Assign<std::set<ExtensionId>>, &blocklisted_ids));
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ((std::set<std::string>{a}), blocklisted_ids);
+  EXPECT_EQ((std::set<ExtensionId>{a}), blocklisted_ids);
 }
 
 TEST_F(BlocklistTest, SafeBrowsing) {
-  std::string a = AddExtension("a");
+  ExtensionId a = AddExtension("a");
 
   Blocklist blocklist;
   TestBlocklist tester(&blocklist);
@@ -94,11 +95,11 @@
   Blocklist blocklist;
   TestBlocklist tester(&blocklist);
 
-  std::string a = AddExtension("a");
-  std::string b = AddExtension("b");
-  std::string c = AddExtension("c");
-  std::string d = AddExtension("d");
-  std::string e = AddExtension("e");
+  ExtensionId a = AddExtension("a");
+  ExtensionId b = AddExtension("b");
+  ExtensionId c = AddExtension("c");
+  ExtensionId d = AddExtension("d");
+  ExtensionId e = AddExtension("e");
 
   tester.SetBlocklistState(a, BLOCKLISTED_MALWARE, false);
   tester.SetBlocklistState(b, BLOCKLISTED_SECURITY_VULNERABILITY, false);
@@ -144,9 +145,9 @@
       new FakeSafeBrowsingDatabaseManager(true));
   ScopedDatabaseManagerForTest scoped_blocklist_db(blocklist_db);
 
-  std::string a = AddExtension("a");
-  std::string b = AddExtension("b");
-  std::string c = AddExtension("c");
+  ExtensionId a = AddExtension("a");
+  ExtensionId b = AddExtension("b");
+  ExtensionId c = AddExtension("c");
 
   blocklist_db->Enable();
   blocklist_db->SetUnsafe(a, b);
diff --git a/chrome/browser/extensions/cache_wasm_extension_browsertest.cc b/chrome/browser/extensions/cache_wasm_extension_browsertest.cc
deleted file mode 100644
index a4a1b84..0000000
--- a/chrome/browser/extensions/cache_wasm_extension_browsertest.cc
+++ /dev/null
@@ -1,141 +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.
-
-#include "base/base_paths.h"
-#include "base/files/file_util.h"
-#include "base/path_service.h"
-#include "base/threading/platform_thread.h"
-#include "chrome/browser/extensions/chrome_test_extension_loader.h"
-#include "chrome/browser/extensions/extension_browsertest.h"
-#include "chrome/browser/ui/browser_commands.h"
-#include "components/metrics/content/subprocess_metrics_provider.h"
-#include "content/public/test/browser_test.h"
-#include "content/public/test/browser_test_utils.h"
-#include "third_party/blink/public/common/switches.h"
-
-namespace chrome {
-
-class WasmExtensionCachingBrowserTest
-    : public extensions::ExtensionBrowserTest {
- public:
-  WasmExtensionCachingBrowserTest() = default;
-  ~WasmExtensionCachingBrowserTest() override = default;
-
-  const base::FilePath& GetExtensionDir() {
-    if (!tmp_dir_.IsValid()) {
-      CHECK(tmp_dir_.CreateUniqueTempDir());
-    }
-    return tmp_dir_.GetPath();
-  }
-
-  // Fetch the |histogram|'s |bucket| in every renderer process until reaching,
-  // but not exceeding, |expected_count|.
-  template <typename T>
-  void CheckHistogramCount(base::StringPiece histogram,
-                           T bucket,
-                           int expected_count) {
-    while (true) {
-      content::FetchHistogramsFromChildProcesses();
-      metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
-
-      int count = histogram_tester_.GetBucketCount(histogram, bucket);
-      CHECK_LE(count, expected_count);
-      if (count == expected_count) {
-        return;
-      }
-
-      base::PlatformThread::Sleep(base::Milliseconds(5));
-    }
-  }
-
- private:
-  // Flag `allow-natives-syntax` is needed to be able to call runtime functions
-  // (runtime functions have the % prefix).
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    command_line->AppendSwitchASCII(blink::switches::kJavaScriptFlags,
-                                    "--allow-natives-syntax");
-    command_line->AppendSwitchASCII("wasm-caching-threshold", "1");
-    ExtensionBrowserTest::SetUpCommandLine(command_line);
-  }
-
-  base::ScopedTempDir tmp_dir_;
-  base::HistogramTester histogram_tester_;
-};
-
-// The enum values need to match "WasmCodeCaching" in
-// tools/metrics/histograms/metadata/v8/enums.xml.
-enum WasmCodeCaching {
-  kMiss = 0,
-  kHit = 1,
-  kInvalidCacheEntry = 2,
-  kNoCacheHandler = 3,
-
-  kMaxValue = kNoCacheHandler
-};
-
-// The `large.wasm` file is very large: 2.5MB. To avoid increasing the git
-// repository, we prefer borrowing it from web_tests.
-base::FilePath LargeWasmPath() {
-  base::FilePath root_path;
-  CHECK(base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &root_path));
-  return root_path.Append(FILE_PATH_LITERAL(
-      "third_party/blink/web_tests/http/tests/wasm/resources/large.wasm"));
-}
-
-// Test that we cache streaming compiled/instantiated Wasm modules in
-// extensions. We have to wait until caching of the module happens and the
-// histogram is populated.
-IN_PROC_BROWSER_TEST_F(WasmExtensionCachingBrowserTest, CacheWasmExtensions) {
-  base::ScopedAllowBlockingForTesting allow_blocking;
-  CHECK(base::CopyFile(LargeWasmPath(),
-                       GetExtensionDir().AppendASCII("large.wasm")));
-
-  base::WriteFile(GetExtensionDir().AppendASCII("service_worker_background.js"),
-                  R"(
-      chrome.tabs.onCreated.addListener(() => {
-        // Run all functions until there are no unoptimized functions left.
-        WebAssembly.instantiateStreaming(fetch("large.wasm")).then(result => {
-          let has_unoptimized = true;
-          while (has_unoptimized) {
-            has_unoptimized = false;
-            for (export_name in result.instance.exports) {
-              const func = result.instance.exports[export_name];
-              func(1, 2, 4);
-              has_unoptimized ||= %IsLiftoffFunction(func);
-            }
-          }
-        });
-      });
-    )");
-
-  base::WriteFile(GetExtensionDir().AppendASCII("manifest.json"), R"({
-    "name": "foo",
-    "description": "foo",
-    "version": "0.1",
-    "manifest_version": 2,
-    "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
-    "background": {
-      "service_worker": "service_worker_background.js"
-    }
-  })");
-
-  // After loading the extension, no WebAssembly have been executed.
-  extensions::ChromeTestExtensionLoader loader(browser()->profile());
-  loader.LoadExtension(GetExtensionDir());
-  CheckHistogramCount("V8.WasmCodeCaching", WasmCodeCaching::kMiss, 0);
-  CheckHistogramCount("V8.WasmCodeCaching", WasmCodeCaching::kHit, 0);
-
-  // Compile and execute webassembly code for the first time. This should be a
-  // cache miss.
-  NewTab(browser());
-  CheckHistogramCount("V8.WasmCodeCaching", WasmCodeCaching::kMiss, 1);
-  CheckHistogramCount("V8.WasmCodeCaching", WasmCodeCaching::kHit, 0);
-
-  // Repeat: This should be a cache hit this time.
-  NewTab(browser());
-  CheckHistogramCount("V8.WasmCodeCaching", WasmCodeCaching::kMiss, 1);
-  CheckHistogramCount("V8.WasmCodeCaching", WasmCodeCaching::kHit, 1);
-}
-
-}  // namespace chrome
diff --git a/chrome/browser/extensions/chrome_app_sorting.cc b/chrome/browser/extensions/chrome_app_sorting.cc
index a4d5438..1310bef8 100644
--- a/chrome/browser/extensions/chrome_app_sorting.cc
+++ b/chrome/browser/extensions/chrome_app_sorting.cc
@@ -28,6 +28,7 @@
 #include "extensions/browser/extension_system.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/manifest_handlers/app_display_info.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -112,8 +113,9 @@
   // Convert all the page index values to page ordinals. If there are any
   // app launch values that need to be migrated, inserted them into a sorted
   // set to be dealt with later.
-  typedef std::map<syncer::StringOrdinal, std::map<int, const std::string*>,
-                   syncer::StringOrdinal::LessThanFn> AppPositionToIdMapping;
+  typedef std::map<syncer::StringOrdinal, std::map<int, const ExtensionId*>,
+                   syncer::StringOrdinal::LessThanFn>
+      AppPositionToIdMapping;
   AppPositionToIdMapping app_launches_to_convert;
   for (auto ext_id = extension_ids.begin(); ext_id != extension_ids.end();
        ++ext_id) {
@@ -224,7 +226,7 @@
       // Note - this iteration doesn't change app_launch_it->first, this just
       // iterates through the value list in the multimap (as it only iterates
       // |app_count| times)
-      std::vector<std::string> conflicting_ids;
+      std::vector<ExtensionId> conflicting_ids;
       for (int i = 0; i < app_count; ++i, ++app_launch_it)
         conflicting_ids.push_back(app_launch_it->second);
       std::sort(conflicting_ids.begin(), conflicting_ids.end());
@@ -256,7 +258,7 @@
 }
 
 void ChromeAppSorting::EnsureValidOrdinals(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     const syncer::StringOrdinal& suggested_page) {
   syncer::StringOrdinal page_ordinal = GetPageOrdinal(extension_id);
   if (!page_ordinal.IsValid()) {
@@ -287,7 +289,7 @@
 }
 
 bool ChromeAppSorting::GetDefaultOrdinals(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     syncer::StringOrdinal* page_ordinal,
     syncer::StringOrdinal* app_launch_ordinal) {
   CreateDefaultOrdinals();
@@ -303,9 +305,9 @@
 }
 
 void ChromeAppSorting::OnExtensionMoved(
-    const std::string& moved_extension_id,
-    const std::string& predecessor_extension_id,
-    const std::string& successor_extension_id) {
+    const ExtensionId& moved_extension_id,
+    const ExtensionId& predecessor_extension_id,
+    const ExtensionId& successor_extension_id) {
   // We only need to change the StringOrdinal if there are neighbours.
   if (!predecessor_extension_id.empty() || !successor_extension_id.empty()) {
     if (predecessor_extension_id.empty()) {
@@ -335,7 +337,7 @@
 }
 
 syncer::StringOrdinal ChromeAppSorting::GetAppLaunchOrdinal(
-    const std::string& extension_id) const {
+    const ExtensionId& extension_id) const {
   if (web_app_registrar_ && web_app_registrar_->IsInstalled(extension_id))
     return web_app_registrar_->GetAppById(extension_id)->user_launch_ordinal();
 
@@ -349,7 +351,7 @@
 }
 
 void ChromeAppSorting::SetAppLaunchOrdinal(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     const syncer::StringOrdinal& new_app_launch_ordinal) {
   // No work is required if the old and new values are the same.
   if (new_app_launch_ordinal.EqualsOrBothInvalid(
@@ -425,7 +427,7 @@
 }
 
 syncer::StringOrdinal ChromeAppSorting::GetPageOrdinal(
-    const std::string& extension_id) const {
+    const ExtensionId& extension_id) const {
   if (web_app_registrar_ && web_app_registrar_->IsInstalled(extension_id))
     return web_app_registrar_->GetAppById(extension_id)->user_page_ordinal();
 
@@ -438,7 +440,7 @@
 }
 
 void ChromeAppSorting::SetPageOrdinal(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     const syncer::StringOrdinal& new_page_ordinal) {
   // No work is required if the old and new values are the same.
   if (new_page_ordinal.EqualsOrBothInvalid(GetPageOrdinal(extension_id)))
@@ -465,7 +467,7 @@
   SyncIfNeeded(extension_id);
 }
 
-void ChromeAppSorting::ClearOrdinals(const std::string& extension_id) {
+void ChromeAppSorting::ClearOrdinals(const ExtensionId& extension_id) {
   RemoveOrdinalMapping(extension_id,
                        GetPageOrdinal(extension_id),
                        GetAppLaunchOrdinal(extension_id));
@@ -497,7 +499,7 @@
   return ntp_ordinal_map_.rbegin()->first;
 }
 
-void ChromeAppSorting::SetExtensionVisible(const std::string& extension_id,
+void ChromeAppSorting::SetExtensionVisible(const ExtensionId& extension_id,
                                            bool visible) {
   if (visible)
     ntp_hidden_extensions_.erase(extension_id);
@@ -621,7 +623,7 @@
 }
 
 void ChromeAppSorting::AddOrdinalMapping(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     const syncer::StringOrdinal& page_ordinal,
     const syncer::StringOrdinal& app_launch_ordinal) {
   if (!page_ordinal.IsValid() || !app_launch_ordinal.IsValid())
@@ -643,7 +645,7 @@
 }
 
 void ChromeAppSorting::RemoveOrdinalMapping(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     const syncer::StringOrdinal& page_ordinal,
     const syncer::StringOrdinal& app_launch_ordinal) {
   if (!page_ordinal.IsValid() || !app_launch_ordinal.IsValid())
@@ -664,7 +666,7 @@
   }
 }
 
-void ChromeAppSorting::SyncIfNeeded(const std::string& extension_id) {
+void ChromeAppSorting::SyncIfNeeded(const ExtensionId& extension_id) {
   // Can be null in tests.
   if (!browser_context_)
     return;
@@ -699,7 +701,7 @@
   syncer::StringOrdinal app_launch_ordinal =
       CreateFirstAppLaunchOrdinal(page_ordinal);
   for (size_t i = 0; i < app_ids.size(); ++i) {
-    const std::string extension_id = app_ids[i];
+    const ExtensionId extension_id = app_ids[i];
     default_ordinals_[extension_id].page_ordinal = page_ordinal;
     default_ordinals_[extension_id].app_launch_ordinal = app_launch_ordinal;
     app_launch_ordinal = app_launch_ordinal.CreateAfter();
@@ -739,7 +741,7 @@
     const AppLaunchOrdinalMap& m) const {
   size_t result = 0;
   for (auto it = m.begin(); it != m.end(); ++it) {
-    const std::string& id = it->second;
+    const ExtensionId& id = it->second;
     if (ntp_hidden_extensions_.count(id) == 0)
       result++;
   }
diff --git a/chrome/browser/extensions/chrome_app_sorting.h b/chrome/browser/extensions/chrome_app_sorting.h
index fde23fc..29e2756f 100644
--- a/chrome/browser/extensions/chrome_app_sorting.h
+++ b/chrome/browser/extensions/chrome_app_sorting.h
@@ -51,18 +51,18 @@
   void InitializePageOrdinalMapFromWebApps() override;
   void FixNTPOrdinalCollisions() override;
   void EnsureValidOrdinals(
-      const std::string& extension_id,
+      const ExtensionId& extension_id,
       const syncer::StringOrdinal& suggested_page) override;
-  bool GetDefaultOrdinals(const std::string& extension_id,
+  bool GetDefaultOrdinals(const ExtensionId& extension_id,
                           syncer::StringOrdinal* page_ordinal,
                           syncer::StringOrdinal* app_launch_ordinal) override;
-  void OnExtensionMoved(const std::string& moved_extension_id,
-                        const std::string& predecessor_extension_id,
-                        const std::string& successor_extension_id) override;
+  void OnExtensionMoved(const ExtensionId& moved_extension_id,
+                        const ExtensionId& predecessor_extension_id,
+                        const ExtensionId& successor_extension_id) override;
   syncer::StringOrdinal GetAppLaunchOrdinal(
-      const std::string& extension_id) const override;
+      const ExtensionId& extension_id) const override;
   void SetAppLaunchOrdinal(
-      const std::string& extension_id,
+      const ExtensionId& extension_id,
       const syncer::StringOrdinal& new_app_launch_ordinal) override;
   syncer::StringOrdinal CreateFirstAppLaunchOrdinal(
       const syncer::StringOrdinal& page_ordinal) const override;
@@ -71,14 +71,14 @@
   syncer::StringOrdinal CreateFirstAppPageOrdinal() const override;
   syncer::StringOrdinal GetNaturalAppPageOrdinal() const override;
   syncer::StringOrdinal GetPageOrdinal(
-      const std::string& extension_id) const override;
-  void SetPageOrdinal(const std::string& extension_id,
+      const ExtensionId& extension_id) const override;
+  void SetPageOrdinal(const ExtensionId& extension_id,
                       const syncer::StringOrdinal& new_page_ordinal) override;
-  void ClearOrdinals(const std::string& extension_id) override;
+  void ClearOrdinals(const ExtensionId& extension_id) override;
   int PageStringOrdinalAsInteger(
       const syncer::StringOrdinal& page_ordinal) const override;
   syncer::StringOrdinal PageIntegerAsStringOrdinal(size_t page_index) override;
-  void SetExtensionVisible(const std::string& extension_id,
+  void SetExtensionVisible(const ExtensionId& extension_id,
                            bool visible) override;
 
   // web_app::WebAppInstallManagerObserver:
@@ -93,9 +93,10 @@
  private:
   // The StringOrdinal is the app launch ordinal and the string is the extension
   // id.
-  typedef std::multimap<
-      syncer::StringOrdinal, std::string,
-    syncer::StringOrdinal::LessThanFn> AppLaunchOrdinalMap;
+  typedef std::multimap<syncer::StringOrdinal,
+                        ExtensionId,
+                        syncer::StringOrdinal::LessThanFn>
+      AppLaunchOrdinalMap;
   // The StringOrdinal is the page ordinal and the AppLaunchOrdinalMap is the
   // contents of that page.
   typedef std::map<
@@ -123,7 +124,7 @@
     syncer::StringOrdinal page_ordinal;
     syncer::StringOrdinal app_launch_ordinal;
   };
-  using AppOrdinalsMap = std::map<std::string, AppOrdinals>;
+  using AppOrdinalsMap = std::map<ExtensionId, AppOrdinals>;
 
   // This function returns the lowest ordinal on |page_ordinal| if
   // |return_value| == AppLaunchOrdinalReturn::MIN_ORDINAL, otherwise it returns
@@ -137,7 +138,7 @@
   // Initialize the |ntp_ordinal_map_| with the page ordinals used by the
   // given extensions or by fetching web apps.
   void InitializePageOrdinalMap(
-      const std::vector<std::string>& extension_or_app_ids);
+      const std::vector<ExtensionId>& extension_or_app_ids);
 
   // Migrates the app launcher and page index values.
   void MigrateAppIndex(const ExtensionIdList& extension_ids);
@@ -145,7 +146,7 @@
   // Called to add a new mapping value for |extension_id| with a page ordinal
   // of |page_ordinal| and a app launch ordinal of |app_launch_ordinal|. This
   // works with valid and invalid StringOrdinals.
-  void AddOrdinalMapping(const std::string& extension_id,
+  void AddOrdinalMapping(const ExtensionId& extension_id,
                          const syncer::StringOrdinal& page_ordinal,
                          const syncer::StringOrdinal& app_launch_ordinal);
 
@@ -156,13 +157,13 @@
   // |page_ordinal| and a app launch ordinal of |app_launch_ordinal|. If there
   // is not matching map, nothing happens. This works with valid and invalid
   // StringOrdinals.
-  void RemoveOrdinalMapping(const std::string& extension_id,
+  void RemoveOrdinalMapping(const ExtensionId& extension_id,
                             const syncer::StringOrdinal& page_ordinal,
                             const syncer::StringOrdinal& app_launch_ordinal);
 
   // Syncs the extension if needed. It is an error to call this if the
   // extension is not an application.
-  void SyncIfNeeded(const std::string& extension_id);
+  void SyncIfNeeded(const ExtensionId& extension_id);
 
   // Creates the default ordinals.
   void CreateDefaultOrdinals();
@@ -211,7 +212,7 @@
   bool default_ordinals_created_;
 
   // The set of extensions that don't appear in the new tab page.
-  std::set<std::string> ntp_hidden_extensions_;
+  std::set<ExtensionId> ntp_hidden_extensions_;
 
   // Observe the ExtensionRegistry. The registry is guaranteed to outlive this
   // object, since this is owned by the ExtensionSystem, which depends on the
diff --git a/chrome/browser/extensions/chrome_component_extension_resource_manager.cc b/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
index 6f75460..1d9aa62 100644
--- a/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
+++ b/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
@@ -20,6 +20,7 @@
 #include "chrome/grit/theme_resources.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/extension_id.h"
 #include "pdf/buildflags.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -50,7 +51,7 @@
 class ChromeComponentExtensionResourceManager::Data {
  public:
   using TemplateReplacementMap =
-      std::map<std::string, ui::TemplateReplacements>;
+      std::map<ExtensionId, ui::TemplateReplacements>;
 
   Data();
   Data(const Data&) = delete;
@@ -207,7 +208,7 @@
 
 const ui::TemplateReplacements*
 ChromeComponentExtensionResourceManager::GetTemplateReplacementsForExtension(
-    const std::string& extension_id) const {
+    const ExtensionId& extension_id) const {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   LazyInitData();
diff --git a/chrome/browser/extensions/chrome_component_extension_resource_manager.h b/chrome/browser/extensions/chrome_component_extension_resource_manager.h
index 52fdabc4..9028b9e 100644
--- a/chrome/browser/extensions/chrome_component_extension_resource_manager.h
+++ b/chrome/browser/extensions/chrome_component_extension_resource_manager.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "extensions/browser/component_extension_resource_manager.h"
+#include "extensions/common/extension_id.h"
 
 namespace extensions {
 
@@ -28,7 +29,7 @@
                                     const base::FilePath& resource_path,
                                     int* resource_id) const override;
   const ui::TemplateReplacements* GetTemplateReplacementsForExtension(
-      const std::string& extension_id) const override;
+      const ExtensionId& extension_id) const override;
 
  private:
   class Data;
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
index 92437a8..2c7d5801 100644
--- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
+++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
@@ -63,6 +63,7 @@
 #include "extensions/browser/url_request_util.h"
 #include "extensions/browser/view_type_utils.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/extension_urls.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/manifest_handlers/background_info.h"
@@ -143,12 +144,12 @@
     content::RenderProcessHost* process_host,
     ProcessMap* process_map,
     ExtensionRegistry* registry) {
-  std::set<std::string> extension_ids =
+  std::set<ExtensionId> extension_ids =
       process_map->GetExtensionsInProcess(process_host->GetID());
   if (extension_ids.empty())
     return PRIV_NORMAL;
 
-  for (const std::string& extension_id : extension_ids) {
+  for (const ExtensionId& extension_id : extension_ids) {
     const Extension* extension =
         registry->enabled_extensions().GetByID(extension_id);
     if (extension && extension->is_hosted_app())
@@ -472,7 +473,7 @@
   bool is_guest =
       WebViewRendererState::GetInstance()->IsGuest(process_host->GetID());
   if (is_guest) {
-    std::string owner_extension_id;
+    ExtensionId owner_extension_id;
     int owner_process_id = -1;
     bool found_owner = WebViewRendererState::GetInstance()->GetOwnerInfo(
         process_host->GetID(), &owner_process_id, &owner_extension_id);
diff --git a/chrome/browser/extensions/chrome_content_verifier_delegate.cc b/chrome/browser/extensions/chrome_content_verifier_delegate.cc
index dad75fa..636ce9c4 100644
--- a/chrome/browser/extensions/chrome_content_verifier_delegate.cc
+++ b/chrome/browser/extensions/chrome_content_verifier_delegate.cc
@@ -34,6 +34,7 @@
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/management_policy.h"
 #include "extensions/browser/pref_types.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/extension_urls.h"
 #include "extensions/common/extensions_client.h"
 #include "extensions/common/manifest.h"
@@ -166,7 +167,7 @@
 }
 
 GURL ChromeContentVerifierDelegate::GetSignatureFetchUrl(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     const base::Version& version) {
   // TODO(asargent) Factor out common code from the extension updater's
   // ManifestFetchData class that can be shared for use here.
@@ -190,7 +191,7 @@
 }
 
 void ChromeContentVerifierDelegate::VerifyFailed(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     ContentVerifyJob::FailureReason reason) {
   ExtensionRegistry* registry = ExtensionRegistry::Get(context_);
   const Extension* extension =
diff --git a/chrome/browser/extensions/chrome_content_verifier_delegate.h b/chrome/browser/extensions/chrome_content_verifier_delegate.h
index 9b85701..7695ea9 100644
--- a/chrome/browser/extensions/chrome_content_verifier_delegate.h
+++ b/chrome/browser/extensions/chrome_content_verifier_delegate.h
@@ -13,6 +13,7 @@
 
 #include "base/memory/raw_ptr.h"
 #include "extensions/browser/content_verifier_delegate.h"
+#include "extensions/common/extension_id.h"
 
 namespace content {
 class BrowserContext;
@@ -76,11 +77,11 @@
   // ContentVerifierDelegate:
   VerifierSourceType GetVerifierSourceType(const Extension& extension) override;
   ContentVerifierKey GetPublicKey() override;
-  GURL GetSignatureFetchUrl(const std::string& extension_id,
+  GURL GetSignatureFetchUrl(const ExtensionId& extension_id,
                             const base::Version& version) override;
   std::set<base::FilePath> GetBrowserImagePaths(
       const extensions::Extension* extension) override;
-  void VerifyFailed(const std::string& extension_id,
+  void VerifyFailed(const ExtensionId& extension_id,
                     ContentVerifyJob::FailureReason reason) override;
   void Shutdown() override;
 
@@ -98,16 +99,16 @@
   // This maps an extension id to a backoff entry for slowing down
   // redownload/reinstall of corrupt policy extensions if it keeps happening
   // in a loop (eg crbug.com/661738).
-  std::map<std::string, std::unique_ptr<net::BackoffEntry>>
+  std::map<ExtensionId, std::unique_ptr<net::BackoffEntry>>
       policy_reinstall_backoff_;
 
   // For reporting metrics in BOOTSTRAP mode, when an extension would be
   // disabled if content verification was in ENFORCE mode.
-  std::set<std::string> would_be_disabled_ids_;
+  std::set<ExtensionId> would_be_disabled_ids_;
 
   // For reporting metrics about extensions without hashes, which we want to
   // reinstall in the future. See https://crbug.com/958794#c22 for details.
-  std::set<std::string> would_be_reinstalled_ids_;
+  std::set<ExtensionId> would_be_reinstalled_ids_;
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/chrome_extension_frame_host.cc b/chrome/browser/extensions/chrome_extension_frame_host.cc
index 772fe80e0..b494e661 100644
--- a/chrome/browser/extensions/chrome_extension_frame_host.cc
+++ b/chrome/browser/extensions/chrome_extension_frame_host.cc
@@ -13,6 +13,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_util.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/extension_set.h"
 #include "extensions/common/extension_urls.h"
 #include "third_party/blink/public/common/logging/logging_utils.h"
@@ -27,7 +28,7 @@
 ChromeExtensionFrameHost::~ChromeExtensionFrameHost() = default;
 
 void ChromeExtensionFrameHost::RequestScriptInjectionPermission(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     mojom::InjectionType script_type,
     mojom::RunLocation run_location,
     RequestScriptInjectionPermissionCallback callback) {
@@ -78,7 +79,7 @@
 
   content::RenderFrameHost* render_frame_host =
       receivers_.GetCurrentTargetFrame();
-  std::string extension_id = util::GetExtensionIdFromFrame(render_frame_host);
+  ExtensionId extension_id = util::GetExtensionIdFromFrame(render_frame_host);
   if (extension_id.empty())
     extension_id = GURL(source).host();
 
@@ -93,7 +94,7 @@
 }
 
 void ChromeExtensionFrameHost::ContentScriptsExecuting(
-    const base::flat_map<std::string, std::vector<std::string>>&
+    const base::flat_map<ExtensionId, std::vector<std::string>>&
         extension_id_to_scripts,
     const GURL& frame_url) {
   ActivityLog::GetInstance(web_contents_->GetBrowserContext())
diff --git a/chrome/browser/extensions/chrome_extension_frame_host.h b/chrome/browser/extensions/chrome_extension_frame_host.h
index 0512bc8..f87df142 100644
--- a/chrome/browser/extensions/chrome_extension_frame_host.h
+++ b/chrome/browser/extensions/chrome_extension_frame_host.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_EXTENSIONS_CHROME_EXTENSION_FRAME_HOST_H_
 
 #include "extensions/browser/extension_frame_host.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/mojom/frame.mojom.h"
 #include "extensions/common/mojom/injection_type.mojom-shared.h"
 #include "extensions/common/mojom/run_location.mojom-shared.h"
@@ -27,7 +28,7 @@
 
   // mojom::LocalFrameHost:
   void RequestScriptInjectionPermission(
-      const std::string& extension_id,
+      const ExtensionId& extension_id,
       mojom::InjectionType script_type,
       mojom::RunLocation run_location,
       RequestScriptInjectionPermissionCallback callback) override;
@@ -41,7 +42,7 @@
       const StackTrace& stack_trace,
       blink::mojom::ConsoleMessageLevel level) override;
   void ContentScriptsExecuting(
-      const base::flat_map<std::string, std::vector<std::string>>&
+      const base::flat_map<ExtensionId, std::vector<std::string>>&
           extension_id_to_scripts,
       const GURL& frame_url) override;
 };
diff --git a/chrome/browser/extensions/chrome_extension_host_delegate.cc b/chrome/browser/extensions/chrome_extension_host_delegate.cc
index b9f07a7..d56c004 100644
--- a/chrome/browser/extensions/chrome_extension_host_delegate.cc
+++ b/chrome/browser/extensions/chrome_extension_host_delegate.cc
@@ -17,6 +17,7 @@
 #include "components/javascript_dialogs/app_modal_dialog_manager.h"
 #include "extensions/browser/extension_host.h"
 #include "extensions/browser/extension_system.h"
+#include "extensions/common/extension_id.h"
 
 namespace extensions {
 
@@ -45,7 +46,7 @@
 
 void ChromeExtensionHostDelegate::CreateTab(
     std::unique_ptr<content::WebContents> web_contents,
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     WindowOpenDisposition disposition,
     const blink::mojom::WindowFeatures& window_features,
     bool user_gesture) {
diff --git a/chrome/browser/extensions/chrome_extension_host_delegate.h b/chrome/browser/extensions/chrome_extension_host_delegate.h
index 41fd960a..dce1cba2 100644
--- a/chrome/browser/extensions/chrome_extension_host_delegate.h
+++ b/chrome/browser/extensions/chrome_extension_host_delegate.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_EXTENSIONS_CHROME_EXTENSION_HOST_DELEGATE_H_
 
 #include "extensions/browser/extension_host_delegate.h"
+#include "extensions/common/extension_id.h"
 
 namespace extensions {
 
@@ -20,7 +21,7 @@
   void OnMainFrameCreatedForBackgroundPage(ExtensionHost* host) override;
   content::JavaScriptDialogManager* GetJavaScriptDialogManager() override;
   void CreateTab(std::unique_ptr<content::WebContents> web_contents,
-                 const std::string& extension_id,
+                 const ExtensionId& extension_id,
                  WindowOpenDisposition disposition,
                  const blink::mojom::WindowFeatures& window_features,
                  bool user_gesture) override;
diff --git a/chrome/browser/extensions/chrome_extension_test_notification_observer.cc b/chrome/browser/extensions/chrome_extension_test_notification_observer.cc
index 3fb2997..863ef14 100644
--- a/chrome/browser/extensions/chrome_extension_test_notification_observer.cc
+++ b/chrome/browser/extensions/chrome_extension_test_notification_observer.cc
@@ -16,6 +16,7 @@
 #include "content/public/test/test_utils.h"
 #include "extensions/browser/process_manager.h"
 #include "extensions/common/extension.h"
+#include "extensions/common/extension_id.h"
 
 namespace extensions {
 
@@ -92,7 +93,7 @@
 }
 
 bool ChromeExtensionTestNotificationObserver::WaitForExtensionIdle(
-    const std::string& extension_id) {
+    const ExtensionId& extension_id) {
   ProcessManager* manager = ProcessManager::Get(GetBrowserContext());
   NotificationSet notification_set(manager);
   WaitForCondition(base::BindRepeating(&util::IsExtensionIdle, extension_id,
@@ -102,11 +103,11 @@
 }
 
 bool ChromeExtensionTestNotificationObserver::WaitForExtensionNotIdle(
-    const std::string& extension_id) {
+    const ExtensionId& extension_id) {
   ProcessManager* manager = ProcessManager::Get(GetBrowserContext());
   NotificationSet notification_set(manager);
   WaitForCondition(base::BindRepeating(
-                       [](const std::string& extension_id,
+                       [](const ExtensionId& extension_id,
                           content::BrowserContext* context) -> bool {
                          return !util::IsExtensionIdle(extension_id, context);
                        },
diff --git a/chrome/browser/extensions/chrome_extension_test_notification_observer.h b/chrome/browser/extensions/chrome_extension_test_notification_observer.h
index 6d830d08..54acf78 100644
--- a/chrome/browser/extensions/chrome_extension_test_notification_observer.h
+++ b/chrome/browser/extensions/chrome_extension_test_notification_observer.h
@@ -5,10 +5,9 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_CHROME_EXTENSION_TEST_NOTIFICATION_OBSERVER_H_
 #define CHROME_BROWSER_EXTENSIONS_CHROME_EXTENSION_TEST_NOTIFICATION_OBSERVER_H_
 
-#include <string>
-
 #include "base/memory/raw_ptr.h"
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/test/extension_test_notification_observer.h"
 
 class Browser;
@@ -42,10 +41,10 @@
   bool WaitForExtensionViewsToLoad();
 
   // Waits for extension to be idle.
-  bool WaitForExtensionIdle(const std::string& extension_id);
+  bool WaitForExtensionIdle(const ExtensionId& extension_id);
 
   // Waits for extension to be not idle.
-  bool WaitForExtensionNotIdle(const std::string& extension_id);
+  bool WaitForExtensionNotIdle(const ExtensionId& extension_id);
 
  private:
   content::BrowserContext* GetBrowserContext();
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc
index 1723445..5a6d3db1 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -91,6 +91,7 @@
 #include "extensions/browser/pref_names.h"
 #include "extensions/browser/updater/scoped_extension_updater_keep_alive.h"
 #include "extensions/browser/url_request_util.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/extension_urls.h"
 #include "extensions/common/features/feature_channel.h"
 #include "extensions/common/permissions/permission_set.h"
@@ -144,7 +145,7 @@
 };
 
 bool ShouldLogExtensionAction(content::BrowserContext* browser_context,
-                              const std::string& extension_id) {
+                              const ExtensionId& extension_id) {
   // We only send these IPCs if activity logging is enabled, but due to race
   // conditions (e.g. logging gets disabled but the renderer sends the message
   // before it gets updated), we still need this check here.
@@ -303,7 +304,7 @@
 }
 
 bool ChromeExtensionsBrowserClient::IsExtensionIncognitoEnabled(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     content::BrowserContext* context) const {
   return IsGuestSession(context) ||
          util::IsIncognitoEnabled(extension_id, context);
@@ -668,7 +669,7 @@
 }
 
 bool ChromeExtensionsBrowserClient::IsExtensionEnabled(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     content::BrowserContext* context) const {
   return ExtensionSystem::Get(context)->extension_service()->IsExtensionEnabled(
       extension_id);
@@ -722,7 +723,7 @@
 }
 
 bool ChromeExtensionsBrowserClient::HasIsolatedStorage(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     content::BrowserContext* context) {
   return util::HasIsolatedStorage(extension_id, context);
 }
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.h b/chrome/browser/extensions/chrome_extensions_browser_client.h
index d54faad8..fd17781a 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.h
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.h
@@ -99,7 +99,7 @@
 #endif
   bool IsGuestSession(content::BrowserContext* context) const override;
   bool IsExtensionIncognitoEnabled(
-      const std::string& extension_id,
+      const ExtensionId& extension_id,
       content::BrowserContext* context) const override;
   bool CanExtensionCrossIncognito(
       const Extension* extension,
@@ -180,7 +180,7 @@
   KioskDelegate* GetKioskDelegate() override;
   bool IsLockScreenContext(content::BrowserContext* context) override;
   std::string GetApplicationLocale() override;
-  bool IsExtensionEnabled(const std::string& extension_id,
+  bool IsExtensionEnabled(const ExtensionId& extension_id,
                           content::BrowserContext* context) const override;
   bool IsWebUIAllowedToMakeNetworkRequests(const url::Origin& origin) override;
   network::mojom::NetworkContext* GetSystemNetworkContext() override;
@@ -192,7 +192,7 @@
   base::FilePath GetSaveFilePath(content::BrowserContext* context) override;
   void SetLastSaveFilePath(content::BrowserContext* context,
                            const base::FilePath& path) override;
-  bool HasIsolatedStorage(const std::string& extension_id,
+  bool HasIsolatedStorage(const ExtensionId& extension_id,
                           content::BrowserContext* context) override;
   bool IsScreenshotRestricted(
       content::WebContents* web_contents) const override;
diff --git a/chrome/browser/extensions/chrome_url_request_util.cc b/chrome/browser/extensions/chrome_url_request_util.cc
index 21fde7c..5804dfd5 100644
--- a/chrome/browser/extensions/chrome_url_request_util.cc
+++ b/chrome/browser/extensions/chrome_url_request_util.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/extensions/chrome_url_request_util.h"
 
 #include <memory>
+#include <string>
 #include <utility>
 
 #include "base/files/file_path.h"
@@ -21,6 +22,7 @@
 #include "extensions/browser/extension_protocols.h"
 #include "extensions/browser/extensions_browser_client.h"
 #include "extensions/browser/url_request_util.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/file_util.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -55,7 +57,7 @@
 
 scoped_refptr<base::RefCountedMemory> GetResource(
     int resource_id,
-    const std::string& extension_id) {
+    const extensions::ExtensionId& extension_id) {
   const ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   scoped_refptr<base::RefCountedMemory> bytes =
       rb.LoadDataResourceBytes(resource_id);
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index 197b71bd..14440c4a 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -47,6 +47,7 @@
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_features.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/extension_l10n_util.h"
 #include "extensions/common/file_util.h"
 #include "extensions/common/manifest_constants.h"
@@ -98,13 +99,13 @@
 bool g_enable_help_app = true;
 #endif
 
-std::string GenerateId(const base::Value::Dict& manifest,
+ExtensionId GenerateId(const base::Value::Dict& manifest,
                        const base::FilePath& path) {
   std::string id_input;
   const std::string* raw_key = manifest.FindString(manifest_keys::kPublicKey);
   CHECK(raw_key != nullptr);
   CHECK(Extension::ParsePEMKeyBytes(*raw_key, &id_input));
-  std::string id = crx_file::id_util::GenerateId(id_input);
+  ExtensionId id = crx_file::id_util::GenerateId(id_input);
   return id;
 }
 
@@ -221,7 +222,7 @@
   return std::move(*manifest).TakeDict();
 }
 
-std::string ComponentLoader::Add(int manifest_resource_id,
+ExtensionId ComponentLoader::Add(int manifest_resource_id,
                                  const base::FilePath& root_directory) {
   if (!ignore_allowlist_for_testing_ &&
       !IsComponentExtensionAllowlisted(manifest_resource_id)) {
@@ -234,17 +235,17 @@
   return Add(manifest_contents, root_directory, true);
 }
 
-std::string ComponentLoader::Add(base::Value::Dict manifest,
+ExtensionId ComponentLoader::Add(base::Value::Dict manifest,
                                  const base::FilePath& root_directory) {
   return Add(std::move(manifest), root_directory, false);
 }
 
-std::string ComponentLoader::Add(const base::StringPiece& manifest_contents,
+ExtensionId ComponentLoader::Add(const base::StringPiece& manifest_contents,
                                  const base::FilePath& root_directory) {
   return Add(manifest_contents, root_directory, false);
 }
 
-std::string ComponentLoader::Add(const base::StringPiece& manifest_contents,
+ExtensionId ComponentLoader::Add(const base::StringPiece& manifest_contents,
                                  const base::FilePath& root_directory,
                                  bool skip_allowlist) {
   // The Value is kept for the lifetime of the ComponentLoader. This is
@@ -256,7 +257,7 @@
   return std::string();
 }
 
-std::string ComponentLoader::Add(base::Value::Dict parsed_manifest,
+ExtensionId ComponentLoader::Add(base::Value::Dict parsed_manifest,
                                  const base::FilePath& root_directory,
                                  bool skip_allowlist) {
   ComponentExtensionInfo info(std::move(parsed_manifest), root_directory);
@@ -273,7 +274,7 @@
   return added_info.extension_id;
 }
 
-std::string ComponentLoader::AddOrReplace(const base::FilePath& path) {
+ExtensionId ComponentLoader::AddOrReplace(const base::FilePath& path) {
   base::FilePath absolute_path = base::MakeAbsoluteFilePath(path);
   std::string error;
   std::optional<base::Value::Dict> manifest(
@@ -290,7 +291,7 @@
   return Add(std::move(*manifest), absolute_path, true);
 }
 
-void ComponentLoader::Reload(const std::string& extension_id) {
+void ComponentLoader::Reload(const ExtensionId& extension_id) {
   for (const auto& component_extension : component_extensions_) {
     if (component_extension.extension_id == extension_id) {
       Load(component_extension);
@@ -322,7 +323,7 @@
   }
 }
 
-void ComponentLoader::Remove(const std::string& id) {
+void ComponentLoader::Remove(const ExtensionId& id) {
   for (auto it = component_extensions_.begin();
        it != component_extensions_.end(); ++it) {
     if (it->extension_id == id) {
@@ -333,7 +334,7 @@
   }
 }
 
-bool ComponentLoader::Exists(const std::string& id) const {
+bool ComponentLoader::Exists(const ExtensionId& id) const {
   for (const auto& component_extension : component_extensions_) {
     if (component_extension.extension_id == id) {
       return true;
@@ -342,9 +343,9 @@
   return false;
 }
 
-std::vector<std::string> ComponentLoader::GetRegisteredComponentExtensionsIds()
+std::vector<ExtensionId> ComponentLoader::GetRegisteredComponentExtensionsIds()
     const {
-  std::vector<std::string> result;
+  std::vector<ExtensionId> result;
   for (const auto& el : component_extensions_) {
     result.push_back(el.extension_id);
   }
diff --git a/chrome/browser/extensions/component_loader.h b/chrome/browser/extensions/component_loader.h
index 322567a..77a9a006 100644
--- a/chrome/browser/extensions/component_loader.h
+++ b/chrome/browser/extensions/component_loader.h
@@ -22,6 +22,7 @@
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/common/buildflags.h"
+#include "extensions/common/extension_id.h"
 
 class Profile;
 
@@ -58,29 +59,29 @@
   //
   //   ssh-keygen -t rsa -b 1024 -N '' -f /tmp/key.pem
   //   openssl rsa -pubout -outform DER < /tmp/key.pem 2>/dev/null | base64 -w 0
-  std::string Add(const base::StringPiece& manifest_contents,
+  ExtensionId Add(const base::StringPiece& manifest_contents,
                   const base::FilePath& root_directory);
 
   // Convenience method for registering a component extension by resource id.
-  std::string Add(int manifest_resource_id,
+  ExtensionId Add(int manifest_resource_id,
                   const base::FilePath& root_directory);
 
   // Convenience method for registering a component extension by parsed
   // manifest.
-  std::string Add(base::Value::Dict manifest,
+  ExtensionId Add(base::Value::Dict manifest,
                   const base::FilePath& root_directory);
 
   // Loads a component extension from file system. Replaces previously added
   // extension with the same ID.
-  std::string AddOrReplace(const base::FilePath& path);
+  ExtensionId AddOrReplace(const base::FilePath& path);
 
   // Returns true if an extension with the specified id has been added.
-  bool Exists(const std::string& id) const;
+  bool Exists(const ExtensionId& id) const;
 
   // Unloads a component extension and removes it from the list of component
   // extensions to be loaded.
   void Remove(const base::FilePath& root_directory);
-  void Remove(const std::string& id);
+  void Remove(const ExtensionId& id);
 
   // Call this during test setup to load component extensions that have
   // background pages for testing, which could otherwise interfere with tests.
@@ -101,10 +102,10 @@
   void AddDefaultComponentExtensionsForKioskMode(bool skip_session_components);
 
   // Reloads a registered component extension.
-  void Reload(const std::string& extension_id);
+  void Reload(const ExtensionId& extension_id);
 
   // Return ids of all registered extensions.
-  std::vector<std::string> GetRegisteredComponentExtensionsIds() const;
+  std::vector<ExtensionId> GetRegisteredComponentExtensionsIds() const;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // Add a component extension from a specific directory. Assumes that the
@@ -166,7 +167,7 @@
     base::FilePath root_directory;
 
     // The component extension's ID.
-    std::string extension_id;
+    ExtensionId extension_id;
   };
 
   // Parses the given JSON manifest. Returns `std::nullopt` if it cannot be
@@ -174,10 +175,10 @@
   std::optional<base::Value::Dict> ParseManifest(
       base::StringPiece manifest_contents) const;
 
-  std::string Add(const base::StringPiece& manifest_contents,
+  ExtensionId Add(const base::StringPiece& manifest_contents,
                   const base::FilePath& root_directory,
                   bool skip_allowlist);
-  std::string Add(base::Value::Dict parsed_manifest,
+  ExtensionId Add(base::Value::Dict parsed_manifest,
                   const base::FilePath& root_directory,
                   bool skip_allowlist);
 
diff --git a/chrome/browser/extensions/context_menu_matcher_unittest.cc b/chrome/browser/extensions/context_menu_matcher_unittest.cc
index bca02f8..3d8d50d01 100644
--- a/chrome/browser/extensions/context_menu_matcher_unittest.cc
+++ b/chrome/browser/extensions/context_menu_matcher_unittest.cc
@@ -18,6 +18,7 @@
 #include "components/prefs/pref_service.h"
 #include "content/public/test/browser_task_environment.h"
 #include "extensions/browser/extension_registry.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/utils/extension_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "ui/base/models/simple_menu_model.h"
@@ -57,7 +58,7 @@
                                            int webview_instance_id,
                                            const std::string& string_id,
                                            bool visible) {
-    const std::string& extension_id = MaybeGetExtensionId(extension);
+    const ExtensionId& extension_id = MaybeGetExtensionId(extension);
     MenuItem::Id id(false, MenuItem::ExtensionKey(
                                extension_id, webview_embedder_process_id,
                                webview_embedder_frame_id, webview_instance_id));
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 1589224..8e23b85 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -56,6 +56,7 @@
 #include "extensions/browser/requirements_checker.h"
 #include "extensions/common/extension_features.h"
 #include "extensions/common/extension_icon_set.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/extension_urls.h"
 #include "extensions/common/file_util.h"
 #include "extensions/common/manifest.h"
@@ -202,7 +203,7 @@
   }
 }
 
-void CrxInstaller::InstallUnpackedCrx(const std::string& extension_id,
+void CrxInstaller::InstallUnpackedCrx(const ExtensionId& extension_id,
                                       const std::string& public_key,
                                       const base::FilePath& unpacked_dir) {
   ExtensionService* service = service_weak_.get();
@@ -258,7 +259,7 @@
 }
 
 void CrxInstaller::UpdateExtensionFromUnpackedCrx(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     const std::string& public_key,
     const base::FilePath& unpacked_dir) {
   ExtensionService* service = service_weak_.get();
@@ -943,7 +944,7 @@
   // lazily and based on the Extension's root path at that moment.
   // TODO(rdevlin.cronin): Continue removing std::string errors and replacing
   // with std::u16string
-  std::string extension_id = extension()->id();
+  ExtensionId extension_id = extension()->id();
   std::string error;
   extension_ = file_util::LoadExtension(
       version_dir, install_source_,
@@ -1074,7 +1075,7 @@
 void CrxInstaller::NotifyCrxInstallComplete(
     const std::optional<CrxInstallError>& error) {
   ReportInstallationStage(InstallationStage::kComplete);
-  const std::string extension_id =
+  const ExtensionId extension_id =
       expected_id_.empty() && extension() ? extension()->id() : expected_id_;
   InstallStageTracker* install_stage_tracker =
       InstallStageTracker::Get(profile_);
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h
index 18b041d..33a81ed 100644
--- a/chrome/browser/extensions/crx_installer.h
+++ b/chrome/browser/extensions/crx_installer.h
@@ -29,6 +29,7 @@
 #include "extensions/browser/preload_check.h"
 #include "extensions/browser/sandboxed_unpacker.h"
 #include "extensions/common/extension.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/manifest.h"
 
 class ExtensionServiceTest;
@@ -125,7 +126,7 @@
   // Install the unpacked crx in |unpacked_dir|.
   // If |delete_source_| is true, |unpacked_dir| will be removed at the end of
   // the installation.
-  void InstallUnpackedCrx(const std::string& extension_id,
+  void InstallUnpackedCrx(const ExtensionId& extension_id,
                           const std::string& public_key,
                           const base::FilePath& unpacked_dir);
 
@@ -137,7 +138,7 @@
   // |unpacked_dir|.
   // If |delete_source_| is true, |unpacked_dir| will be removed at the end of
   // the update.
-  void UpdateExtensionFromUnpackedCrx(const std::string& extension_id,
+  void UpdateExtensionFromUnpackedCrx(const ExtensionId& extension_id,
                                       const std::string& public_key,
                                       const base::FilePath& unpacked_dir);
 
@@ -163,8 +164,8 @@
     install_source_ = source;
   }
 
-  const std::string& expected_id() const { return expected_id_; }
-  void set_expected_id(const std::string& val) { expected_id_ = val; }
+  const ExtensionId& expected_id() const { return expected_id_; }
+  void set_expected_id(const ExtensionId& val) { expected_id_ = val; }
 
   // Expected SHA256 hash sum for the package.
   const std::string& expected_hash() const { return expected_hash_; }
@@ -412,7 +413,7 @@
 
   // For updates, external and webstore installs we have an ID we're expecting
   // the extension to contain.
-  std::string expected_id_;
+  ExtensionId expected_id_;
 
   // An expected hash sum for the .crx file.
   std::string expected_hash_;
diff --git a/chrome/browser/extensions/crx_installer_browsertest.cc b/chrome/browser/extensions/crx_installer_browsertest.cc
index e98b130..35758af 100644
--- a/chrome/browser/extensions/crx_installer_browsertest.cc
+++ b/chrome/browser/extensions/crx_installer_browsertest.cc
@@ -64,6 +64,7 @@
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/extension_features.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/feature_switch.h"
 #include "extensions/common/file_util.h"
 #include "extensions/common/permissions/api_permission.h"
@@ -102,11 +103,13 @@
   ~MockPromptProxy();
 
   bool did_succeed() const { return !extension_id_.empty(); }
-  const ExtensionId& extension_id() { return extension_id_; }
+  const extensions::ExtensionId& extension_id() { return extension_id_; }
   bool confirmation_requested() const { return confirmation_requested_; }
   const std::u16string& error() const { return error_; }
 
-  void set_extension_id(const std::string& id) { extension_id_ = id; }
+  void set_extension_id(const extensions::ExtensionId& id) {
+    extension_id_ = id;
+  }
   void set_confirmation_requested(bool requested) {
     confirmation_requested_ = requested;
   }
@@ -120,7 +123,7 @@
 
   // Data reported back to us by the prompt we created.
   bool confirmation_requested_;
-  ExtensionId extension_id_;
+  extensions::ExtensionId extension_id_;
   std::u16string error_;
 
   std::unique_ptr<ScopedTestDialogAutoConfirm> auto_confirm;
@@ -197,7 +200,7 @@
  protected:
   std::unique_ptr<WebstoreInstaller::Approval> GetApproval(
       const char* manifest_dir,
-      const std::string& id,
+      const extensions::ExtensionId& id,
       bool strict_manifest_checks) {
     std::unique_ptr<WebstoreInstaller::Approval> result;
 
@@ -214,7 +217,8 @@
         strict_manifest_checks);
   }
 
-  const Extension* GetInstalledExtension(const std::string& extension_id) {
+  const Extension* GetInstalledExtension(
+      const extensions::ExtensionId& extension_id) {
     return extension_registry()->GetInstalledExtension(extension_id);
   }
 
@@ -242,7 +246,7 @@
     return base::WriteFile(full_path, content);
   }
 
-  void AddExtension(const std::string& extension_id,
+  void AddExtension(const extensions::ExtensionId& extension_id,
                     const std::string& version) {
     base::ScopedTempDir temp_dir;
     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
@@ -298,7 +302,7 @@
   void RunCrxInstallerFromUnpackedDirectory(
       std::unique_ptr<ExtensionInstallPrompt> prompt,
       CrxInstaller::InstallerResultCallback callback,
-      const std::string& extension_id,
+      const extensions::ExtensionId& extension_id,
       const std::string& public_key,
       const base::FilePath& crx_directory) {
     base::RunLoop run_loop;
@@ -317,7 +321,7 @@
   }
 
   void RunUpdateExtension(std::unique_ptr<ExtensionInstallPrompt> prompt,
-                          const std::string& extension_id,
+                          const extensions::ExtensionId& extension_id,
                           const std::string& public_key,
                           const base::FilePath& unpacked_dir,
                           CrxInstaller::InstallerResultCallback callback) {
@@ -338,7 +342,7 @@
   // Installs a crx from |crx_relpath| (a path relative to the extension test
   // data dir) with expected id |id|.
   void InstallWithPrompt(const char* ext_relpath,
-                         const std::string& id,
+                         const extensions::ExtensionId& id,
                          CrxInstaller::InstallerResultCallback callback,
                          MockPromptProxy* mock_install_prompt) {
     base::FilePath ext_path = test_data_dir_.AppendASCII(ext_relpath);
@@ -574,7 +578,8 @@
 
   ASSERT_TRUE(InstallExtension(crx_path, 1));
 
-  const std::string extension_id("gllekhaobjnhgeagipipnkpmmmpchacm");
+  const extensions::ExtensionId extension_id(
+      "gllekhaobjnhgeagipipnkpmmmpchacm");
   ExtensionRegistry* registry = ExtensionRegistry::Get(browser()->profile());
   const Extension* extension =
       registry->enabled_extensions().GetByID(extension_id);
@@ -587,7 +592,8 @@
 
 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
                        InstallDelayedUntilNextUpdate) {
-  const std::string extension_id("ldnnhddmnhbkjipkidpdiheffobcpfmf");
+  const extensions::ExtensionId extension_id(
+      "ldnnhddmnhbkjipkidpdiheffobcpfmf");
   base::FilePath base_path = test_data_dir_.AppendASCII("delayed_install");
 
   ExtensionService* service = extension_service();
@@ -649,7 +655,8 @@
       new FakeSafeBrowsingDatabaseManager(true));
   ScopedDatabaseManagerForTest scoped_blocklist_db(blocklist_db);
 
-  const std::string extension_id = "gllekhaobjnhgeagipipnkpmmmpchacm";
+  const extensions::ExtensionId extension_id =
+      "gllekhaobjnhgeagipipnkpmmmpchacm";
   blocklist_db->SetUnsafe(extension_id);
 
   base::FilePath crx_path = test_data_dir_.AppendASCII("theme_hidpi_crx")
@@ -673,7 +680,7 @@
   // version of the manifest, but the downloaded .crx file is old since
   // the newly published version hasn't fully propagated to all the download
   // servers yet. So load the v2 manifest, but then install the v1 crx file.
-  std::string id = "ooklpoaelmiimcjipecogjfcejghbogp";
+  extensions::ExtensionId id = "ooklpoaelmiimcjipecogjfcejghbogp";
   std::unique_ptr<WebstoreInstaller::Approval> approval =
       GetApproval("crx_installer/v2_no_permission_change/", id, false);
 
@@ -693,7 +700,7 @@
   // version of the manifest, but the downloaded .crx file is old since
   // the newly published version hasn't fully propagated to all the download
   // servers yet. So load the v2 manifest, but then install the v1 crx file.
-  const std::string id = "ooklpoaelmiimcjipecogjfcejghbogp";
+  const extensions::ExtensionId id = "ooklpoaelmiimcjipecogjfcejghbogp";
   std::unique_ptr<WebstoreInstaller::Approval> approval =
       GetApproval("crx_installer/v2_no_permission_change/", id, false);
 
@@ -828,7 +835,8 @@
       CreateMockPromptProxyForBrowser(browser());
 
   // Update won't work as the extension doesn't exist.
-  const std::string extension_id = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
+  const extensions::ExtensionId extension_id =
+      "ldnnhddmnhbkjipkidpdiheffobcpfmf";
   const std::string public_key =
       "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8c4fBSPZ6utYoZ8NiWF/"
       "DSaimBhihjwgOsskyleFGaurhi3TDClTVSGPxNkgCzrz0wACML7M4aNjpd05qupdbR2d294j"
@@ -858,7 +866,8 @@
   std::unique_ptr<MockPromptProxy> mock_prompt =
       CreateMockPromptProxyForBrowser(browser());
 
-  const std::string extension_id = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
+  const extensions::ExtensionId extension_id =
+      "ldnnhddmnhbkjipkidpdiheffobcpfmf";
   const std::string public_key =
       "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8c4fBSPZ6utYoZ8NiWF/"
       "DSaimBhihjwgOsskyleFGaurhi3TDClTVSGPxNkgCzrz0wACML7M4aNjpd05qupdbR2d294j"
@@ -892,7 +901,8 @@
   std::unique_ptr<MockPromptProxy> mock_prompt =
       CreateMockPromptProxyForBrowser(browser());
 
-  const std::string extension_id = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
+  const extensions::ExtensionId extension_id =
+      "ldnnhddmnhbkjipkidpdiheffobcpfmf";
   const std::string public_key = "invalid public key";
 
   // Test updating an existing extension.
@@ -933,7 +943,8 @@
   std::unique_ptr<MockPromptProxy> mock_prompt =
       CreateMockPromptProxyForBrowser(browser());
 
-  const std::string extension_id = "gllekhaobjnhgeagipipnkpmmmpchacm";
+  const extensions::ExtensionId extension_id =
+      "gllekhaobjnhgeagipipnkpmmmpchacm";
   const std::string public_key =
       "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8c4fBSPZ6utYoZ8NiWF/"
       "DSaimBhihjwgOsskyleFGaurhi3TDClTVSGPxNkgCzrz0wACML7M4aNjpd05qupdbR2d294j"
@@ -1003,7 +1014,7 @@
   EXPECT_TRUE(cache_dir.GetPath().IsParent(extension_path));
   EXPECT_TRUE(base::PathExists(extension_path));
 
-  std::string extension_id = extension->id();
+  extensions::ExtensionId extension_id = extension->id();
   UninstallExtension(extension_id);
   ExtensionRegistry* registry = ExtensionRegistry::Get(browser()->profile());
   EXPECT_FALSE(registry->enabled_extensions().GetByID(extension_id));
@@ -1051,7 +1062,8 @@
 
   ExtensionService* service = extension_service();
 
-  const std::string extension_id("bdkapipdccfifhdghmblnenbbncfcpid");
+  const extensions::ExtensionId extension_id(
+      "bdkapipdccfifhdghmblnenbbncfcpid");
   {
     // Install extension.
     scoped_refptr<CrxInstaller> installer(CrxInstaller::CreateSilent(service));
diff --git a/chrome/browser/extensions/cws_info_service.cc b/chrome/browser/extensions/cws_info_service.cc
index 0ba6664b..c8fd26c75 100644
--- a/chrome/browser/extensions/cws_info_service.cc
+++ b/chrome/browser/extensions/cws_info_service.cc
@@ -312,25 +312,32 @@
 
   if (CanFetchInfo()) {
     base::TimeDelta elapsed_time =
-        base::Time::Now() - pref_service_->GetTime(prefs::kCWSInfoTimestamp);
-    // Enough time has elapsed since the last fetch.
-    bool data_refresh_needed =
-        elapsed_time >= base::Seconds(current_fetch_interval_secs_);
+        base::Time::Now() -
+        pref_service_->GetTime(prefs::kCWSInfoFetchErrorTimestamp);
+    // If there was a previous fetch error, wait a full fetch interval before
+    // retrying.
+    if (elapsed_time >= base::Seconds(current_fetch_interval_secs_)) {
+      elapsed_time =
+          base::Time::Now() - pref_service_->GetTime(prefs::kCWSInfoTimestamp);
+      // Enough time has elapsed since the last successful fetch.
+      bool data_refresh_needed =
+          elapsed_time >= base::Seconds(current_fetch_interval_secs_);
 
-    bool new_info_requested = false;
-    std::unique_ptr<FetchContext> fetch_context =
-        CreateRequests(new_info_requested);
+      bool new_info_requested = false;
+      std::unique_ptr<FetchContext> fetch_context =
+          CreateRequests(new_info_requested);
 
-    if ((data_refresh_needed || new_info_requested) && fetch_context) {
-      // Stop the check timer in case it is running. This can happen if we got
-      // here because of an out-of-cycle fetch.
-      info_check_timer_.Stop();
-      // Save the fetch context and send the (first) request.
-      active_fetch_ = std::move(fetch_context);
-      RecordNumRequestsInFetch(active_fetch_->requests.size());
-      current_fetch_interval_secs_ = GetNextFetchInterval();
-      SendRequest();
-      return;
+      if ((data_refresh_needed || new_info_requested) && fetch_context) {
+        // Stop the check timer in case it is running. This can happen if we got
+        // here because of an out-of-cycle fetch.
+        info_check_timer_.Stop();
+        // Save the fetch context and send the (first) request.
+        active_fetch_ = std::move(fetch_context);
+        RecordNumRequestsInFetch(active_fetch_->requests.size());
+        current_fetch_interval_secs_ = GetNextFetchInterval();
+        SendRequest();
+        return;
+      }
     }
   }
 
@@ -457,7 +464,13 @@
     error = true;
   }
 
-  if (!error) {
+  if (error) {
+    // Record the fetch error timestamp. This timestamp is used to
+    // wait at least one fetch interval after an error before
+    // attempting another fetch.
+    pref_service_->SetTime(prefs::kCWSInfoFetchErrorTimestamp,
+                           base::Time::Now());
+  } else {
     // Info response received without any errors. Remove the request object
     // from the request queue.
     active_fetch_->requests.pop();
@@ -571,4 +584,8 @@
   return pref_service_->GetTime(prefs::kCWSInfoTimestamp);
 }
 
+base::Time CWSInfoService::GetCWSInfoFetchErrorTimestampForTesting() const {
+  return pref_service_->GetTime(prefs::kCWSInfoFetchErrorTimestamp);
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/cws_info_service.h b/chrome/browser/extensions/cws_info_service.h
index b06ef7e9..db7b8d3 100644
--- a/chrome/browser/extensions/cws_info_service.h
+++ b/chrome/browser/extensions/cws_info_service.h
@@ -127,6 +127,7 @@
   int GetCheckIntervalForTesting() const;
   int GetFetchIntervalForTesting() const;
   base::Time GetCWSInfoTimestampForTesting() const;
+  base::Time GetCWSInfoFetchErrorTimestampForTesting() const;
   void SetMaxExtensionIdsPerRequestForTesting(int max);
 
  protected:
diff --git a/chrome/browser/extensions/cws_info_service_factory.cc b/chrome/browser/extensions/cws_info_service_factory.cc
index 44caac1..d2d9a22 100644
--- a/chrome/browser/extensions/cws_info_service_factory.cc
+++ b/chrome/browser/extensions/cws_info_service_factory.cc
@@ -61,6 +61,7 @@
 void CWSInfoServiceFactory::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterTimePref(prefs::kCWSInfoTimestamp, base::Time());
+  registry->RegisterTimePref(prefs::kCWSInfoFetchErrorTimestamp, base::Time());
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/cws_info_service_unittest.cc b/chrome/browser/extensions/cws_info_service_unittest.cc
index d39c6cdd..cdbe5ba6 100644
--- a/chrome/browser/extensions/cws_info_service_unittest.cc
+++ b/chrome/browser/extensions/cws_info_service_unittest.cc
@@ -22,6 +22,7 @@
 #include "extensions/browser/pref_names.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_builder.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/extension_urls.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
@@ -51,7 +52,7 @@
     test_url_loader_factory_.AddResponse(load_url.spec(), response);
   }
 
-  StoreMetadata BuildStoreMetadata(const std::string& extension_id,
+  StoreMetadata BuildStoreMetadata(const ExtensionId& extension_id,
                                    base::Time last_update_time);
   void VerifyCWSInfoRetrieved(
       const StoreMetadata* metadata,
@@ -71,7 +72,7 @@
     return cws_info_service_->info_check_timer_.GetCurrentDelay().InSeconds();
   }
 
-  static std::string GetNameFromId(const std::string& id) {
+  static std::string GetNameFromId(const ExtensionId& id) {
     return "items/" + id + "/storeMetadata";
   }
 
@@ -144,7 +145,7 @@
 }
 
 StoreMetadata CWSInfoServiceTest::BuildStoreMetadata(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     base::Time last_update_time) {
   StoreMetadata metadata;
   metadata.set_name(GetNameFromId(extension_id));
@@ -209,7 +210,7 @@
   EXPECT_EQ(0u, test_url_loader_factory_.pending_requests()->size());
 }
 
-TEST_F(CWSInfoServiceTest, IgnoresNetworkErrorAndBadServerResponse) {
+TEST_F(CWSInfoServiceTest, HandlesNetworkErrorAndBadServerResponse) {
   base::HistogramTester histogram_tester;
   scoped_refptr<const Extension> test1 =
       AddExtension("test1", /* updates_from_cws= */ true);
@@ -218,6 +219,7 @@
   cws_info_service_->CheckAndMaybeFetchInfo();
   task_environment_.FastForwardBy(base::Seconds(0));
 
+  // Verify an errored response was received.
   EXPECT_TRUE(VerifyStats(/*requests=*/1, /*responses=*/0, /*changes=*/0,
                           /*errors=*/1));
   histogram_tester.ExpectBucketCount(
@@ -226,7 +228,14 @@
   histogram_tester.ExpectBucketCount("Extensions.CWSInfoService.FetchSuccess",
                                      false, 1);
   EXPECT_TRUE(cws_info_service_->GetCWSInfo(*test1) == std::nullopt);
+  // Verify that the fetch error timestamp was recorded.
+  EXPECT_EQ(base::Time::Now(),
+            cws_info_service_->GetCWSInfoFetchErrorTimestampForTesting());
 
+  // After a response error, the next fetch request is only made after
+  // another fetch interval has elapsed. Advance the time by that amount.
+  task_environment_.FastForwardBy(
+      base::Seconds(cws_info_service_->GetFetchIntervalForTesting()));
   SetUpResponseWithData(GURL(cws_info_service_->GetRequestURLForTesting()),
                         "bad response");
   cws_info_service_->CheckAndMaybeFetchInfo();
@@ -357,17 +366,25 @@
       GURL(cws_info_service_->GetRequestURLForTesting()));
   task_environment_.FastForwardBy(
       base::Seconds(cws_info_service_->GetStartupDelayForTesting()));
+  // Verify that a request was sent and an errored response was received.
   EXPECT_TRUE(VerifyStats(/*requests=*/1, /*responses=*/0, /*changes=*/0,
                           /*errors=*/1));
-
   // Verify that the subsequent info check is scheduled with the regular check
   // interval.
   EXPECT_EQ(cws_info_service_->GetCheckIntervalForTesting(),
             GetTimerCurrentDelay());
+
+  // Advance the time by check interval and verify that a request is not sent
+  // because of the previous fetch response error.
   task_environment_.FastForwardBy(
       base::Seconds(cws_info_service_->GetCheckIntervalForTesting()));
-  EXPECT_TRUE(VerifyStats(/*requests=*/2, /*responses=*/0, /*changes=*/0,
-                          /*errors=*/2));
+  EXPECT_TRUE(VerifyStats(/*requests=*/1, /*responses=*/0, /*changes=*/0,
+                          /*errors=*/1));
+  // Check that nothing was written to extension prefs.
+  EXPECT_EQ(base::Time(), cws_info_service_->GetCWSInfoTimestampForTesting());
+
+  // Verify that the subsequent info check is scheduled with the regular check
+  // interval.
   EXPECT_EQ(cws_info_service_->GetCheckIntervalForTesting(),
             GetTimerCurrentDelay());
 
@@ -380,23 +397,22 @@
   ASSERT_TRUE(!response_str.empty());
   SetUpResponseWithData(GURL(cws_info_service_->GetRequestURLForTesting()),
                         response_str);
+  // Forward time by the fetch interval since CWSInfoService will wait that
+  // long after a fetch error before sending another request.
   task_environment_.FastForwardBy(
-      base::Seconds(cws_info_service_->GetCheckIntervalForTesting()));
+      base::Seconds(cws_info_service_->GetFetchIntervalForTesting()));
   // Verify that the request was sent, response was received and the data was
   // saved to extension prefs.
-  EXPECT_TRUE(VerifyStats(/*requests=*/3, /*responses=*/1, /*changes=*/1,
-                          /*errors=*/2));
-  EXPECT_EQ(base::Time::Now(),
-            cws_info_service_->GetCWSInfoTimestampForTesting());
+  EXPECT_TRUE(VerifyStats(/*requests=*/2, /*responses=*/1, /*changes=*/1,
+                          /*errors=*/1));
+  EXPECT_NE(base::Time(), cws_info_service_->GetCWSInfoTimestampForTesting());
   // Verify that the next check is scheduled with the regular check interval.
   EXPECT_EQ(cws_info_service_->GetCheckIntervalForTesting(),
             GetTimerCurrentDelay());
 }
 
-// The service only makes requests to the CWS server if:
-// - there are extensions that are missing the store metadata info OR
-// - enough time (fetch interval) has elapsed since the last update
-// This test verifies the latter condition.
+// If there are no new extensions installed, CWS Info is only
+// requested after a fetch interval has elapsed.
 TEST_F(CWSInfoServiceTest, UpdatesExistingInfoAtUpdateIntervals) {
   // Add an extension to cause queries to CWS.
   scoped_refptr<const Extension> test1 =
diff --git a/chrome/browser/extensions/event_router_forwarder.cc b/chrome/browser/extensions/event_router_forwarder.cc
index 7aeb076..abce638 100644
--- a/chrome/browser/extensions/event_router_forwarder.cc
+++ b/chrome/browser/extensions/event_router_forwarder.cc
@@ -17,6 +17,7 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/browser/event_router.h"
+#include "extensions/common/extension_id.h"
 #include "url/gurl.h"
 
 using content::BrowserThread;
@@ -55,7 +56,7 @@
 }
 
 void EventRouterForwarder::HandleEvent(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     events::HistogramValue histogram_value,
     const std::string& event_name,
     base::Value::List event_args,
@@ -121,7 +122,7 @@
 
 void EventRouterForwarder::CallEventRouter(
     Profile* profile,
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     events::HistogramValue histogram_value,
     const std::string& event_name,
     base::Value::List event_args,
diff --git a/chrome/browser/extensions/event_router_forwarder.h b/chrome/browser/extensions/event_router_forwarder.h
index 49aa1f5..2115388 100644
--- a/chrome/browser/extensions/event_router_forwarder.h
+++ b/chrome/browser/extensions/event_router_forwarder.h
@@ -11,6 +11,7 @@
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
 #include "extensions/browser/extension_event_histogram_value.h"
+#include "extensions/common/extension_id.h"
 
 class GURL;
 
@@ -61,7 +62,7 @@
 
   // Helper function for {Broadcast,Dispatch}EventTo{Extension,Renderers}.
   // Virtual for testing.
-  virtual void HandleEvent(const std::string& extension_id,
+  virtual void HandleEvent(const ExtensionId& extension_id,
                            events::HistogramValue histogram_value,
                            const std::string& event_name,
                            base::Value::List event_args,
@@ -75,7 +76,7 @@
   // |profile| may never be NULL.
   // Virtual for testing.
   virtual void CallEventRouter(Profile* profile,
-                               const std::string& extension_id,
+                               const ExtensionId& extension_id,
                                events::HistogramValue histogram_value,
                                const std::string& event_name,
                                base::Value::List event_args,
diff --git a/chrome/browser/extensions/event_router_forwarder_unittest.cc b/chrome/browser/extensions/event_router_forwarder_unittest.cc
index e336f9b..6687cf7 100644
--- a/chrome/browser/extensions/event_router_forwarder_unittest.cc
+++ b/chrome/browser/extensions/event_router_forwarder_unittest.cc
@@ -18,6 +18,7 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/browser_task_environment.h"
+#include "extensions/common/extension_id.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -40,7 +41,7 @@
                     const GURL&));
 
   void CallEventRouter(Profile* profile,
-                       const std::string& extension_id,
+                       const ExtensionId& extension_id,
                        events::HistogramValue histogram_value,
                        const std::string& event_name,
                        base::Value::List args,
diff --git a/chrome/browser/extensions/extension_action_runner.cc b/chrome/browser/extensions/extension_action_runner.cc
index fcad287d..9eadc17 100644
--- a/chrome/browser/extensions/extension_action_runner.cc
+++ b/chrome/browser/extensions/extension_action_runner.cc
@@ -339,7 +339,7 @@
 }
 
 void ExtensionActionRunner::OnRequestScriptInjectionPermission(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     mojom::InjectionType script_type,
     mojom::RunLocation run_location,
     mojom::LocalFrameHost::RequestScriptInjectionPermissionCallback callback) {
diff --git a/chrome/browser/extensions/extension_action_runner.h b/chrome/browser/extensions/extension_action_runner.h
index 9c888d3..78f3123 100644
--- a/chrome/browser/extensions/extension_action_runner.h
+++ b/chrome/browser/extensions/extension_action_runner.h
@@ -10,7 +10,6 @@
 #include <map>
 #include <optional>
 #include <set>
-#include <string>
 #include <vector>
 
 #include "base/functional/callback.h"
@@ -121,7 +120,7 @@
   // Handles mojom::LocalFrameHost::RequestScriptInjectionPermission(). It
   // replies back with |callback|.
   void OnRequestScriptInjectionPermission(
-      const std::string& extension_id,
+      const ExtensionId& extension_id,
       mojom::InjectionType script_type,
       mojom::RunLocation run_location,
       mojom::LocalFrameHost::RequestScriptInjectionPermissionCallback callback);
@@ -164,7 +163,7 @@
   };
 
   using PendingScriptList = std::vector<std::unique_ptr<PendingScript>>;
-  using PendingScriptMap = std::map<std::string, PendingScriptList>;
+  using PendingScriptMap = std::map<ExtensionId, PendingScriptList>;
 
   // Returns true if the extension requesting script injection requires
   // user consent. If this is true, the caller should then register a request
@@ -224,13 +223,13 @@
   PendingScriptMap pending_scripts_;
 
   // A set of ids for which the webRequest API was blocked on the page.
-  std::set<std::string> web_request_blocked_;
+  std::set<ExtensionId> web_request_blocked_;
 
   // The extensions which have been granted permission to run on the given page.
   // TODO(rdevlin.cronin): Right now, this just keeps track of extensions that
   // have been permitted to run on the page via this interface. Instead, it
   // should incorporate more fully with ActiveTab.
-  std::set<std::string> permitted_extensions_;
+  std::set<ExtensionId> permitted_extensions_;
 
   // If true, ignore active tab being granted rather than running pending
   // actions.
diff --git a/chrome/browser/extensions/extension_action_runner_unittest.cc b/chrome/browser/extensions/extension_action_runner_unittest.cc
index af1d21d..a29b7dc 100644
--- a/chrome/browser/extensions/extension_action_runner_unittest.cc
+++ b/chrome/browser/extensions/extension_action_runner_unittest.cc
@@ -28,6 +28,7 @@
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/extension_features.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/manifest.h"
 #include "extensions/common/mojom/injection_type.mojom-shared.h"
 #include "extensions/common/mojom/run_location.mojom-shared.h"
@@ -72,17 +73,17 @@
                         mojom::RunLocation run_location);
 
   // Returns the number of times a given extension has had a script execute.
-  size_t GetExecutionCountForExtension(const std::string& extension_id) const;
+  size_t GetExecutionCountForExtension(const ExtensionId& extension_id) const;
 
   ExtensionActionRunner* runner() const { return extension_action_runner_; }
 
  private:
   // Returns a closure to use as a script execution for a given extension.
   ExtensionActionRunner::ScriptInjectionCallback
-  GetExecutionCallbackForExtension(const std::string& extension_id);
+  GetExecutionCallbackForExtension(const ExtensionId& extension_id);
 
   // Increment the number of executions for the given |extension_id|.
-  void IncrementExecutionCount(const std::string& extension_id, bool granted);
+  void IncrementExecutionCount(const ExtensionId& extension_id, bool granted);
 
   void SetUp() override;
 
@@ -91,7 +92,7 @@
       nullptr;
 
   // The map of observed executions, keyed by extension id.
-  std::map<std::string, int> extension_executions_;
+  std::map<ExtensionId, int> extension_executions_;
 
   scoped_refptr<const Extension> extension_;
 };
@@ -100,7 +101,7 @@
 ExtensionActionRunnerUnitTest::~ExtensionActionRunnerUnitTest() = default;
 
 const Extension* ExtensionActionRunnerUnitTest::AddExtension() {
-  const std::string kId = crx_file::id_util::GenerateId("all_hosts_extension");
+  const ExtensionId kId = crx_file::id_util::GenerateId("all_hosts_extension");
   extension_ =
       ExtensionBuilder()
           .SetManifest(base::Value::Dict()
@@ -151,7 +152,7 @@
 }
 
 size_t ExtensionActionRunnerUnitTest::GetExecutionCountForExtension(
-    const std::string& extension_id) const {
+    const ExtensionId& extension_id) const {
   auto iter = extension_executions_.find(extension_id);
   if (iter != extension_executions_.end())
     return iter->second;
@@ -160,7 +161,7 @@
 
 ExtensionActionRunner::ScriptInjectionCallback
 ExtensionActionRunnerUnitTest::GetExecutionCallbackForExtension(
-    const std::string& extension_id) {
+    const ExtensionId& extension_id) {
   // We use base unretained here, but if this ever gets executed outside of
   // this test's lifetime, we have a major problem anyway.
   return base::BindOnce(&ExtensionActionRunnerUnitTest::IncrementExecutionCount,
@@ -168,7 +169,7 @@
 }
 
 void ExtensionActionRunnerUnitTest::IncrementExecutionCount(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     bool granted) {
   if (!granted)
     return;
diff --git a/chrome/browser/extensions/extension_action_storage_manager.cc b/chrome/browser/extensions/extension_action_storage_manager.cc
index df0462a..bbefb6ce 100644
--- a/chrome/browser/extensions/extension_action_storage_manager.cc
+++ b/chrome/browser/extensions/extension_action_storage_manager.cc
@@ -18,6 +18,7 @@
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/state_store.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/extension_id.h"
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
@@ -246,7 +247,7 @@
 }
 
 void ExtensionActionStorageManager::ReadFromStorage(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     std::optional<base::Value> value) {
   const Extension* extension = ExtensionRegistry::Get(browser_context_)->
       enabled_extensions().GetByID(extension_id);
diff --git a/chrome/browser/extensions/extension_action_storage_manager.h b/chrome/browser/extensions/extension_action_storage_manager.h
index b79ddf2..0f35a9dd 100644
--- a/chrome/browser/extensions/extension_action_storage_manager.h
+++ b/chrome/browser/extensions/extension_action_storage_manager.h
@@ -14,6 +14,7 @@
 #include "extensions/browser/extension_action.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_observer.h"
+#include "extensions/common/extension_id.h"
 
 namespace content {
 class BrowserContext;
@@ -48,7 +49,7 @@
 
   // Reads/Writes the ExtensionAction's default values to/from storage.
   void WriteToStorage(ExtensionAction* extension_action);
-  void ReadFromStorage(const std::string& extension_id,
+  void ReadFromStorage(const ExtensionId& extension_id,
                        std::optional<base::Value> value);
 
   // Returns the Extensions StateStore for the |browser_context_|.
diff --git a/chrome/browser/extensions/extension_allowlist.cc b/chrome/browser/extensions/extension_allowlist.cc
index cbfd270c..3ac8dbb 100644
--- a/chrome/browser/extensions/extension_allowlist.cc
+++ b/chrome/browser/extensions/extension_allowlist.cc
@@ -15,6 +15,7 @@
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/common/extension_features.h"
+#include "extensions/common/extension_id.h"
 
 namespace extensions {
 
@@ -96,7 +97,7 @@
 }
 
 AllowlistState ExtensionAllowlist::GetExtensionAllowlistState(
-    const std::string& extension_id) const {
+    const ExtensionId& extension_id) const {
   int value = 0;
   if (!extension_prefs_->ReadPrefAsInteger(extension_id, kPrefAllowlist,
                                            &value)) {
@@ -112,7 +113,7 @@
 }
 
 void ExtensionAllowlist::SetExtensionAllowlistState(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     AllowlistState state) {
   DCHECK_NE(state, ALLOWLIST_UNDEFINED);
 
@@ -127,7 +128,7 @@
 
 AllowlistAcknowledgeState
 ExtensionAllowlist::GetExtensionAllowlistAcknowledgeState(
-    const std::string& extension_id) const {
+    const ExtensionId& extension_id) const {
   int value = 0;
   if (!extension_prefs_->ReadPrefAsInteger(extension_id,
                                            kPrefAllowlistAcknowledge, &value)) {
@@ -144,7 +145,7 @@
 }
 
 void ExtensionAllowlist::SetExtensionAllowlistAcknowledgeState(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     AllowlistAcknowledgeState state) {
   if (state != GetExtensionAllowlistAcknowledgeState(extension_id)) {
     extension_prefs_->SetIntegerPref(extension_id, kPrefAllowlistAcknowledge,
@@ -153,7 +154,7 @@
 }
 
 void ExtensionAllowlist::PerformActionBasedOnOmahaAttributes(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     const base::Value::Dict& attributes) {
   const base::Value* allowlist_value = attributes.Find("_esbAllowlist");
 
@@ -209,7 +210,7 @@
 }
 
 bool ExtensionAllowlist::ShouldDisplayWarning(
-    const std::string& extension_id) const {
+    const ExtensionId& extension_id) const {
   if (!warnings_enabled_)
     return false;  // No warnings should be shown.
 
@@ -229,7 +230,7 @@
   return true;
 }
 
-void ExtensionAllowlist::OnExtensionInstalled(const std::string& extension_id,
+void ExtensionAllowlist::OnExtensionInstalled(const ExtensionId& extension_id,
                                               int install_flags) {
   // Check if a user clicked through the install friction and set the
   // acknowledge state accordingly.
@@ -255,7 +256,7 @@
 // `ApplyEnforcement` can be called when an extension becomes not allowlisted or
 // when the allowlist enforcement is activated (for already not allowlisted
 // extensions).
-void ExtensionAllowlist::ApplyEnforcement(const std::string& extension_id) {
+void ExtensionAllowlist::ApplyEnforcement(const ExtensionId& extension_id) {
   DCHECK(should_auto_disable_extensions_);
   DCHECK_EQ(GetExtensionAllowlistState(extension_id),
             ALLOWLIST_NOT_ALLOWLISTED);
@@ -354,7 +355,7 @@
 
 // ExtensionPrefsObserver::OnExtensionStateChanged override
 void ExtensionAllowlist::OnExtensionStateChanged(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     bool is_now_enabled) {
   // TODO(crbug.com/1192225): Can be removed when the bug is resolved. This
   // check is needed because `OnExtensionStateChanged` is called for all loaded
@@ -390,7 +391,7 @@
 }
 
 void ExtensionAllowlist::NotifyExtensionAllowlistWarningStateChanged(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     bool show_warning) {
   for (auto& observer : observers_) {
     observer.OnExtensionAllowlistWarningStateChanged(extension_id,
diff --git a/chrome/browser/extensions/extension_allowlist.h b/chrome/browser/extensions/extension_allowlist.h
index 639543e2..774fe4ad 100644
--- a/chrome/browser/extensions/extension_allowlist.h
+++ b/chrome/browser/extensions/extension_allowlist.h
@@ -12,6 +12,7 @@
 #include "extensions/browser/allowlist_state.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_prefs_observer.h"
+#include "extensions/common/extension_id.h"
 
 class Profile;
 
@@ -33,7 +34,7 @@
     // This can occur when an extension is included/excluded of the allowlist,
     // or when the user turns on/off the Enhanced Safe Browsing setting.
     virtual void OnExtensionAllowlistWarningStateChanged(
-        const std::string& extension_id,
+        const ExtensionId& extension_id,
         bool show_warning) {}
   };
 
@@ -54,33 +55,33 @@
 
   // Gets the Safe Browsing allowlist state.
   AllowlistState GetExtensionAllowlistState(
-      const std::string& extension_id) const;
+      const ExtensionId& extension_id) const;
 
   // Sets the Safe Browsing allowlist state.
-  void SetExtensionAllowlistState(const std::string& extension_id,
+  void SetExtensionAllowlistState(const ExtensionId& extension_id,
                                   AllowlistState state);
 
   // Gets the Safe Browsing allowlist acknowledge state.
   AllowlistAcknowledgeState GetExtensionAllowlistAcknowledgeState(
-      const std::string& extension_id) const;
+      const ExtensionId& extension_id) const;
 
   // Sets the Safe Browsing allowlist acknowledge state.
-  void SetExtensionAllowlistAcknowledgeState(const std::string& extension_id,
+  void SetExtensionAllowlistAcknowledgeState(const ExtensionId& extension_id,
                                              AllowlistAcknowledgeState state);
 
   // Performs action based on Omaha attributes for the extension.
-  void PerformActionBasedOnOmahaAttributes(const std::string& extension_id,
+  void PerformActionBasedOnOmahaAttributes(const ExtensionId& extension_id,
                                            const base::Value::Dict& attributes);
 
   // Whether a warning should be displayed for an extension, `true` if the
   // extension is not allowlisted and the allowlist is enforced.
-  bool ShouldDisplayWarning(const std::string& extension_id) const;
+  bool ShouldDisplayWarning(const ExtensionId& extension_id) const;
 
   // Informs the allowlist that a new extension was installed.
   //
   // `extension_id` is the id of the extension that was installed, and
   // `install_flags` is a bitmask of InstallFlags for the installation.
-  void OnExtensionInstalled(const std::string& extension_id, int install_flags);
+  void OnExtensionInstalled(const ExtensionId& extension_id, int install_flags);
 
   // Whether warnings should be shown for extensions not included in the
   // allowlist (considers Enhanced Safe Browsing setting and finch feature).
@@ -92,7 +93,7 @@
 
   // Apply the allowlist enforcement by disabling a not allowlisted extension if
   // allowed by policy.
-  void ApplyEnforcement(const std::string& extension_id);
+  void ApplyEnforcement(const ExtensionId& extension_id);
 
   // Blocklist all extensions with allowlist state `ALLOWLIST_NOT_ALLOWLISTED`.
   void ActivateAllowlistEnforcement();
@@ -108,11 +109,11 @@
   // Observes extension state changes to set
   // `ALLOWLIST_ACKNOWLEDGE_ENABLED_BY_USER` when a not allowlisted extension is
   // re-enabled by the user.
-  void OnExtensionStateChanged(const std::string& extension_id,
+  void OnExtensionStateChanged(const ExtensionId& extension_id,
                                bool is_now_enabled) override;
 
   void NotifyExtensionAllowlistWarningStateChanged(
-      const std::string& extension_id,
+      const ExtensionId& extension_id,
       bool show_warning);
 
   // Adds extension acknowledged events to Safe Browsing metrics collector for
diff --git a/chrome/browser/extensions/extension_allowlist_unittest.cc b/chrome/browser/extensions/extension_allowlist_unittest.cc
index ee599535..96a5213 100644
--- a/chrome/browser/extensions/extension_allowlist_unittest.cc
+++ b/chrome/browser/extensions/extension_allowlist_unittest.cc
@@ -17,6 +17,7 @@
 #include "extensions/browser/blocklist_extension_prefs.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/extension_features.h"
+#include "extensions/common/extension_id.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace extensions {
@@ -63,7 +64,7 @@
         safe_browsing::SafeBrowsingState::ENHANCED_PROTECTION);
   }
 
-  void PerformActionBasedOnOmahaAttributes(const std::string& extension_id,
+  void PerformActionBasedOnOmahaAttributes(const ExtensionId& extension_id,
                                            bool is_malware,
                                            bool is_allowlisted) {
     auto attributes = base::Value::Dict().Set("_esbAllowlist", is_allowlisted);
@@ -74,15 +75,15 @@
     service()->PerformActionBasedOnOmahaAttributes(extension_id, attributes);
   }
 
-  bool IsEnabled(const std::string& extension_id) {
+  bool IsEnabled(const ExtensionId& extension_id) {
     return registry()->enabled_extensions().Contains(extension_id);
   }
 
-  bool IsDisabled(const std::string& extension_id) {
+  bool IsDisabled(const ExtensionId& extension_id) {
     return registry()->disabled_extensions().Contains(extension_id);
   }
 
-  bool IsBlocklisted(const std::string& extension_id) {
+  bool IsBlocklisted(const ExtensionId& extension_id) {
     return registry()->blocklisted_extensions().Contains(extension_id);
   }
 
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index b49f7a15..6ef7a9b 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -76,6 +76,7 @@
 #include "extensions/browser/uninstall_reason.h"
 #include "extensions/browser/updater/extension_cache_fake.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/extension_set.h"
 #include "extensions/common/file_util.h"
 #include "extensions/common/manifest_constants.h"
@@ -484,7 +485,7 @@
 
   extension_service()->component_loader()->set_ignore_allowlist_for_testing(
       true);
-  std::string extension_id =
+  extensions::ExtensionId extension_id =
       extension_service()->component_loader()->Add(manifest, path);
   const Extension* extension =
       extension_registry()->enabled_extensions().GetByID(extension_id);
@@ -583,7 +584,7 @@
 }
 
 const Extension* ExtensionBrowserTest::UpdateExtensionWaitForIdle(
-    const std::string& id,
+    const extensions::ExtensionId& id,
     const base::FilePath& path,
     std::optional<int> expected_change) {
   return InstallOrUpdateExtension(id, path, INSTALL_UI_TYPE_NONE,
@@ -602,7 +603,7 @@
 }
 
 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
-    const std::string& id,
+    const extensions::ExtensionId& id,
     const base::FilePath& path,
     InstallUIType ui_type,
     std::optional<int> expected_change) {
@@ -612,7 +613,7 @@
 }
 
 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
-    const std::string& id,
+    const extensions::ExtensionId& id,
     const base::FilePath& path,
     InstallUIType ui_type,
     std::optional<int> expected_change,
@@ -624,7 +625,7 @@
 }
 
 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
-    const std::string& id,
+    const extensions::ExtensionId& id,
     const base::FilePath& path,
     InstallUIType ui_type,
     std::optional<int> expected_change,
@@ -635,7 +636,7 @@
 }
 
 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
-    const std::string& id,
+    const extensions::ExtensionId& id,
     const base::FilePath& path,
     InstallUIType ui_type,
     std::optional<int> expected_change,
@@ -736,7 +737,8 @@
   return registry->enabled_extensions().GetByID(installer->extension()->id());
 }
 
-void ExtensionBrowserTest::ReloadExtension(const std::string& extension_id) {
+void ExtensionBrowserTest::ReloadExtension(
+    const extensions::ExtensionId& extension_id) {
   const Extension* extension =
       extension_registry()->GetInstalledExtension(extension_id);
   ASSERT_TRUE(extension);
@@ -752,22 +754,26 @@
   observer_->WaitForExtensionViewsToLoad();
 }
 
-void ExtensionBrowserTest::UnloadExtension(const std::string& extension_id) {
+void ExtensionBrowserTest::UnloadExtension(
+    const extensions::ExtensionId& extension_id) {
   extension_service()->UnloadExtension(extension_id,
                                        UnloadedExtensionReason::DISABLE);
 }
 
-void ExtensionBrowserTest::UninstallExtension(const std::string& extension_id) {
+void ExtensionBrowserTest::UninstallExtension(
+    const extensions::ExtensionId& extension_id) {
   extension_service()->UninstallExtension(
       extension_id, UNINSTALL_REASON_FOR_TESTING, nullptr);
 }
 
-void ExtensionBrowserTest::DisableExtension(const std::string& extension_id) {
+void ExtensionBrowserTest::DisableExtension(
+    const extensions::ExtensionId& extension_id) {
   extension_service()->DisableExtension(extension_id,
                                         disable_reason::DISABLE_USER_ACTION);
 }
 
-void ExtensionBrowserTest::EnableExtension(const std::string& extension_id) {
+void ExtensionBrowserTest::EnableExtension(
+    const extensions::ExtensionId& extension_id) {
   extension_service()->EnableExtension(extension_id);
 }
 
@@ -833,7 +839,7 @@
 }
 
 base::Value ExtensionBrowserTest::ExecuteScriptInBackgroundPage(
-    const std::string& extension_id,
+    const extensions::ExtensionId& extension_id,
     const std::string& script,
     browsertest_util::ScriptUserActivation script_user_activation) {
   return browsertest_util::ExecuteScriptInBackgroundPage(
@@ -841,7 +847,7 @@
 }
 
 std::string ExtensionBrowserTest::ExecuteScriptInBackgroundPageDeprecated(
-    const std::string& extension_id,
+    const extensions::ExtensionId& extension_id,
     const std::string& script,
     browsertest_util::ScriptUserActivation script_user_activation) {
   return browsertest_util::ExecuteScriptInBackgroundPageDeprecated(
@@ -849,7 +855,7 @@
 }
 
 bool ExtensionBrowserTest::ExecuteScriptInBackgroundPageNoWait(
-    const std::string& extension_id,
+    const extensions::ExtensionId& extension_id,
     const std::string& script,
     browsertest_util::ScriptUserActivation script_user_activation) {
   return browsertest_util::ExecuteScriptInBackgroundPageNoWait(
diff --git a/chrome/browser/extensions/extension_browsertest.h b/chrome/browser/extensions/extension_browsertest.h
index 0158180..6550796 100644
--- a/chrome/browser/extensions/extension_browsertest.h
+++ b/chrome/browser/extensions/extension_browsertest.h
@@ -33,6 +33,7 @@
 #include "extensions/browser/sandboxed_unpacker.h"
 #include "extensions/browser/scoped_ignore_content_verifier_for_test.h"
 #include "extensions/common/extension.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/feature_switch.h"
 #include "extensions/common/features/feature_channel.h"
 #include "extensions/common/manifest.h"
@@ -132,7 +133,7 @@
     return ExtensionRegistry::Get(profile());
   }
 
-  const std::string& last_loaded_extension_id() {
+  const extensions::ExtensionId& last_loaded_extension_id() {
     return last_loaded_extension_id_;
   }
 
@@ -248,7 +249,7 @@
 
   // Same as above but passes an id to CrxInstaller and does not allow a
   // privilege increase.
-  const Extension* UpdateExtension(const std::string& id,
+  const Extension* UpdateExtension(const extensions::ExtensionId& id,
                                    const base::FilePath& path,
                                    std::optional<int> expected_change) {
     return InstallOrUpdateExtension(id, path, INSTALL_UI_TYPE_NONE,
@@ -257,7 +258,7 @@
 
   // Same as UpdateExtension but waits for the extension to be idle first.
   const Extension* UpdateExtensionWaitForIdle(
-      const std::string& id,
+      const extensions::ExtensionId& id,
       const base::FilePath& path,
       std::optional<int> expected_change);
 
@@ -286,15 +287,15 @@
         std::string(), path, INSTALL_UI_TYPE_CANCEL, 0);
   }
 
-  void ReloadExtension(const std::string& extension_id);
+  void ReloadExtension(const extensions::ExtensionId& extension_id);
 
-  void UnloadExtension(const std::string& extension_id);
+  void UnloadExtension(const extensions::ExtensionId& extension_id);
 
-  void UninstallExtension(const std::string& extension_id);
+  void UninstallExtension(const extensions::ExtensionId& extension_id);
 
-  void DisableExtension(const std::string& extension_id);
+  void DisableExtension(const extensions::ExtensionId& extension_id);
 
-  void EnableExtension(const std::string& extension_id);
+  void EnableExtension(const extensions::ExtensionId& extension_id);
 
   // Wait for the number of visible page actions to change to |count|.
   bool WaitForPageActionVisibilityChangeTo(int count) {
@@ -307,12 +308,12 @@
   }
 
   // Wait for the extension to be idle.
-  bool WaitForExtensionIdle(const std::string& extension_id) {
+  bool WaitForExtensionIdle(const extensions::ExtensionId& extension_id) {
     return observer_->WaitForExtensionIdle(extension_id);
   }
 
   // Wait for the extension to not be idle.
-  bool WaitForExtensionNotIdle(const std::string& extension_id) {
+  bool WaitForExtensionNotIdle(const extensions::ExtensionId& extension_id) {
     return observer_->WaitForExtensionNotIdle(extension_id);
   }
 
@@ -346,7 +347,7 @@
   // if executing the script fails. The argument `script_user_activation`
   // determines if the script should be executed after a user activation.
   base::Value ExecuteScriptInBackgroundPage(
-      const std::string& extension_id,
+      const extensions::ExtensionId& extension_id,
       const std::string& script,
       browsertest_util::ScriptUserActivation script_user_activation =
           browsertest_util::ScriptUserActivation::kDontActivate);
@@ -358,13 +359,13 @@
   // fails. The argument |script_user_activation| determines if the script
   // should be executed after a user activation.
   std::string ExecuteScriptInBackgroundPageDeprecated(
-      const std::string& extension_id,
+      const extensions::ExtensionId& extension_id,
       const std::string& script,
       browsertest_util::ScriptUserActivation script_user_activation =
           browsertest_util::ScriptUserActivation::kDontActivate);
 
   bool ExecuteScriptInBackgroundPageNoWait(
-      const std::string& extension_id,
+      const extensions::ExtensionId& extension_id,
       const std::string& script,
       browsertest_util::ScriptUserActivation script_user_activation =
           browsertest_util::ScriptUserActivation::kDontActivate);
@@ -409,25 +410,25 @@
     INSTALL_UI_TYPE_AUTO_CONFIRM,
   };
 
-  const Extension* InstallOrUpdateExtension(const std::string& id,
+  const Extension* InstallOrUpdateExtension(const extensions::ExtensionId& id,
                                             const base::FilePath& path,
                                             InstallUIType ui_type,
                                             std::optional<int> expected_change);
   const Extension* InstallOrUpdateExtension(
-      const std::string& id,
+      const extensions::ExtensionId& id,
       const base::FilePath& path,
       InstallUIType ui_type,
       std::optional<int> expected_change,
       Browser* browser,
       Extension::InitFromValueFlags creation_flags);
   const Extension* InstallOrUpdateExtension(
-      const std::string& id,
+      const extensions::ExtensionId& id,
       const base::FilePath& path,
       InstallUIType ui_type,
       std::optional<int> expected_change,
       mojom::ManifestLocation install_source);
   const Extension* InstallOrUpdateExtension(
-      const std::string& id,
+      const extensions::ExtensionId& id,
       const base::FilePath& path,
       InstallUIType ui_type,
       std::optional<int> expected_change,
@@ -486,7 +487,7 @@
   base::ScopedObservation<ExtensionRegistry, ExtensionRegistryObserver>
       registry_observation_{this};
 
-  std::string last_loaded_extension_id_;
+  extensions::ExtensionId last_loaded_extension_id_;
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc
index ce8956f..ef9adf0 100644
--- a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc
+++ b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc
@@ -32,6 +32,7 @@
 #include "extensions/browser/process_map.h"
 #include "extensions/browser/test_extension_registry_observer.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/test/extension_background_page_waiter.h"
 #include "ui/message_center/public/cpp/notification.h"
 #include "ui/message_center/public/cpp/notification_delegate.h"
@@ -70,7 +71,7 @@
     return GetExtensionRegistry()->terminated_extensions().size();
   }
 
-  void CrashExtension(const std::string& extension_id) {
+  void CrashExtension(const extensions::ExtensionId& extension_id) {
     const Extension* extension =
         GetExtensionRegistry()->enabled_extensions().GetByID(extension_id);
     ASSERT_TRUE(extension);
@@ -89,7 +90,7 @@
     base::RunLoop().RunUntilIdle();
   }
 
-  void CheckExtensionConsistency(const std::string& extension_id) {
+  void CheckExtensionConsistency(const extensions::ExtensionId& extension_id) {
     const Extension* extension =
         GetExtensionRegistry()->enabled_extensions().GetByID(extension_id);
     ASSERT_TRUE(extension);
@@ -126,7 +127,7 @@
     CheckExtensionConsistency(second_extension_id_);
   }
 
-  void AcceptNotification(const std::string& extension_id) {
+  void AcceptNotification(const extensions::ExtensionId& extension_id) {
     extensions::TestExtensionRegistryObserver observer(GetExtensionRegistry());
     display_service_->SimulateClick(NotificationHandler::Type::TRANSIENT,
                                     "app.background.crashed." + extension_id,
@@ -143,8 +144,8 @@
         .size();
   }
 
-  std::string first_extension_id_;
-  std::string second_extension_id_;
+  extensions::ExtensionId first_extension_id_;
+  extensions::ExtensionId second_extension_id_;
   std::unique_ptr<NotificationDisplayServiceTester> display_service_;
   content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes_;
 };
diff --git a/chrome/browser/extensions/extension_garbage_collector.cc b/chrome/browser/extensions/extension_garbage_collector.cc
index a1fab5d6..6488d11 100644
--- a/chrome/browser/extensions/extension_garbage_collector.cc
+++ b/chrome/browser/extensions/extension_garbage_collector.cc
@@ -36,6 +36,7 @@
 #include "extensions/browser/extension_util.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_features.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/file_util.h"
 
 namespace extensions {
@@ -49,7 +50,7 @@
 // garbage collected.
 constexpr base::TimeDelta kGarbageCollectStartupDelay = base::Seconds(30);
 
-using ExtensionPathsMultimap = std::multimap<std::string, base::FilePath>;
+using ExtensionPathsMultimap = std::multimap<ExtensionId, base::FilePath>;
 
 void CheckExtensionDirectory(const base::FilePath& path,
                              const ExtensionPathsMultimap& extension_paths) {
@@ -62,7 +63,7 @@
   }
 
   // Parse directory name as a potential extension ID.
-  std::string extension_id;
+  ExtensionId extension_id;
   if (base::IsStringASCII(basename.value())) {
     extension_id = base::UTF16ToASCII(basename.LossyDisplayName());
     if (!crx_file::id_util::IdIsValid(extension_id))
@@ -209,7 +210,7 @@
   // like that to ensure we're inside the profile directory.
   ExtensionPrefs::ExtensionsInfo extensions_info =
       extension_prefs->GetInstalledExtensionsInfo();
-  std::multimap<std::string, base::FilePath> extension_paths;
+  std::multimap<ExtensionId, base::FilePath> extension_paths;
   for (const auto& info : extensions_info) {
     extension_paths.insert(
         std::make_pair(info.extension_id, info.extension_path));
@@ -245,14 +246,14 @@
 void ExtensionGarbageCollector::OnBeginCrxInstall(
     content::BrowserContext* context,
     const CrxInstaller& installer,
-    const std::string& extension_id) {
+    const ExtensionId& extension_id) {
   crx_installs_in_progress_++;
 }
 
 void ExtensionGarbageCollector::OnFinishCrxInstall(
     content::BrowserContext* context,
     const CrxInstaller& installer,
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     bool success) {
   crx_installs_in_progress_--;
   if (crx_installs_in_progress_ < 0) {
diff --git a/chrome/browser/extensions/extension_garbage_collector.h b/chrome/browser/extensions/extension_garbage_collector.h
index ae9376f..ea7566b 100644
--- a/chrome/browser/extensions/extension_garbage_collector.h
+++ b/chrome/browser/extensions/extension_garbage_collector.h
@@ -13,6 +13,7 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/extensions/install_observer.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "extensions/common/extension_id.h"
 
 namespace content {
 class BrowserContext;
@@ -46,10 +47,10 @@
   // InstallObserver:
   void OnBeginCrxInstall(content::BrowserContext* context,
                          const CrxInstaller& installer,
-                         const std::string& extension_id) override;
+                         const ExtensionId& extension_id) override;
   void OnFinishCrxInstall(content::BrowserContext* context,
                           const CrxInstaller& installer,
-                          const std::string& extension_id,
+                          const ExtensionId& extension_id,
                           bool success) override;
 
  protected:
@@ -64,7 +65,7 @@
 
   static void GarbageCollectExtensionsOnFileThread(
       const base::FilePath& install_directory,
-      const std::multimap<std::string, base::FilePath>& extension_paths,
+      const std::multimap<ExtensionId, base::FilePath>& extension_paths,
       bool unpacked);
 
   // The BrowserContext associated with the GarbageCollector.
diff --git a/chrome/browser/extensions/extension_garbage_collector_unittest.cc b/chrome/browser/extensions/extension_garbage_collector_unittest.cc
index 2d64610f..1b6ecb3 100644
--- a/chrome/browser/extensions/extension_garbage_collector_unittest.cc
+++ b/chrome/browser/extensions/extension_garbage_collector_unittest.cc
@@ -22,6 +22,7 @@
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/pref_names.h"
 #include "extensions/common/extension_features.h"
+#include "extensions/common/extension_id.h"
 #include "ppapi/buildflags/buildflags.h"
 
 #if BUILDFLAG(ENABLE_PLUGINS)
@@ -55,7 +56,7 @@
 TEST_F(ExtensionGarbageCollectorUnitTest, CleanupOnStartup) {
   feature_list_.InitAndDisableFeature(
       extensions_features::kExtensionsZipFileInstalledInProfileDir);
-  const std::string kExtensionId = "behllobkkfkfnphdnhnkndlbkcpglgmj";
+  const ExtensionId kExtensionId = "behllobkkfkfnphdnhnkndlbkcpglgmj";
 
   InitPluginService();
   InitializeGoodInstalledExtensionService();
@@ -98,7 +99,7 @@
        CleanupUnpackedOnStartup_DeleteWhenNoLongerInstalled) {
   feature_list_.InitAndEnableFeature(
       extensions_features::kExtensionsZipFileInstalledInProfileDir);
-  const std::string kExtensionId = "lckcjklfapeiadkadngidmocpbkemckm";
+  const ExtensionId kExtensionId = "lckcjklfapeiadkadngidmocpbkemckm";
 
   InitPluginService();
   InitializeGoodInstalledExtensionService();
@@ -131,7 +132,7 @@
        CleanupUnpackedOnStartup_DoNotDeleteWhenStillInstalled) {
   feature_list_.InitAndEnableFeature(
       extensions_features::kExtensionsZipFileInstalledInProfileDir);
-  const std::string kExtensionId = "lckcjklfapeiadkadngidmocpbkemckm";
+  const ExtensionId kExtensionId = "lckcjklfapeiadkadngidmocpbkemckm";
 
   InitPluginService();
   InitializeGoodInstalledExtensionService();
@@ -165,7 +166,7 @@
 // Test that garbage collection doesn't delete anything while a crx is being
 // installed.
 TEST_F(ExtensionGarbageCollectorUnitTest, NoCleanupDuringInstall) {
-  const std::string kExtensionId = "behllobkkfkfnphdnhnkndlbkcpglgmj";
+  const ExtensionId kExtensionId = "behllobkkfkfnphdnhnkndlbkcpglgmj";
 
   InitPluginService();
   InitializeGoodInstalledExtensionService();
diff --git a/chrome/browser/extensions/extension_icon_manager.cc b/chrome/browser/extensions/extension_icon_manager.cc
index 7b766ea..7d18121 100644
--- a/chrome/browser/extensions/extension_icon_manager.cc
+++ b/chrome/browser/extensions/extension_icon_manager.cc
@@ -11,6 +11,7 @@
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_icon_set.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/extension_resource.h"
 #include "extensions/common/manifest_handlers/icons_handler.h"
 #include "skia/ext/image_operations.h"
@@ -42,7 +43,8 @@
                      weak_ptr_factory_.GetWeakPtr(), extension->id()));
 }
 
-gfx::Image ExtensionIconManager::GetIcon(const std::string& extension_id) {
+gfx::Image ExtensionIconManager::GetIcon(
+    const extensions::ExtensionId& extension_id) {
   auto iter = icons_.find(extension_id);
   gfx::Image* result = nullptr;
   if (iter == icons_.end()) {
@@ -58,13 +60,15 @@
   return *result;
 }
 
-void ExtensionIconManager::RemoveIcon(const std::string& extension_id) {
+void ExtensionIconManager::RemoveIcon(
+    const extensions::ExtensionId& extension_id) {
   icons_.erase(extension_id);
   pending_icons_.erase(extension_id);
 }
 
-void ExtensionIconManager::OnImageLoaded(const std::string& extension_id,
-                                         const gfx::Image& image) {
+void ExtensionIconManager::OnImageLoaded(
+    const extensions::ExtensionId& extension_id,
+    const gfx::Image& image) {
   if (!image.IsEmpty()) {
     // We may have removed the icon while waiting for it to load. In that case,
     // do nothing.
diff --git a/chrome/browser/extensions/extension_icon_manager.h b/chrome/browser/extensions/extension_icon_manager.h
index b179a5d..7bbb366 100644
--- a/chrome/browser/extensions/extension_icon_manager.h
+++ b/chrome/browser/extensions/extension_icon_manager.h
@@ -7,10 +7,10 @@
 
 #include <map>
 #include <set>
-#include <string>
 
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "extensions/common/extension_id.h"
 #include "ui/gfx/image/image.h"
 
 namespace content {
@@ -25,7 +25,7 @@
  public:
   class Observer {
    public:
-    virtual void OnImageLoaded(const std::string& extension_id) = 0;
+    virtual void OnImageLoaded(const extensions::ExtensionId& extension_id) = 0;
   };
 
   ExtensionIconManager();
@@ -42,26 +42,27 @@
   // This returns an image of width/height kFaviconSize, loaded either from an
   // entry specified in the extension's 'icon' section of the manifest, or a
   // default extension icon.
-  gfx::Image GetIcon(const std::string& extension_id);
+  gfx::Image GetIcon(const extensions::ExtensionId& extension_id);
 
   // Removes the extension's icon from memory.
-  void RemoveIcon(const std::string& extension_id);
+  void RemoveIcon(const extensions::ExtensionId& extension_id);
 
   void set_monochrome(bool value) { monochrome_ = value; }
   void set_observer(Observer* observer) { observer_ = observer; }
 
  private:
-  void OnImageLoaded(const std::string& extension_id, const gfx::Image& image);
+  void OnImageLoaded(const extensions::ExtensionId& extension_id,
+                     const gfx::Image& image);
 
   // Makes sure we've done one-time initialization of the default extension icon
   // default_icon_.
   void EnsureDefaultIcon();
 
   // Maps extension id to the icon for that extension.
-  std::map<std::string, gfx::Image> icons_;
+  std::map<extensions::ExtensionId, gfx::Image> icons_;
 
   // Set of extension IDs waiting for icons to load.
-  std::set<std::string> pending_icons_;
+  std::set<extensions::ExtensionId> pending_icons_;
 
   // The default icon we'll use if an extension doesn't have one.
   gfx::Image default_icon_;
diff --git a/chrome/browser/extensions/extension_icon_manager_unittest.cc b/chrome/browser/extensions/extension_icon_manager_unittest.cc
index 4a63c1b7..a7e09272 100644
--- a/chrome/browser/extensions/extension_icon_manager_unittest.cc
+++ b/chrome/browser/extensions/extension_icon_manager_unittest.cc
@@ -20,6 +20,7 @@
 #include "components/crx_file/id_util.h"
 #include "content/public/test/browser_task_environment.h"
 #include "extensions/common/extension.h"
+#include "extensions/common/extension_id.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/resource/resource_scale_factor.h"
 #include "ui/display/display_list.h"
@@ -73,7 +74,7 @@
 
   ~ExtensionIconManagerTest() override = default;
 
-  void OnImageLoaded(const std::string& extension_id) override {
+  void OnImageLoaded(const ExtensionId& extension_id) override {
     unwaited_image_loads_++;
     if (waiting_) {
       std::move(quit_closure_).Run();
@@ -107,7 +108,7 @@
 // Returns the default icon that ExtensionIconManager gives when an extension
 // doesn't have an icon.
 gfx::Image GetDefaultIcon() {
-  std::string dummy_id = crx_file::id_util::GenerateId("whatever");
+  ExtensionId dummy_id = crx_file::id_util::GenerateId("whatever");
   ExtensionIconManager manager;
   return manager.GetIcon(dummy_id);
 }
diff --git a/chrome/browser/extensions/extension_keybinding_registry.cc b/chrome/browser/extensions/extension_keybinding_registry.cc
index f142271..e332885 100644
--- a/chrome/browser/extensions/extension_keybinding_registry.cc
+++ b/chrome/browser/extensions/extension_keybinding_registry.cc
@@ -18,6 +18,7 @@
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/common/command.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/extension_set.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/mojom/context_type.mojom.h"
@@ -135,7 +136,8 @@
 }
 
 void ExtensionKeybindingRegistry::CommandExecuted(
-    const std::string& extension_id, const std::string& command) {
+    const ExtensionId& extension_id,
+    const std::string& command) {
   const Extension* extension = ExtensionRegistry::Get(browser_context_)
                                    ->enabled_extensions()
                                    .GetByID(extension_id);
@@ -193,7 +195,7 @@
 
 void ExtensionKeybindingRegistry::AddEventTarget(
     const ui::Accelerator& accelerator,
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     const std::string& command_name) {
   event_targets_[accelerator].push_back(
       std::make_pair(extension_id, command_name));
@@ -225,7 +227,7 @@
 
 bool ExtensionKeybindingRegistry::GetFirstTarget(
     const ui::Accelerator& accelerator,
-    std::string* extension_id,
+    ExtensionId* extension_id,
     std::string* command_name) const {
   auto targets = event_targets_.find(accelerator);
   if (targets == event_targets_.end())
@@ -258,7 +260,7 @@
 }
 
 void ExtensionKeybindingRegistry::OnExtensionCommandAdded(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     const Command& command) {
   const Extension* extension = ExtensionRegistry::Get(browser_context_)
                                    ->enabled_extensions()
@@ -279,7 +281,7 @@
 }
 
 void ExtensionKeybindingRegistry::OnExtensionCommandRemoved(
-    const std::string& extension_id,
+    const ExtensionId& extension_id,
     const Command& command) {
   const Extension* extension = ExtensionRegistry::Get(browser_context_)
                                    ->enabled_extensions()
@@ -317,7 +319,7 @@
 
 bool ExtensionKeybindingRegistry::ExecuteCommands(
     const ui::Accelerator& accelerator,
-    const std::string& extension_id) {
+    const ExtensionId& extension_id) {
   auto targets = event_targets_.find(accelerator);
   if (targets == event_targets_.end() || targets->second.empty())
     return false;
diff --git a/chrome/browser/extensions/extension_keybinding_registry.h b/chrome/browser/extensions/extension_keybinding_registry.h
index 77a4197f..efef7887 100644
--- a/chrome/browser/extensions/extension_keybinding_registry.h
+++ b/chrome/browser/extensions/extension_keybinding_registry.h
@@ -15,6 +15,7 @@
 #include "chrome/browser/extensions/api/commands/command_service.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_observer.h"
+#include "extensions/common/extension_id.h"
 #include "ui/base/accelerators/media_keys_listener.h"
 
 namespace content {
@@ -102,14 +103,14 @@
   bool NotifyEventTargets(const ui::Accelerator& accelerator);
 
   // Notifies appropriate parties that a command has been executed.
-  void CommandExecuted(const std::string& extension_id,
+  void CommandExecuted(const ExtensionId& extension_id,
                        const std::string& command);
 
   // Add event target (extension_id, command name) to the target list of
   // |accelerator|. Note that only media keys can have more than one event
   // target.
   void AddEventTarget(const ui::Accelerator& accelerator,
-                      const std::string& extension_id,
+                      const ExtensionId& extension_id,
                       const std::string& command_name);
 
   // Get the first event target by the given |accelerator|. For a valid
@@ -118,7 +119,7 @@
   // set to the right target; otherwise, false is returned and |extension_id|,
   // |command_name| are unchanged.
   bool GetFirstTarget(const ui::Accelerator& accelerator,
-                      std::string* extension_id,
+                      ExtensionId* extension_id,
                       std::string* command_name) const;
 
   // Returns true if the |event_targets_| is empty; otherwise returns false.
@@ -129,9 +130,9 @@
 
  private:
   // extensions::CommandService::Observer:
-  void OnExtensionCommandAdded(const std::string& extension_id,
+  void OnExtensionCommandAdded(const ExtensionId& extension_id,
                                const Command& command) override;
-  void OnExtensionCommandRemoved(const std::string& extension_id,
+  void OnExtensionCommandRemoved(const ExtensionId& extension_id,
                                  const Command& command) override;
   void OnCommandServiceDestroying() override;
 
@@ -153,7 +154,7 @@
   // the corresponding extension. Returns true if at least one command was
   // executed.
   bool ExecuteCommands(const ui::Accelerator& accelerator,
-                       const std::string& extension_id);
+                       const ExtensionId& extension_id);
 
   // Returns true if any media keys are registered.
   bool IsListeningToAnyMediaKeys() const;
@@ -173,7 +174,7 @@
   // commands, whereas on other platforms it does not. Note that normal
   // accelerator (which isn't media keys) has only one target, while the media
   // keys can have more than one.
-  typedef std::list<std::pair<std::string, std::string> > TargetList;
+  typedef std::list<std::pair<ExtensionId, std::string>> TargetList;
   typedef std::map<ui::Accelerator, TargetList> EventTargets;
   EventTargets event_targets_;
 
diff --git a/chrome/browser/extensions/webstore_installer.cc b/chrome/browser/extensions/webstore_installer.cc
index b67d227..a92aa551 100644
--- a/chrome/browser/extensions/webstore_installer.cc
+++ b/chrome/browser/extensions/webstore_installer.cc
@@ -55,6 +55,7 @@
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/install/crx_install_error.h"
 #include "extensions/common/extension.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/common/extension_urls.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/manifest_handlers/shared_module_info.h"
@@ -101,7 +102,7 @@
 base::FilePath* g_download_directory_for_tests = nullptr;
 
 base::FilePath GetDownloadFilePath(const base::FilePath& download_directory,
-                                   const std::string& id) {
+                                   const extensions::ExtensionId& id) {
   // Ensure the download directory exists. TODO(asargent) - make this use
   // common code from the downloads system.
   if (!base::DirectoryExists(download_directory) &&
@@ -232,7 +233,7 @@
 std::unique_ptr<WebstoreInstaller::Approval>
 WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
     Profile* profile,
-    const std::string& extension_id,
+    const extensions::ExtensionId& extension_id,
     base::Value::Dict parsed_manifest,
     bool strict_manifest_check) {
   std::unique_ptr<Approval> result(new Approval());
@@ -258,7 +259,7 @@
                                      SuccessCallback success_callback,
                                      FailureCallback failure_callback,
                                      content::WebContents* web_contents,
-                                     const std::string& id,
+                                     const extensions::ExtensionId& id,
                                      std::unique_ptr<Approval> approval,
                                      InstallSource source)
     : web_contents_(web_contents->GetWeakPtr()),
@@ -302,7 +303,7 @@
 
   total_modules_ = pending_modules_.size();
 
-  std::set<std::string> ids;
+  std::set<extensions::ExtensionId> ids;
   std::list<SharedModuleInfo::ImportInfo>::const_iterator i;
   for (i = pending_modules_.begin(); i != pending_modules_.end(); ++i) {
     ids.insert(i->extension_id);
@@ -398,7 +399,7 @@
 }
 
 void WebstoreInstaller::OnDownloadStarted(
-    const std::string& extension_id,
+    const extensions::ExtensionId& extension_id,
     DownloadItem* item,
     download::DownloadInterruptReason interrupt_reason) {
   if (!item || interrupt_reason != download::DOWNLOAD_INTERRUPT_REASON_NONE) {
@@ -517,9 +518,8 @@
   }
 }
 
-void WebstoreInstaller::DownloadCrx(
-    const std::string& extension_id,
-    InstallSource source) {
+void WebstoreInstaller::DownloadCrx(const extensions::ExtensionId& extension_id,
+                                    InstallSource source) {
   download_url_ = GetWebstoreInstallURL(extension_id, source);
   MaybeAppendAuthUserParameter(approval_->authuser, &download_url_);
 
@@ -544,8 +544,9 @@
 // reports should narrow down exactly which pointer it is.  Collapsing all the
 // early-returns into a single branch makes it hard to see exactly which pointer
 // it is.
-void WebstoreInstaller::StartDownload(const std::string& extension_id,
-                                      const base::FilePath& file) {
+void WebstoreInstaller::StartDownload(
+    const extensions::ExtensionId& extension_id,
+    const base::FilePath& file) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (file.empty()) {
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 15d2b17c..c772a76 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1050,6 +1050,22 @@
     "expiry_milestone": 140
   },
   {
+    "name": "campbell-glyph",
+    "owners": [
+      "tbarzic@chromiu.org",
+      "chromeos-launcher@google.com"
+    ],
+    "expiry_milestone": 124
+  },
+  {
+    "name": "campbell-key",
+    "owners": [
+      "tbarzic@chromiu.org",
+      "chromeos-launcher@google.com"
+    ],
+    "expiry_milestone": 124
+  },
+  {
     "name": "canvas-2d-layers",
     "owners": [ "fserb@chromium.org", "jpgravel@chromium.org", "yiyix@chromium.org" ],
     "expiry_milestone": 125
@@ -1599,6 +1615,11 @@
     "expiry_milestone": 125
   },
   {
+    "name": "data-sharing-android",
+    "owners": [ "haileywang@google.com" ],
+    "expiry_milestone": 140
+  },
+  {
     "name": "dcheck-is-fatal",
     "owners": [ "wez@chromium.org" ],
     // Used to debug failed assertions in environments where debug builds cannot
@@ -6540,6 +6561,15 @@
     "expiry_milestone": 123
   },
   {
+    "name": "prerender2",
+    "owners": [
+      "//content/browser/preloading/prerender/OWNERS"
+    ],
+    // This flag is used for QA & debugging on ChromeOS, which has no way to
+    // customize switches. See https://crbug.com/1494471.
+    "expiry_milestone": -1
+  },
+  {
     "name": "price-change-module",
     "owners": [ "yuezhanggg@chromium.org", "chrome-shopping-eng@google.com" ],
     "expiry_milestone": 125
diff --git a/chrome/browser/flag-never-expire-list.json b/chrome/browser/flag-never-expire-list.json
index a0af02d..a045535 100644
--- a/chrome/browser/flag-never-expire-list.json
+++ b/chrome/browser/flag-never-expire-list.json
@@ -107,6 +107,7 @@
   "overlay-scrollbars",
   "overlay-strategies",
   "prefer-dcheck",
+  "prerender2",
   "printing-ppd-channel",
   "reader-mode-heuristics",
   "record-web-app-debug-info",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 516282a..f38fe66 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -296,6 +296,12 @@
 const char kPreloadingOnPerformancePageDescription[] =
     "Moves preloading settings to the performance page.";
 
+const char kPrerender2Name[] = "Prerendering";
+const char kPrerender2Description[] =
+    "If enabled, browser features and the speculation rules API can trigger "
+    "prerendering. If disabled, all prerendering APIs still exist, but a "
+    "prerender will never successfully take place.";
+
 const char kPrivacyIndicatorsName[] = "Enable Privacy Indicators";
 const char kPrivacyIndicatorsDescription[] =
     "While screen sharing or camera/microphone is being accessed, show a green "
@@ -4043,6 +4049,10 @@
 const char kConvertTrackpadEventsToMouseDescription[] =
     "Convert trackpad events to mouse events to improve gesture support";
 
+const char kDataSharingAndroidName[] = "Data Sharing for Android";
+const char kDataSharingAndroidDescription[] =
+    "Data sharing service in Android devices.";
+
 const char kDefaultViewportIsDeviceWidthName[] =
     "Default viewport width is device width";
 const char kDefaultViewportIsDeviceWidthDescription[] =
@@ -5810,6 +5820,13 @@
     "Enable address resolution offloading to Bluetooth Controller if "
     "supported. Modifying this flag will cause Bluetooth Controller to reset.";
 
+const char kCampbellGlyphName[] = "Enable glyph for Campbell";
+const char kCampbellGlyphDescription[] = "Enables a Campbell glyph.";
+
+const char kCampbellKeyName[] = "Key to enable glyph for Campbell";
+const char kCampbellKeyDescription[] =
+    "Secret key to enable glyph for Campbell";
+
 const char kCaptureModeAudioMixingName[] =
     "Enable screen capture advanced audio settings";
 const char kCaptureModeAudioMixingDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 47f582d4..4a6e64ab 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1682,6 +1682,9 @@
 extern const char kPreloadingOnPerformancePageName[];
 extern const char kPreloadingOnPerformancePageDescription[];
 
+extern const char kPrerender2Name[];
+extern const char kPrerender2Description[];
+
 extern const char kCbdTimeframeRequiredName[];
 extern const char kCbdTimeframeRequiredDescription[];
 
@@ -2359,6 +2362,9 @@
 extern const char kConvertTrackpadEventsToMouseName[];
 extern const char kConvertTrackpadEventsToMouseDescription[];
 
+extern const char kDataSharingAndroidName[];
+extern const char kDataSharingAndroidDescription[];
+
 extern const char kDefaultViewportIsDeviceWidthName[];
 extern const char kDefaultViewportIsDeviceWidthDescription[];
 
@@ -3352,6 +3358,12 @@
 extern const char kBluetoothUseLLPrivacyName[];
 extern const char kBluetoothUseLLPrivacyDescription[];
 
+extern const char kCampbellGlyphName[];
+extern const char kCampbellGlyphDescription[];
+
+extern const char kCampbellKeyName[];
+extern const char kCampbellKeyDescription[];
+
 extern const char kCaptureModeAudioMixingName[];
 extern const char kCaptureModeAudioMixingDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 8155a63..f9c78f52 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -192,6 +192,7 @@
     &kCCTResizableSideSheet,
     &kCCTResizableSideSheetForThirdParties,
     &kCCTTabModalDialog,
+    &kDataSharingAndroid,
     &kDontAutoHideBrowserControls,
     &kCacheDeprecatedSystemLocationSetting,
     &kChromeSurveyNextAndroid,
@@ -261,6 +262,7 @@
     &kTabStripGroupIndicatorsAndroid,
     &kTabEngagementReportingAndroid,
     &kTabGroupParityAndroid,
+    &kTabletTabSwitcherLongPressMenu,
     &kTabletToolbarIncognitoStatus,
     &kTabletToolbarReordering,
     &kTabResumptionModuleAndroid,
@@ -286,7 +288,6 @@
     &kVoiceSearchAudioCapturePolicy,
     &kWebOtpCrossDeviceSimpleString,
     &kWebApkAllowIconUpdate,
-    &kWebApkBackupAndRestoreBackend,
     &kWebApkIconUpdateThreshold,
     &features::kDnsOverHttps,
     &notifications::features::kUseChimeAndroidSdk,
@@ -348,6 +349,7 @@
     &syncer::kSyncDecoupleAddressPaymentSettings,
     &syncer::kSyncEnableContactInfoDataTypeInTransportMode,
     &syncer::kSyncShowIdentityErrorsForSignedInUsers,
+    &syncer::kWebApkBackupAndRestoreBackend,
     &webapps::features::kWebApkInstallFailureNotification,
     &webapps::features::kAmbientBadgeSuppressFirstVisit,
     &network::features::kPrivateStateTokens,
@@ -561,6 +563,10 @@
              "ContextualSearchThinWebViewImplementation",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kDataSharingAndroid,
+             "DataSharingAndroid",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kDeferKeepScreenOnDuringGesture,
              "DeferKeepScreenOnDuringGesture",
              base::FEATURE_ENABLED_BY_DEFAULT);
@@ -803,6 +809,10 @@
              "TabStateFlatBuffer",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kTabletTabSwitcherLongPressMenu,
+             "TabletTabSwitcherLongPressMenu",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 BASE_FEATURE(kTabletToolbarIncognitoStatus,
              "TabletToolbarIncognitoStatus",
              base::FEATURE_ENABLED_BY_DEFAULT);
@@ -926,9 +936,5 @@
              "WebApkIconUpdateThreshold",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kWebApkBackupAndRestoreBackend,
-             "WebApkBackupAndRestoreBackend",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 }  // namespace android
 }  // namespace chrome
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index a7ce651..c47215b 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -58,6 +58,7 @@
 BASE_DECLARE_FEATURE(kCCTResizableSideSheetForThirdParties);
 BASE_DECLARE_FEATURE(kCCTRetainingStateInMemory);
 BASE_DECLARE_FEATURE(kCCTTabModalDialog);
+BASE_DECLARE_FEATURE(kDataSharingAndroid);
 BASE_DECLARE_FEATURE(kDontAutoHideBrowserControls);
 BASE_DECLARE_FEATURE(kCacheDeprecatedSystemLocationSetting);
 BASE_DECLARE_FEATURE(kChromeShareScreenshot);
@@ -142,6 +143,7 @@
 BASE_DECLARE_FEATURE(kTabGroupParityAndroid);
 BASE_DECLARE_FEATURE(kTabStripGroupIndicatorsAndroid);
 BASE_DECLARE_FEATURE(kTabStateFlatBuffer);
+BASE_DECLARE_FEATURE(kTabletTabSwitcherLongPressMenu);
 BASE_DECLARE_FEATURE(kTabletToolbarIncognitoStatus);
 BASE_DECLARE_FEATURE(kTabletToolbarReordering);
 BASE_DECLARE_FEATURE(kTabStripStartupRefactoring);
@@ -168,7 +170,6 @@
 BASE_DECLARE_FEATURE(kVoiceSearchAudioCapturePolicy);
 BASE_DECLARE_FEATURE(kWebOtpCrossDeviceSimpleString);
 BASE_DECLARE_FEATURE(kWebApkAllowIconUpdate);
-BASE_DECLARE_FEATURE(kWebApkBackupAndRestoreBackend);
 BASE_DECLARE_FEATURE(kWebApkIconUpdateThreshold);
 
 // For FeatureParam, Alphabetical:
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 56ea63a..f56aca0 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -253,6 +253,7 @@
     public static final String DARKEN_WEBSITES_CHECKBOX_IN_THEMES_SETTING =
             "DarkenWebsitesCheckboxInThemesSetting";
     public static final String DATA_SHARING = "DataSharing";
+    public static final String DATA_SHARING_ANDROID = "DataSharingAndroid";
     public static final String DEFER_KEEP_SCREEN_ON_DURING_GESTURE =
             "DeferKeepScreenOnDuringGesture";
     public static final String DEFER_NOTIFY_IN_MOTION = "DeferNotifyInMotion";
@@ -453,6 +454,8 @@
     public static final String TAB_RESUMPTION_MODULE_ANDROID = "TabResumptionModuleAndroid";
     public static final String TAB_STRIP_GROUP_INDICATORS = "TabStripGroupIndicatorsAndroid";
     public static final String TAB_STRIP_STARTUP_REFACTORING = "TabStripStartupRefactoring";
+    public static final String TABLET_TAB_SWITCHER_LONG_PRESS_MENU =
+            "TabletTabSwitcherLongPressMenu";
     public static final String TABLET_TOOLBAR_INCOGNITO_STATUS = "TabletToolbarIncognitoStatus";
     public static final String TABLET_TOOLBAR_REORDERING = "TabletToolbarReordering";
     public static final String TAB_TO_GTS_ANIMATION = "TabToGTSAnimation";
diff --git a/chrome/browser/headless/headless_command_processor.cc b/chrome/browser/headless/headless_command_processor.cc
index 096211a..9d8cd68 100644
--- a/chrome/browser/headless/headless_command_processor.cc
+++ b/chrome/browser/headless/headless_command_processor.cc
@@ -41,7 +41,6 @@
 
   // Create web contents to run the command processing in.
   content::WebContents::CreateParams create_params(browser_context);
-  create_params.is_never_visible = true;
   auto web_contents = content::WebContents::Create(create_params);
 
   // Navigate web contents to the command processor page.
diff --git a/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler.cc b/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler.cc
index 885334a..c35ff08 100644
--- a/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler.cc
+++ b/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler.cc
@@ -35,6 +35,14 @@
 using history::BrowsingHistoryService;
 using history::HistoryService;
 
+const size_t kCategoryBlockListCount = 18;
+constexpr std::array<std::string_view, kCategoryBlockListCount>
+    kCategoryBlockList{"/g/11b76fyj2r", "/m/09lkz",  "/m/012mj",  "/m/01rbb",
+                       "/m/02px0wr",    "/m/028hh",  "/m/034qg",  "/m/034dj",
+                       "/m/0jxxt",      "/m/015fwp", "/m/04shl0", "/m/01h6rj",
+                       "/m/05qt0",      "/m/06gqm",  "/m/09l0j_", "/m/01pxgq",
+                       "/m/0chbx",      "/m/02c66t"};
+
 namespace {
 // Maximum number of sessions we're going to display on the NTP
 const size_t kMaxSessionsToShow = 10;
@@ -123,7 +131,10 @@
           static_cast<float>(base::GetFieldTrialParamByFeatureAsDouble(
               ntp_features::kNtpTabResumptionModule,
               ntp_features::kNtpTabResumptionModuleVisibilityThresholdDataParam,
-              /*Default value for visibility threshold*/ 0.5))) {
+              /*Default value for visibility threshold*/ 0.5))),
+      categories_blocklist_(GetTabResumptionCategories(
+          ntp_features::kNtpTabResumptionModuleCategoriesBlocklistParam,
+          {kCategoryBlockList.begin(), kCategoryBlockListCount})) {
   DCHECK(profile_);
   DCHECK(web_contents_);
 }
@@ -164,6 +175,9 @@
     if (visibility_score < visibility_threshold_ && visibility_score >= 0) {
       continue;
     }
+    if (IsVisitInCategories(annotated_visit, categories_blocklist_)) {
+      continue;
+    }
     for (size_t i = 0; i < tabs.size(); i++) {
       if (annotated_visit.url_row.url() == tabs[i]->url &&
           scored_tab_indices.find(i) == scored_tab_indices.end()) {
diff --git a/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler.h b/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler.h
index 3861219..43d0234 100644
--- a/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler.h
+++ b/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler.h
@@ -12,6 +12,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/containers/flat_set.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "chrome/browser/history/profile_based_browsing_history_driver.h"
 #include "chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption.mojom.h"
@@ -73,6 +74,10 @@
 
   const float visibility_threshold_;
 
+  // The category IDs that a tab must not contain for it to be included.
+  // If `categories_blocklist`is empty, the returned tabs will not be filtered.
+  base::flat_set<std::string> categories_blocklist_;
+
   base::WeakPtrFactory<TabResumptionPageHandler> weak_ptr_factory_{this};
 };
 
diff --git a/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler_unittest.cc b/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler_unittest.cc
index 253bb59..c2b0a20 100644
--- a/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler_unittest.cc
+++ b/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_page_handler_unittest.cc
@@ -82,9 +82,9 @@
 };
 
 TEST_F(TabResumptionPageHandlerTest, GetTabs) {
-  const int kSampleSessionsCount = 3;
+  const size_t kSampleSessionsCount = 3;
   std::vector<std::unique_ptr<sync_sessions::SyncedSession>> sample_sessions;
-  for (int i = 0; i < kSampleSessionsCount; i++) {
+  for (size_t i = 0; i < kSampleSessionsCount; i++) {
     sample_sessions.push_back(SampleSession(
         "Test Name", ("Test Tag " + base::NumberToString(i)).c_str(), 1, 1));
   }
@@ -160,7 +160,100 @@
 
   ASSERT_EQ(3u, tabs_mojom.size());
 
-  for (unsigned int i = 0; i < kSampleSessionsCount; i++) {
+  for (size_t i = 0; i < kSampleSessionsCount; i++) {
+    const auto& tab_mojom = tabs_mojom[i];
+    ASSERT_TRUE(tab_mojom);
+    ASSERT_EQ("Test Tag " + base::NumberToString(i), tab_mojom->session_tag);
+    ASSERT_EQ(GURL(kSampleUrl), tab_mojom->url);
+  }
+}
+
+TEST_F(TabResumptionPageHandlerTest, BlocklistTest) {
+  const size_t kSampleSessionsCount = 3;
+  std::vector<std::unique_ptr<sync_sessions::SyncedSession>> sample_sessions;
+  for (size_t i = 0; i < kSampleSessionsCount; i++) {
+    sample_sessions.push_back(SampleSession(
+        "Test Name", ("Test Tag " + base::NumberToString(i)).c_str(), 1, 1));
+  }
+
+  EXPECT_CALL(*mock_session_sync_service().GetOpenTabsUIDelegate(),
+              GetAllForeignSessions(testing::_))
+      .WillOnce(testing::Invoke(
+          [&sample_sessions](
+              std::vector<vector_experimental_raw_ptr<
+                  const sync_sessions::SyncedSession>>* sessions) {
+            for (auto& sample_session : sample_sessions) {
+              sessions->push_back(sample_session.get());
+            }
+            return true;
+          }));
+
+  std::vector<history::mojom::TabPtr> tabs_mojom;
+  base::MockCallback<TabResumptionPageHandler::GetTabsCallback> callback;
+  EXPECT_CALL(callback, Run(testing::_))
+      .Times(1)
+      .WillOnce(testing::Invoke(
+          [&tabs_mojom](std::vector<history::mojom::TabPtr> tabs_arg) {
+            tabs_mojom = std::move(tabs_arg);
+          }));
+
+  EXPECT_CALL(mock_history_service(),
+              QueryURLs(testing::_, true, testing::_, testing::_))
+      .WillOnce(
+          (testing::Invoke([&](const std::vector<GURL>& urls, bool want_visits,
+                               MockHistoryService::QueryURLsCallback callback,
+                               base::CancelableTaskTracker* tracker) {
+            std::vector<history::QueryURLResult> results;
+            for (auto url : urls) {
+              history::QueryURLResult result;
+              result.success = true;
+              result.row.set_url(url);
+              result.row.set_last_visit(base::Time::Now());
+              history::VisitVector visits;
+              history::VisitRow visit;
+              visits.push_back(visit);
+              result.visits = visits;
+              results.push_back(result);
+            }
+            std::move(callback).Run(results);
+            return base::CancelableTaskTracker::TaskId();
+          })));
+
+  EXPECT_CALL(mock_history_service(),
+              ToAnnotatedVisits(testing::_, false, testing::_, testing::_))
+      .WillOnce((testing::Invoke(
+          [&](const history::VisitVector& visit_rows,
+              bool compute_redirect_chain_start_properties,
+              MockHistoryService::ToAnnotatedVisitsCallback callback,
+              base::CancelableTaskTracker* tracker) {
+            std::vector<history::AnnotatedVisit> annotated_visits;
+            for (auto visit : visit_rows) {
+              history::URLRow url_row;
+              url_row.set_url(GURL(kSampleUrl));
+              history::AnnotatedVisit annotated_visit;
+              annotated_visit.url_row = url_row;
+              history::VisitContentModelAnnotations model_annotations;
+              model_annotations.visibility_score = 1.0;
+              history::VisitContentAnnotations content_annotations;
+              content_annotations.model_annotations = model_annotations;
+              annotated_visit.content_annotations = content_annotations;
+              annotated_visits.push_back(annotated_visit);
+            }
+            history::VisitContentModelAnnotations::Category category;
+            category.id = "/g/11b76fyj2r";
+            annotated_visits[kSampleSessionsCount - 1]
+                .content_annotations.model_annotations.categories.push_back(
+                    category);
+            std::move(callback).Run(annotated_visits);
+            return base::CancelableTaskTracker::TaskId();
+          })));
+
+  handler().GetTabs(callback.Get());
+
+  // Last visit has a blocked category so it should be excluded
+  ASSERT_EQ(2u, tabs_mojom.size());
+
+  for (size_t i = 0; i < kSampleSessionsCount - 1; i++) {
     const auto& tab_mojom = tabs_mojom[i];
     ASSERT_TRUE(tab_mojom);
     ASSERT_EQ("Test Tag " + base::NumberToString(i), tab_mojom->session_tag);
diff --git a/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_util.cc b/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_util.cc
index 80c3add..99286856 100644
--- a/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_util.cc
+++ b/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_util.cc
@@ -4,11 +4,46 @@
 
 #include "chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_util.h"
 
+#include "base/strings/string_split.h"
+#include "base/strings/utf_string_conversions.h"
 #include "components/history/core/browser/history_types.h"
+#include "components/search/ntp_features.h"
 #include "components/sessions/core/serialized_navigation_entry.h"
 #include "components/sessions/core/session_id.h"
 #include "components/sync_sessions/synced_session.h"
 
+namespace {
+
+std::unique_ptr<sessions::SessionTab> SampleSessionTab(int tab_id) {
+  auto session_tab = std::make_unique<sessions::SessionTab>();
+  session_tab->current_navigation_index = 0;
+
+  sessions::SerializedNavigationEntry navigation;
+  navigation.set_title(u"Test");
+  navigation.set_virtual_url(GURL(kSampleUrl));
+  navigation.set_timestamp(base::Time::Now());
+  navigation.set_favicon_url(GURL(kSampleUrl));
+  session_tab->navigations.push_back(navigation);
+
+  session_tab->timestamp = base::Time::Now();
+  session_tab->tab_id = SessionID::FromSerializedValue(tab_id);
+
+  return session_tab;
+}
+
+std::unique_ptr<sync_sessions::SyncedSessionWindow> SampleSessionWindow(
+    int num_tabs) {
+  auto synced_session_window =
+      std::make_unique<sync_sessions::SyncedSessionWindow>();
+  synced_session_window->wrapped_window.timestamp = base::Time::Now();
+  for (int i = 0; i < num_tabs; i++) {
+    synced_session_window->wrapped_window.tabs.push_back(SampleSessionTab(i));
+  }
+  return synced_session_window;
+}
+
+}  // namespace
+
 std::unique_ptr<sync_sessions::SyncedSession> SampleSession(
     const char session_name[],
     const char session_tag[],
@@ -27,30 +62,32 @@
   return sample_session;
 }
 
-std::unique_ptr<sync_sessions::SyncedSessionWindow> SampleSessionWindow(
-    int num_tabs) {
-  auto synced_session_window =
-      std::make_unique<sync_sessions::SyncedSessionWindow>();
-  synced_session_window->wrapped_window.timestamp = base::Time::Now();
-  for (int i = 0; i < num_tabs; i++) {
-    synced_session_window->wrapped_window.tabs.push_back(SampleSessionTab(i));
+base::flat_set<std::string> GetTabResumptionCategories(
+    const char* feature_param,
+    base::span<const std::string_view> default_categories) {
+  std::string categories_string = base::GetFieldTrialParamValueByFeature(
+      ntp_features::kNtpTabResumptionModuleCategories, feature_param);
+  if (categories_string.empty()) {
+    return base::flat_set<std::string>(default_categories.begin(),
+                                       default_categories.end());
   }
-  return synced_session_window;
+
+  auto categories = base::SplitString(categories_string, ",",
+                                      base::WhitespaceHandling::TRIM_WHITESPACE,
+                                      base::SplitResult::SPLIT_WANT_NONEMPTY);
+
+  return categories.empty() ? base::flat_set<std::string>()
+                            : base::flat_set<std::string>(categories.begin(),
+                                                          categories.end());
 }
 
-std::unique_ptr<sessions::SessionTab> SampleSessionTab(int tab_id) {
-  auto session_tab = std::make_unique<sessions::SessionTab>();
-  session_tab->current_navigation_index = 0;
-
-  sessions::SerializedNavigationEntry navigation;
-  navigation.set_title(u"Test");
-  navigation.set_virtual_url(GURL(kSampleUrl));
-  navigation.set_timestamp(base::Time::Now());
-  navigation.set_favicon_url(GURL(kSampleUrl));
-  session_tab->navigations.push_back(navigation);
-
-  session_tab->timestamp = base::Time::Now();
-  session_tab->tab_id = SessionID::FromSerializedValue(tab_id);
-
-  return session_tab;
+bool IsVisitInCategories(const history::AnnotatedVisit& annotated_visit,
+                         const base::flat_set<std::string>& categories) {
+  for (const auto& visit_category :
+       annotated_visit.content_annotations.model_annotations.categories) {
+    if (categories.contains(visit_category.id)) {
+      return true;
+    }
+  }
+  return false;
 }
diff --git a/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_util.h b/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_util.h
index ae94daf5..cf2f49e 100644
--- a/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_util.h
+++ b/chrome/browser/new_tab_page/modules/v2/tab_resumption/tab_resumption_util.h
@@ -15,8 +15,12 @@
     const char session_tag[],
     int num_windows,
     int num_tabs);
-std::unique_ptr<sync_sessions::SyncedSessionWindow> SampleSessionWindow(
-    int num_tabs);
-std::unique_ptr<sessions::SessionTab> SampleSessionTab(int tab_id);
+
+base::flat_set<std::string> GetTabResumptionCategories(
+    const char* feature_param,
+    base::span<const std::string_view> default_categories);
+
+bool IsVisitInCategories(const history::AnnotatedVisit& annotated_visit,
+                         const base::flat_set<std::string>& categories);
 
 #endif  // CHROME_BROWSER_NEW_TAB_PAGE_MODULES_V2_TAB_RESUMPTION_TAB_RESUMPTION_UTIL_H_
diff --git a/chrome/browser/performance_manager/metrics/metrics_provider_common.cc b/chrome/browser/performance_manager/metrics/metrics_provider_common.cc
index 6d9b56ec..106799e 100644
--- a/chrome/browser/performance_manager/metrics/metrics_provider_common.cc
+++ b/chrome/browser/performance_manager/metrics/metrics_provider_common.cc
@@ -28,7 +28,7 @@
       return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_HTML_METADATA;
     case ui::AXMode::kLabelImages:
       return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_LABEL_IMAGES;
-    case ui::AXMode::kPDF:
+    case ui::AXMode::kPDFPrinting:
       return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_PDF;
     case ui::AXMode::kPDFOcr:
       return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_PDF_OCR;
@@ -69,7 +69,7 @@
     MaybeRecordAccessibilityModeFlags(mode, ui::AXMode::kHTML);
     MaybeRecordAccessibilityModeFlags(mode, ui::AXMode::kHTMLMetadata);
     MaybeRecordAccessibilityModeFlags(mode, ui::AXMode::kLabelImages);
-    MaybeRecordAccessibilityModeFlags(mode, ui::AXMode::kPDF);
+    MaybeRecordAccessibilityModeFlags(mode, ui::AXMode::kPDFPrinting);
     MaybeRecordAccessibilityModeFlags(mode, ui::AXMode::kPDFOcr);
   }
 }
diff --git a/chrome/browser/performance_manager/metrics/page_resource_monitor.cc b/chrome/browser/performance_manager/metrics/page_resource_monitor.cc
index 2b01e76..828a0983 100644
--- a/chrome/browser/performance_manager/metrics/page_resource_monitor.cc
+++ b/chrome/browser/performance_manager/metrics/page_resource_monitor.cc
@@ -42,7 +42,7 @@
 namespace {
 
 using system_cpu::CpuProbe;
-using system_cpu::PressureSample;
+using system_cpu::CpuSample;
 using PageMeasurementBackgroundState =
     PageResourceMonitor::PageMeasurementBackgroundState;
 
@@ -110,9 +110,8 @@
 class PageResourceMonitor::CPUResultConverter {
  public:
   // A callback that's invoked with the converted results.
-  using ResultCallback =
-      base::OnceCallback<void(const PageCPUUsageMap&,
-                              std::optional<PressureSample>)>;
+  using ResultCallback = base::OnceCallback<void(const PageCPUUsageMap&,
+                                                 std::optional<CpuSample>)>;
 
   explicit CPUResultConverter(std::unique_ptr<CpuProbe> system_cpu_probe);
   ~CPUResultConverter() = default;
@@ -130,7 +129,7 @@
   void StartNextInterval(ResultCallback result_callback,
                          base::TimeTicks time,
                          const QueryResultMap& results,
-                         std::optional<PressureSample> system_cpu);
+                         std::optional<CpuSample> system_cpu);
 
   std::unique_ptr<CpuProbe> system_cpu_probe_;
   resource_attribution::CPUProportionTracker proportion_tracker_;
@@ -196,7 +195,7 @@
 void PageResourceMonitor::OnPageResourceUsageResult(
     const QueryResultMap& results,
     const PageCPUUsageMap& page_cpu_usage,
-    std::optional<PressureSample> system_cpu) {
+    std::optional<CpuSample> system_cpu) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Calculate the overall CPU usage.
@@ -328,7 +327,7 @@
 
 void PageResourceMonitor::OnDelayedCPUInterventionMetricsResult(
     const PageCPUUsageMap& page_cpu_usage,
-    std::optional<PressureSample> system_cpu) {
+    std::optional<CpuSample> system_cpu) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Now that results are received, stop the delayed CPU probe and proportion
   // tracking.
@@ -349,7 +348,7 @@
 
 void PageResourceMonitor::LogCPUInterventionMetrics(
     const PageCPUUsageMap& page_cpu_usage,
-    const std::optional<PressureSample>& system_cpu,
+    const std::optional<CpuSample>& system_cpu,
     const base::TimeTicks now,
     CPUInterventionSuffix histogram_suffix) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -561,7 +560,7 @@
     CPUResultConverter::ResultCallback result_callback,
     base::TimeTicks time,
     const QueryResultMap& results,
-    std::optional<PressureSample> system_cpu) {
+    std::optional<CpuSample> system_cpu) {
   std::move(result_callback)
       .Run(proportion_tracker_.StartNextInterval(time, results),
            std::move(system_cpu));
diff --git a/chrome/browser/performance_manager/metrics/page_resource_monitor.h b/chrome/browser/performance_manager/metrics/page_resource_monitor.h
index cee4ba8..ab7faf4 100644
--- a/chrome/browser/performance_manager/metrics/page_resource_monitor.h
+++ b/chrome/browser/performance_manager/metrics/page_resource_monitor.h
@@ -18,7 +18,7 @@
 #include "components/performance_manager/public/resource_attribution/queries.h"
 #include "components/performance_manager/public/resource_attribution/query_results.h"
 #include "components/performance_manager/public/resource_attribution/resource_contexts.h"
-#include "components/system_cpu/pressure_sample.h"
+#include "components/system_cpu/cpu_sample.h"
 
 namespace performance_manager::metrics {
 
@@ -104,7 +104,7 @@
   void OnPageResourceUsageResult(
       const resource_attribution::QueryResultMap& results,
       const PageCPUUsageMap& page_cpu_usage,
-      std::optional<system_cpu::PressureSample> system_cpu);
+      std::optional<system_cpu::CpuSample> system_cpu);
 
   // Asynchronously checks if the CPU metrics are still above the threshold
   // after a delay.
@@ -114,12 +114,12 @@
   // page and system CPU measurements are ready.
   void OnDelayedCPUInterventionMetricsResult(
       const PageCPUUsageMap& page_cpu_usage,
-      std::optional<system_cpu::PressureSample> system_cpu);
+      std::optional<system_cpu::CpuSample> system_cpu);
 
   // Log CPU intervention metrics with the provided suffix.
   void LogCPUInterventionMetrics(
       const PageCPUUsageMap& page_cpu_usage,
-      const std::optional<system_cpu::PressureSample>& system_cpu,
+      const std::optional<system_cpu::CpuSample>& system_cpu,
       const base::TimeTicks now,
       CPUInterventionSuffix histogram_suffix);
 
diff --git a/chrome/browser/preloading/chrome_preloading.h b/chrome/browser/preloading/chrome_preloading.h
index 88fd2b0a..1ab1d95 100644
--- a/chrome/browser/preloading/chrome_preloading.h
+++ b/chrome/browser/preloading/chrome_preloading.h
@@ -110,6 +110,14 @@
 // be reused in the future.
 static constexpr content::PreloadingPredictor kLinkPreview(112, "LinkPreview");
 
+// When a mousehover or mousedown event happens on a bookmark bar linking to an
+// HTTPS origin, we may attempt to preload the link. This predictor, instead of
+// using kPointerDownOnBookmarkBar or kMouseHoverOnBookmarkBar, is for solving
+// the problem in https://crbug.com/1516514.
+static constexpr content::PreloadingPredictor
+    kMouseHoverOrMouseDownOnBookmarkBar(113,
+                                        "MouseHoverOrMouseDownOnBookmarkBar");
+
 // TODO(crbug.com/1309934): Integrate more Preloading predictors with
 // Preloading logging APIs.
 }  // namespace chrome_preloading_predictor
diff --git a/chrome/browser/preloading/prerender/prerender_manager.cc b/chrome/browser/preloading/prerender/prerender_manager.cc
index 890e4c5..d4ca11a2 100644
--- a/chrome/browser/preloading/prerender/prerender_manager.cc
+++ b/chrome/browser/preloading/prerender/prerender_manager.cc
@@ -233,9 +233,7 @@
 }
 
 base::WeakPtr<content::PrerenderHandle>
-PrerenderManager::StartPrerenderBookmark(
-    const GURL& prerendering_url,
-    content::PreloadingPredictor predictor) {
+PrerenderManager::StartPrerenderBookmark(const GURL& prerendering_url) {
   // Helpers to create content::PreloadingAttempt.
   auto* preloading_data =
       content::PreloadingData::GetOrCreateForWebContents(web_contents());
@@ -246,8 +244,8 @@
   // this prerendering attempt for Prerender.
   content::PreloadingAttempt* preloading_attempt =
       preloading_data->AddPreloadingAttempt(
-          predictor, content::PreloadingType::kPrerender,
-          std::move(same_url_matcher),
+          chrome_preloading_predictor::kMouseHoverOrMouseDownOnBookmarkBar,
+          content::PreloadingType::kPrerender, std::move(same_url_matcher),
           web_contents()->GetPrimaryMainFrame()->GetPageUkmSourceId());
 
   // BookmarkBar only allow https protocol.
diff --git a/chrome/browser/preloading/prerender/prerender_manager.h b/chrome/browser/preloading/prerender/prerender_manager.h
index bb2b737..6b44e1b 100644
--- a/chrome/browser/preloading/prerender/prerender_manager.h
+++ b/chrome/browser/preloading/prerender/prerender_manager.h
@@ -74,8 +74,7 @@
   // from the on-going one. If the url given is already on-going, this function
   // will return the weak pointer to the on-going prerender handle.
   base::WeakPtr<content::PrerenderHandle> StartPrerenderBookmark(
-      const GURL& prerendering_url,
-      content::PreloadingPredictor predictor);
+      const GURL& prerendering_url);
   void StopPrerenderBookmark(
       base::WeakPtr<content::PrerenderHandle> prerender_handle);
 
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 9149e11..7f0f101 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -232,6 +232,7 @@
 #include "components/site_engagement/content/site_engagement_service.h"
 #include "components/spellcheck/spellcheck_buildflags.h"
 #include "components/supervised_user/core/common/buildflags.h"
+#include "components/sync/base/features.h"
 #include "extensions/buildflags/buildflags.h"
 #include "media/base/media_switches.h"
 #include "ppapi/buildflags/buildflags.h"
@@ -1261,8 +1262,7 @@
 #endif
 #if BUILDFLAG(IS_ANDROID)
   WebApkInstallServiceFactory::GetInstance();
-  if (base::FeatureList::IsEnabled(
-          chrome::android::kWebApkBackupAndRestoreBackend)) {
+  if (base::FeatureList::IsEnabled(syncer::kWebApkBackupAndRestoreBackend)) {
     webapk::WebApkSyncServiceFactory::GetInstance();
   }
 #endif
diff --git a/chrome/browser/readaloud/android/BUILD.gn b/chrome/browser/readaloud/android/BUILD.gn
index 9e46b752..815d8bc 100644
--- a/chrome/browser/readaloud/android/BUILD.gn
+++ b/chrome/browser/readaloud/android/BUILD.gn
@@ -121,6 +121,7 @@
     "java/res/layout/readaloud_mini_player_layout.xml",
     "java/res/layout/readaloud_radio_button.xml",
     "java/res/layout/readaloud_toggle_switch.xml",
+    "java/res/values/attrs.xml",
     "java/res/values/colors.xml",
     "java/res/values/dimens.xml",
   ]
@@ -240,6 +241,7 @@
     "java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerMediator.java",
     "java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerSheetContent.java",
     "java/src/org/chromium/chrome/browser/readaloud/player/expanded/ExpandedPlayerViewBinder.java",
+    "java/src/org/chromium/chrome/browser/readaloud/player/expanded/MaxHeightScrollView.java",
     "java/src/org/chromium/chrome/browser/readaloud/player/expanded/Menu.java",
     "java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuItem.java",
     "java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuSheetContent.java",
diff --git a/chrome/browser/readaloud/android/java/res/layout/readaloud_menu.xml b/chrome/browser/readaloud/android/java/res/layout/readaloud_menu.xml
index 0dacc80..e36fa318 100644
--- a/chrome/browser/readaloud/android/java/res/layout/readaloud_menu.xml
+++ b/chrome/browser/readaloud/android/java/res/layout/readaloud_menu.xml
@@ -41,7 +41,8 @@
     </LinearLayout>
 
     <!-- Scroll view in case there are a lot of items. -->
-    <ScrollView
+    <org.chromium.chrome.browser.readaloud.player.expanded.MaxHeightScrollView
+        app:maxHeight="586dp"
         android:id="@+id/items_scroll_view"
         android:layout_width="match_parent"
         android:layout_height="wrap_content">
@@ -53,6 +54,6 @@
             android:orientation="vertical">
             <!-- Menu items and headings are added programmatically here. -->
         </LinearLayout>
-    </ScrollView>
+    </org.chromium.chrome.browser.readaloud.player.expanded.MaxHeightScrollView>
 
 </org.chromium.chrome.browser.readaloud.player.expanded.Menu>
\ No newline at end of file
diff --git a/chrome/browser/readaloud/android/java/res/layout/readaloud_menu_item.xml b/chrome/browser/readaloud/android/java/res/layout/readaloud_menu_item.xml
index 792ac6aa..72ee07e7 100644
--- a/chrome/browser/readaloud/android/java/res/layout/readaloud_menu_item.xml
+++ b/chrome/browser/readaloud/android/java/res/layout/readaloud_menu_item.xml
@@ -9,64 +9,80 @@
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:paddingVertical="12dp"
-    android:orientation="horizontal"
-    android:background="@drawable/rounded_ripple">
-    <ImageView
-        android:id="@+id/icon"
-        android:layout_width="wrap_content"
-        android:layout_height="24dp"
-        android:layout_weight="0"
-        android:layout_gravity="center_vertical"
-        android:layout_marginEnd="16dp"
-        android:visibility="gone"
-        android:importantForAccessibility="no"/>
-    <ProgressBar
-        android:id="@+id/spinner"
-        style="?android:attr/progressBarStyleLarge"
-        android:layout_width="@dimen/preview_play_button_diameter"
-        android:layout_height="@dimen/preview_play_button_diameter"
-        android:layout_marginEnd="@dimen/preview_play_button_margin_end"
-        android:visibility="gone"
-        android:focusable="true"/>
-    <ImageView
-        android:id="@+id/play_button"
-        android:layout_width="@dimen/preview_play_button_diameter"
-        android:layout_height="@dimen/preview_play_button_diameter"
-        android:layout_gravity="center_vertical"
-        android:layout_marginEnd="@dimen/preview_play_button_margin_end"
-        android:visibility="gone"
-        android:src="@drawable/mini_play_button"
-        android:background="@drawable/rounded_ripple"
-        android:clickable="true"
-        android:focusable="true"/>
+    android:orientation="vertical">
+
+    <TextView
+          android:id="@+id/item_header"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:paddingTop="20dp"
+          android:paddingBottom="4dp"
+          android:ellipsize="end"
+          android:maxLines="1"
+          android:textAppearance="@style/TextAppearance.TextMediumThick.Primary"/>
+
     <LinearLayout
-        android:layout_width="fill_parent"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:layout_gravity="center_vertical"
-        android:orientation="vertical">
-        <TextView
-            android:id="@+id/item_label"
+        android:orientation="horizontal"
+        android:paddingVertical="12dp"
+        android:background="@drawable/rounded_ripple">
+        <ImageView
+            android:id="@+id/icon"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:ellipsize="end"
-            android:maxLines="1"
-            android:textAppearance="@style/TextAppearance.TextLarge.Primary"/>
-        <TextView
-            android:id="@+id/item_sublabel"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
+            android:layout_height="24dp"
+            android:layout_weight="0"
+            android:layout_gravity="center_vertical"
+            android:layout_marginEnd="16dp"
             android:visibility="gone"
-            android:ellipsize="end"
-            android:maxLines="1"
-            android:textAppearance="@style/TextAppearance.TextMedium.Secondary"/>
+            android:importantForAccessibility="no"/>
+        <ProgressBar
+            android:id="@+id/spinner"
+            style="?android:attr/progressBarStyleLarge"
+            android:layout_width="@dimen/preview_play_button_diameter"
+            android:layout_height="@dimen/preview_play_button_diameter"
+            android:layout_marginEnd="@dimen/preview_play_button_margin_end"
+            android:visibility="gone"
+            android:focusable="true"/>
+        <ImageView
+            android:id="@+id/play_button"
+            android:layout_width="@dimen/preview_play_button_diameter"
+            android:layout_height="@dimen/preview_play_button_diameter"
+            android:layout_gravity="center_vertical"
+            android:layout_marginEnd="@dimen/preview_play_button_margin_end"
+            android:visibility="gone"
+            android:src="@drawable/mini_play_button"
+            android:background="@drawable/rounded_ripple"
+            android:clickable="true"
+            android:focusable="true"/>
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_gravity="center_vertical"
+            android:orientation="vertical">
+            <TextView
+                android:id="@+id/item_label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:ellipsize="end"
+                android:maxLines="1"
+                android:textAppearance="@style/TextAppearance.TextLarge.Primary"/>
+            <TextView
+                android:id="@+id/item_sublabel"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:visibility="gone"
+                android:ellipsize="end"
+                android:maxLines="1"
+                android:textAppearance="@style/TextAppearance.TextMedium.Secondary"/>
+        </LinearLayout>
+        <!-- Menu items that have images/radio buttons/toggles should place them here. -->
+        <FrameLayout
+            android:id="@+id/end_view"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_weight="0"/>
     </LinearLayout>
-    <!-- Menu items that have images/radio buttons/toggles should place them here. -->
-    <FrameLayout
-        android:id="@+id/end_view"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:layout_weight="0"/>
 </LinearLayout>
\ No newline at end of file
diff --git a/chrome/browser/readaloud/android/java/res/values/attrs.xml b/chrome/browser/readaloud/android/java/res/values/attrs.xml
new file mode 100644
index 0000000..799c44c
--- /dev/null
+++ b/chrome/browser/readaloud/android/java/res/values/attrs.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+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.
+-->
+
+<resources>
+    <declare-styleable name="MaxHeightScrollView">
+       <attr name="maxHeight" format="dimension"/>
+    </declare-styleable>
+</resources>
\ No newline at end of file
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MaxHeightScrollView.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MaxHeightScrollView.java
new file mode 100644
index 0000000..c45bb4f
--- /dev/null
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MaxHeightScrollView.java
@@ -0,0 +1,46 @@
+// 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.
+
+package org.chromium.chrome.browser.readaloud.player.expanded;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.widget.ScrollView;
+
+import org.chromium.chrome.browser.readaloud.player.R;
+
+/** An implementation of scroll view with enforced max height. */
+public class MaxHeightScrollView extends ScrollView {
+    private int mMaxHeight;
+
+    public MaxHeightScrollView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(attrs);
+    }
+
+    public MaxHeightScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(attrs);
+    }
+
+    public MaxHeightScrollView(
+            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init(attrs);
+    }
+
+    private void init(AttributeSet attrs) {
+        TypedArray a =
+                getContext().obtainStyledAttributes(attrs, R.styleable.MaxHeightScrollView, 0, 0);
+        mMaxHeight = a.getDimensionPixelSize(R.styleable.MaxHeightScrollView_maxHeight, 0);
+        a.recycle();
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        heightMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxHeight, MeasureSpec.AT_MOST);
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+}
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/Menu.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/Menu.java
index c471048..2204844 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/Menu.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/Menu.java
@@ -9,6 +9,8 @@
 import android.view.ViewGroup.LayoutParams;
 import android.widget.LinearLayout;
 
+import androidx.annotation.Nullable;
+
 import org.chromium.base.Callback;
 import org.chromium.chrome.browser.readaloud.player.R;
 
@@ -35,11 +37,16 @@
         mLastItemIndex = -1;
     }
 
-    public MenuItem addItem(int itemId, int iconId, String label, @MenuItem.Action int action) {
+    public MenuItem addItem(
+            int itemId,
+            int iconId,
+            String label,
+            @Nullable String header,
+            @MenuItem.Action int action) {
         if (mItemsContainer == null) {
             mItemsContainer = (LinearLayout) findViewById(R.id.items_container);
         }
-        MenuItem item = new MenuItem(mContext, this, itemId, iconId, label, action);
+        MenuItem item = new MenuItem(mContext, this, itemId, iconId, label, header, action);
         mItemsContainer.addView(
                 item,
                 /* width= */ LayoutParams.MATCH_PARENT,
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuItem.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuItem.java
index 338ef91..1fbe1ed5 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuItem.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuItem.java
@@ -18,6 +18,7 @@
 import android.widget.TextView;
 
 import androidx.annotation.IntDef;
+import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.appcompat.widget.SwitchCompat;
 
@@ -77,6 +78,7 @@
             int itemId,
             int iconId,
             String label,
+            @Nullable String header,
             @Action int action) {
         super(context);
         mMenu = parentMenu;
@@ -98,6 +100,13 @@
             // Icon is GONE by default.
             icon.setVisibility(View.VISIBLE);
         }
+        TextView localeView = layout.findViewById(R.id.item_header);
+        if (header == null) {
+            localeView.setVisibility(View.GONE);
+        } else {
+            localeView.setVisibility(View.VISIBLE);
+            localeView.setText(header);
+        }
 
         ((TextView) layout.findViewById(R.id.item_label)).setText(label);
 
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuUnitTest.java
index 03093fb..1c665c8 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuUnitTest.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/MenuUnitTest.java
@@ -64,7 +64,7 @@
 
     @Test
     public void testAddGetItem() {
-        MenuItem item = mMenu.addItem(1, 0, "test item", Action.NONE);
+        MenuItem item = mMenu.addItem(1, 0, "test item", /* header= */ null, Action.NONE);
         MenuItem recievedItem = mMenu.getItem(1);
         assertEquals(item, recievedItem);
 
@@ -74,14 +74,14 @@
 
     @Test
     public void testExpandAction() {
-        MenuItem item = mMenu.addItem(1, 0, "Expand action", Action.EXPAND);
+        MenuItem item = mMenu.addItem(1, 0, "Expand action", /* header= */ null, Action.EXPAND);
         assertEquals(mMenu.getItem(1), item);
     }
 
     @Test
     public void testActionToggle() {
         // addItem and setValue
-        MenuItem item = mMenu.addItem(1, 0, "Toggle action", Action.TOGGLE);
+        MenuItem item = mMenu.addItem(1, 0, "Toggle action", /* header= */ null, Action.TOGGLE);
         item.setValue(true);
         SwitchCompat toggle = (SwitchCompat) item.findViewById(R.id.toggle_switch);
         assertTrue(toggle.isChecked());
@@ -99,7 +99,7 @@
     @Test
     public void testActionRadio() {
         // addItem and setValue
-        MenuItem item = mMenu.addItem(1, 0, "Radio action", Action.RADIO);
+        MenuItem item = mMenu.addItem(1, 0, "Radio action", /* header= */ null, Action.RADIO);
         item.setValue(true);
         RadioButton radioButton = (RadioButton) item.findViewById(R.id.readaloud_radio_button);
         assertTrue(radioButton.isChecked());
@@ -120,7 +120,7 @@
 
     @Test
     public void testSetItemEnabled() {
-        MenuItem item = mMenu.addItem(1, 0, "test item", Action.TOGGLE);
+        MenuItem item = mMenu.addItem(1, 0, "test item", /* header= */ null, Action.TOGGLE);
         item.setToggleHandler(mToggleHandler);
         item.setItemEnabled(false);
 
@@ -130,7 +130,7 @@
 
     @Test
     public void testClearItems() {
-        MenuItem item = mMenu.addItem(1, 0, "test item", Action.NONE);
+        MenuItem item = mMenu.addItem(1, 0, "test item", /* header= */ null, Action.NONE);
         assertEquals(item, mMenu.getItem(1));
         mMenu.clearItems();
         assertEquals(null, mMenu.getItem(1));
@@ -146,7 +146,7 @@
     @Test
     public void testAddPlayButton_OnPlayButtonClicked() {
         mMenu.setPlayButtonClickHandler(mHandler);
-        MenuItem item = mMenu.addItem(1, 0, "test item", Action.NONE);
+        MenuItem item = mMenu.addItem(1, 0, "test item", /* header= */ null, Action.NONE);
         item.addPlayButton();
         ImageView playButton = (ImageView) item.findViewById(R.id.play_button);
         assertEquals(View.VISIBLE, playButton.getVisibility());
@@ -164,7 +164,7 @@
     public void testOnRadioButtonSelected() {
         mMenu.setRadioTrueHandler(mHandler);
         for (int i = 0; i < 3; i++) {
-            mMenu.addItem(i, 0, "test item", Action.RADIO);
+            mMenu.addItem(i, 0, "test item", /* header= */ null, Action.RADIO);
         }
         mMenu.onRadioButtonSelected(0);
         mMenu.onRadioButtonSelected(1);
@@ -179,7 +179,7 @@
 
     @Test
     public void testMenuItemLayoutInflated() {
-        MenuItem item = mMenu.addItem(1, 0, "testToggle", Action.TOGGLE);
+        MenuItem item = mMenu.addItem(1, 0, "testToggle", /* header= */ null, Action.TOGGLE);
         LinearLayout layout =
                 (LinearLayout)
                         mActivity.getLayoutInflater().inflate(R.layout.readaloud_menu_item, null);
@@ -222,7 +222,7 @@
 
     @Test
     public void testMenuItemLayoutInflated_NothingForActionExpand() {
-        MenuItem item = mMenu.addItem(1, 0, "testExpand", Action.EXPAND);
+        MenuItem item = mMenu.addItem(1, 0, "testExpand", /* header= */ null, Action.EXPAND);
         LinearLayout layout =
                 (LinearLayout)
                         mActivity.getLayoutInflater().inflate(R.layout.readaloud_menu_item, null);
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/OptionsMenuSheetContent.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/OptionsMenuSheetContent.java
index f5491ee..0be6d85 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/OptionsMenuSheetContent.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/OptionsMenuSheetContent.java
@@ -67,11 +67,13 @@
                 Item.VOICE,
                 R.drawable.voice_selection_24,
                 res.getString(R.string.readaloud_voice_menu_title),
+                /* header */ null,
                 MenuItem.Action.EXPAND);
         mMenu.addItem(
                 Item.HIGHLIGHT,
                 R.drawable.format_ink_highlighter_24,
                 res.getString(R.string.readaloud_highlight_toggle_name),
+                /*header*/ null,
                 MenuItem.Action.TOGGLE);
 
         mMenu.setItemClickHandler(this::onClick);
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/OptionsMenuSheetContentUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/OptionsMenuSheetContentUnitTest.java
index 6abfe37..afc6555 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/OptionsMenuSheetContentUnitTest.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/OptionsMenuSheetContentUnitTest.java
@@ -67,7 +67,15 @@
 
     @Test
     public void testClickVoiceMenu() {
-        doReturn(List.of(new PlaybackVoice("en", "a")))
+        doReturn(
+                        List.of(
+                                new PlaybackVoice(
+                                        "en",
+                                        "US",
+                                        "a",
+                                        "Sand",
+                                        PlaybackVoice.Pitch.NONE,
+                                        PlaybackVoice.Tone.NONE)))
                 .when(mModel)
                 .get(eq(PlayerProperties.VOICES_LIST));
         doReturn("a").when(mModel).get(eq(PlayerProperties.SELECTED_VOICE_ID));
@@ -97,7 +105,15 @@
     @Test
     public void testCloseVoiceMenu() {
         // Show the voice menu.
-        doReturn(List.of(new PlaybackVoice("en", "a", "description")))
+        doReturn(
+                        List.of(
+                                new PlaybackVoice(
+                                        "en",
+                                        "US",
+                                        "a",
+                                        "Sand",
+                                        PlaybackVoice.Pitch.NONE,
+                                        PlaybackVoice.Tone.NONE)))
                 .when(mModel)
                 .get(eq(PlayerProperties.VOICES_LIST));
         doReturn("a").when(mModel).get(eq(PlayerProperties.SELECTED_VOICE_ID));
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/SpeedMenuSheetContent.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/SpeedMenuSheetContent.java
index db89598..c77ee3c 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/SpeedMenuSheetContent.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/SpeedMenuSheetContent.java
@@ -53,7 +53,8 @@
             String speedString =
                     mContext.getResources()
                             .getString(R.string.readaloud_speed, speedFormatter(mSpeeds[i]));
-            MenuItem item = mMenu.addItem(i, 0, speedString, MenuItem.Action.RADIO);
+            MenuItem item =
+                    mMenu.addItem(i, 0, speedString, /* header= */ null, MenuItem.Action.RADIO);
             if (mSpeeds[i] == currentSpeed) {
                 item.setValue(true);
             }
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/VoiceMenuSheetContent.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/VoiceMenuSheetContent.java
index 9f1ef89..3bdfb00 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/VoiceMenuSheetContent.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/VoiceMenuSheetContent.java
@@ -27,6 +27,7 @@
 
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 
 /** Bottom sheet content for Read Aloud voices menu. */
 class VoiceMenuSheetContent extends MenuSheetContent {
@@ -59,10 +60,22 @@
         mVoices = new PlaybackVoice[voices.size()];
 
         int id = 0;
+        String displayLocale = null;
         for (PlaybackVoice voice : voices) {
+            if (id == 0 || isDifferentLocale(voice, voices.get(id - 1))) {
+                displayLocale =
+                        new Locale(voice.getLanguage(), voice.getAccentRegionCode())
+                                .getDisplayName();
+            } else {
+                displayLocale = null;
+            }
             MenuItem item =
                     mMenu.addItem(
-                            id, /* iconId= */ 0, voice.getDisplayName(), MenuItem.Action.RADIO);
+                            id,
+                            /* iconId= */ 0,
+                            voice.getDisplayName(),
+                            displayLocale,
+                            MenuItem.Action.RADIO);
             item.addPlayButton();
             String secondLine = getAttributesString(voice);
             if (secondLine != null) {
@@ -74,6 +87,11 @@
         }
     }
 
+    private boolean isDifferentLocale(PlaybackVoice current, PlaybackVoice previous) {
+        return (!current.getLanguage().equals(previous.getLanguage())
+                || !current.getAccentRegionCode().equals(previous.getAccentRegionCode()));
+    }
+
     void setVoiceSelection(String voiceId) {
         if (mVoices.length == 0) {
             return;
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/VoiceMenuSheetContentUnitTest.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/VoiceMenuSheetContentUnitTest.java
index b515757..945a3e59 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/VoiceMenuSheetContentUnitTest.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/player/expanded/VoiceMenuSheetContentUnitTest.java
@@ -68,9 +68,9 @@
                         .with(
                                 PlayerProperties.VOICES_LIST,
                                 List.of(
-                                        createVoice("en", "a", "voice a"),
-                                        createVoice("en", "b", "voice b"),
-                                        createVoice("en", "c", "voice c")))
+                                        createVoice("a", "voice a"),
+                                        createVoice("b", "voice b"),
+                                        createVoice("c", "voice c")))
                         .with(PlayerProperties.SELECTED_VOICE_ID, "a")
                         .build();
         mContent = new VoiceMenuSheetContent(mActivity, mParent, mBottomSheetController, mModel);
@@ -101,17 +101,9 @@
         mContent.setVoices(
                 List.of(
                         createVoice(
-                                "en",
-                                "d",
-                                "voice d",
-                                PlaybackVoice.Pitch.LOW,
-                                PlaybackVoice.Tone.SMOOTH),
+                                "a", "voice d", PlaybackVoice.Pitch.LOW, PlaybackVoice.Tone.SMOOTH),
                         createVoice(
-                                "en",
-                                "e",
-                                "voice e",
-                                PlaybackVoice.Pitch.MID,
-                                PlaybackVoice.Tone.CALM)));
+                                "e", "voice e", PlaybackVoice.Pitch.MID, PlaybackVoice.Tone.CALM)));
 
         assertEquals("voice d", getText(mMenu.getItem(0), R.id.item_label));
         assertEquals("Low-pitch, Smooth", getText(mMenu.getItem(0), R.id.item_sublabel));
@@ -191,10 +183,6 @@
         return (RadioButton) item.findViewById(R.id.readaloud_radio_button);
     }
 
-    private static PlaybackVoice createVoice(String language, String id, String displayName) {
-        return createVoice(
-                language, id, displayName, PlaybackVoice.Pitch.NONE, PlaybackVoice.Tone.NONE);
-    }
 
     @Test
     public void testEmptyVoiceList() {
@@ -215,17 +203,9 @@
         mContent.setVoices(
                 List.of(
                         createVoice(
-                                "en",
-                                "d",
-                                "voice d",
-                                PlaybackVoice.Pitch.LOW,
-                                PlaybackVoice.Tone.SMOOTH),
+                                "d", "voice d", PlaybackVoice.Pitch.LOW, PlaybackVoice.Tone.SMOOTH),
                         createVoice(
-                                "en",
-                                "e",
-                                "voice e",
-                                PlaybackVoice.Pitch.MID,
-                                PlaybackVoice.Tone.CALM)));
+                                "e", "voice e", PlaybackVoice.Pitch.MID, PlaybackVoice.Tone.CALM)));
 
         assertEquals("voice d", getText(mMenu.getItem(0), R.id.item_label));
         assertEquals("Low-pitch, Smooth", getText(mMenu.getItem(0), R.id.item_sublabel));
@@ -233,13 +213,36 @@
         assertEquals("Mid-pitch, Calm", getText(mMenu.getItem(1), R.id.item_sublabel));
     }
 
+    @Test
+    public void testLocaleLabel() {
+        mContent.setVoices(
+                List.of(
+                        createVoice(
+                                "a", "voice d", PlaybackVoice.Pitch.LOW, PlaybackVoice.Tone.SMOOTH),
+                        createVoice(
+                                "e", "voice e", PlaybackVoice.Pitch.MID, PlaybackVoice.Tone.CALM),
+                        new PlaybackVoice(
+                                "en",
+                                "IN",
+                                "in",
+                                "voice in",
+                                PlaybackVoice.Pitch.MID,
+                                PlaybackVoice.Tone.CALM)));
+
+        assertEquals("English (United States)", getText(mMenu.getItem(0), R.id.item_header));
+        assertEquals("", getText(mMenu.getItem(1), R.id.item_header));
+        assertEquals("English (India)", getText(mMenu.getItem(2), R.id.item_header));
+    }
+
+    private static PlaybackVoice createVoice(String id, String displayName) {
+        return createVoice(id, displayName, PlaybackVoice.Pitch.NONE, PlaybackVoice.Tone.NONE);
+    }
+
     private static PlaybackVoice createVoice(
-            String language,
             String id,
             String displayName,
             @PlaybackVoice.Pitch int pitch,
             @PlaybackVoice.Tone int tone) {
-        return new PlaybackVoice(
-                language, /* accentRegionCode= */ null, id, displayName, pitch, tone);
+        return new PlaybackVoice("en", "US", id, displayName, pitch, tone);
     }
 }
diff --git a/chrome/browser/resources/accessibility/accessibility.ts b/chrome/browser/resources/accessibility/accessibility.ts
index 35705ba..0495ce3 100644
--- a/chrome/browser/resources/accessibility/accessibility.ts
+++ b/chrome/browser/resources/accessibility/accessibility.ts
@@ -19,7 +19,7 @@
   HTML = 1 << 4,
   HTML_METADATA = 1 << 5,
   LABEL_IMAGES = 1 << 6,
-  PDF = 1 << 7,
+  PDF_PRINTING = 1 << 7,
   PDF_OCR = 1 << 8,
 }
 
@@ -46,7 +46,7 @@
   // chrome/browser/accessibility/accessibility_ui.cc.
   metadata: boolean,
   native: boolean,
-  pdf: boolean,
+  pdfPrinting: boolean,
   screenreader: boolean,
   web: boolean,
 
@@ -71,7 +71,7 @@
   html: EnabledStatus;
   internal: EnabledStatus;
   native: EnabledStatus;
-  pdf: EnabledStatus;
+  pdfPrinting: EnabledStatus;
   screenreader: EnabledStatus;
   text: EnabledStatus;
   web: EnabledStatus;
@@ -79,7 +79,7 @@
 
 type RequestType = 'showOrRefreshTree';
 
-type GlobalStateName = 'native'|'web'|'metadata'|'pdf'|'screenreader';
+type GlobalStateName = 'native'|'web'|'metadata'|'pdfPrinting'|'screenreader';
 
 class BrowserProxy {
   toggleAccessibility(
@@ -364,7 +364,8 @@
     row.appendChild(createModeElement(AxMode.HTML, pageData, 'web'));
     row.appendChild(
         createModeElement(AxMode.HTML_METADATA, pageData, 'metadata'));
-    row.appendChild(createModeElement(AxMode.PDF, pageData, 'pdf'));
+    row.appendChild(
+        createModeElement(AxMode.PDF_PRINTING, pageData, 'pdfPrinting'));
     row.appendChild(createModeElement(
         AxMode.LABEL_IMAGES, pageData, 'screenreader',
         /*readonly=*/ true));
@@ -467,8 +468,8 @@
       return 'HTML Metadata';
     case AxMode.LABEL_IMAGES:
       return 'Label images';
-    case AxMode.PDF:
-      return 'PDF';
+    case AxMode.PDF_PRINTING:
+      return 'PDF printing';
     case AxMode.PDF_OCR:
       return 'PDF OCR';
     default:
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn
index 8786dce4..423de30 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/BUILD.gn
@@ -92,6 +92,7 @@
 }
 
 ts_definitions = [
+  "dictation/parse/pumpkin/pumpkin_tagger_externs.d.ts",
   "../definitions/accessibility_features_mv2.d.ts",
   "../definitions/accessibility_private_mv2.d.ts",
   "../definitions/audio.d.ts",
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/pumpkin/pumpkin_tagger_externs.d.ts b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/pumpkin/pumpkin_tagger_externs.d.ts
new file mode 100644
index 0000000..5126784
--- /dev/null
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/pumpkin/pumpkin_tagger_externs.d.ts
@@ -0,0 +1,72 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Externs for PumpkinTagger. These are added on an as-needed
+ * basis.
+ */
+
+declare namespace proto {
+  export namespace speech {
+    export namespace pumpkin {
+      export interface ActionArgument {
+        name: string;
+        argumentType: string;
+        userType: string;
+        score: number;
+        unnormalizedValue: string;
+        value: any;
+      }
+
+      export interface HypothesisResult {
+        actionExportName: string;
+        actionName: string;
+        actionArgumentList: ActionArgument[];
+        score: number;
+        taggedHypothesis: string;
+      }
+
+      export interface PumpkinTaggerResults {
+        hypothesisList: HypothesisResult[];
+      }
+    }
+  }
+}
+
+declare namespace speech {
+  export namespace pumpkin {
+    export namespace api {
+      export namespace js {
+        export interface PumpkinTagger {
+          /**
+           * Loads the PumpkinTagger from a PumpkinConfig proto binary file.
+           * This proto file can be generated using
+           * pumpkin/tools/build_binary_configs which converts an
+           * pumpkin.config and directory of grammar .far files into a single
+           * binary file.
+           */
+          initializeFromPumpkinConfig:
+              (buffer: ArrayBuffer) => Promise<boolean>;
+          /**
+           * Loads an ActionFrame from an ActionSetConfig proto binary file.
+           * This proto file can be generated using
+           * pumpkin/tools/build_binary_configs which converts an
+           * action.config and directory of .far files into a single binary
+           * file.
+           */
+          loadActionFrame: (buffer: ArrayBuffer) => Promise<boolean>;
+          /**
+           * Cleans up C++ memory. Should be called before the tagger is
+           * deconstructed.
+           */
+          cleanUp: () => void;
+          /** Tags an input string and returns the results. */
+          tagAndGetNBestHypotheses:
+              (input: string,
+               numResults: number) => proto.speech.pumpkin.PumpkinTaggerResults;
+        }
+      }
+    }
+  }
+}
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/pumpkin/pumpkin_tagger_externs.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/pumpkin/pumpkin_tagger_externs.js
deleted file mode 100644
index fc174daa..0000000
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/dictation/parse/pumpkin/pumpkin_tagger_externs.js
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Externs for PumpkinTagger. These are added on an as-needed
- * basis.
- */
-
-const proto = {};
-
-/** @const */
-proto.speech = {};
-
-/** @const */
-proto.speech.pumpkin = {};
-
-/** @const */
-proto.speech.pumpkin.ActionArgument = {};
-
-/**
- * @typedef {{
- *   name: string,
- *   argumentType: string,
- *   userType: string,
- *   score: number,
- *   unnormalizedValue: string,
- * }}
- */
-proto.speech.pumpkin.ActionArgument.ObjectFormat = {};
-
-/** @const */
-proto.speech.pumpkin.HypothesisResult = {};
-
-/**
- * @typedef {{
- *   actionExportName: string,
- *   actionName: string,
- *   actionArgumentList:
- *       Array<proto.speech.pumpkin.ActionArgument.ObjectFormat>, score: number,
- *   taggedHypothesis: string,
- * }}
- */
-proto.speech.pumpkin.HypothesisResult.ObjectFormat = {};
-
-/** @const */
-proto.speech.pumpkin.PumpkinTaggerResults = {};
-
-/**
- * @typedef {{
- *   hypothesisList: Array<proto.speech.pumpkin.HypothesisResult.ObjectFormat>,
- * }}
- */
-proto.speech.pumpkin.PumpkinTaggerResults.ObjectFormat = {};
-
-const speech = {};
-
-/** @const */
-speech.pumpkin = {};
-
-/** @const */
-speech.pumpkin.api = {};
-
-/** @const */
-speech.pumpkin.api.js = {};
-
-/** @const */
-speech.pumpkin.api.js.PumpkinTagger = {};
-
-/** @constructor */
-speech.pumpkin.api.js.PumpkinTagger.PumpkinTagger = function() {};
-
-/**
- * Loads the PumpkinTagger from a PumpkinConfig proto binary file.
- * This proto file can be generated using pumpkin/tools/build_binary_configs
- * which converts an pumpkin.config and directory of grammar .far files into a
- * single binary file.
- * @param {!ArrayBuffer} buffer The pumpkin config binary file contents.
- * @return {!Promise<boolean>}
- */
-speech.pumpkin.api.js.PumpkinTagger.PumpkinTagger.prototype
-    .initializeFromPumpkinConfig = async function(buffer) {};
-
-/**
- * Loads an ActionFrame from an ActionSetConfig proto binary file.
- * This proto file can be generated using pumpkin/tools/build_binary_configs
- * which converts an action.config and directory of .far files into a single
- * binary file.
- * @param {!ArrayBuffer} buffer The action set config binary file contents.
- * @return {!Promise<boolean>}
- */
-speech.pumpkin.api.js.PumpkinTagger.PumpkinTagger.prototype.loadActionFrame =
-    async function(buffer) {};
-
-/**
- * Cleans up C++ memory. Should be called before the tagger is
- * deconstructed.
- */
-speech.pumpkin.api.js.PumpkinTagger.PumpkinTagger.prototype.cleanUp =
-    function() {};
-
-/**
- * Tags an input string and returns the results.
- * @param {string} input The string to tag.
- * @param {number} numResults The maximum number of results.
- * @return {?proto.speech.pumpkin.PumpkinTaggerResults.ObjectFormat}
- */
-speech.pumpkin.api.js.PumpkinTagger.PumpkinTagger.prototype
-    .tagAndGetNBestHypotheses = function(input, numResults) {};
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.ts b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.ts
index f541a227..14930ee 100644
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.ts
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.ts
@@ -5,6 +5,7 @@
 import {AutomationPredicate} from '/common/automation_predicate.js';
 import {AutomationUtil} from '/common/automation_util.js';
 import {constants} from '/common/constants.js';
+import {FlagName, Flags} from '/common/flags.js';
 import {NodeNavigationUtils} from '/common/node_navigation_utils.js';
 import {NodeUtils} from '/common/node_utils.js';
 import {ParagraphUtils} from '/common/paragraph_utils.js';
@@ -165,7 +166,7 @@
     this.init_();
   }
 
-  private init_(): void {
+  private async init_(): Promise<void> {
     chrome.automation.getDesktop(desktop => {
       this.desktop_ = desktop;
 
@@ -187,14 +188,26 @@
     this.runContentScripts_();
     this.setUpEventListeners_();
 
-    chrome.contextMenus.create({
+    await Flags.init();
+    const createArgs: chrome.contextMenus.CreateProperties = {
       title: chrome.i18n.getMessage(
           'select_to_speak_listen_context_menu_option_text'),
       contexts: [chrome.contextMenus.ContextType.SELECTION],
-      onclick: () => {
+      id: 'select_to_speak',
+    };
+    if (Flags.isEnabled(FlagName.MANIFEST_V3)) {
+      chrome.contextMenus.onClicked.addListener(() => {
         this.getFocusedNodeAndSpeakSelectedText_();
-      },
-    });
+      });
+    } else {
+      createArgs['onclick'] = () => {
+        this.getFocusedNodeAndSpeakSelectedText_();
+      };
+    }
+    // Install the context menu in the Ash browser.
+    await chrome.contextMenus.create(createArgs);
+
+    // Listen for context menu clicks from other contexts (like Lacros).
     chrome.accessibilityPrivate.onSelectToSpeakContextMenuClicked.addListener(
         () => {
           this.getFocusedNodeAndSpeakSelectedText_();
diff --git a/chrome/browser/resources/compose/animations/app_animator.ts b/chrome/browser/resources/compose/animations/app_animator.ts
index db06635..d50ad47 100644
--- a/chrome/browser/resources/compose/animations/app_animator.ts
+++ b/chrome/browser/resources/compose/animations/app_animator.ts
@@ -230,4 +230,46 @@
       this.fadeIn('#editContainer .footer', {delay: 100, duration: 100}),
     ].flat();
   }
+
+  transitionFromEditingToResult(resultContainerHeight: number): Animation[] {
+    const bodyGapHeightAnimation = this.animate(
+        '#body',
+        [
+          {gap: '0px'},
+          {gap: '8px'},
+        ],
+        {duration: 200, easing: STANDARD_EASING});
+
+    const resultContainerHeightAnimation = this.animate(
+        '#resultContainer',
+        [
+          {
+            height: '0px',
+            overflow: 'hidden',
+            alignItems: 'flex-end',
+          },
+          {
+            height: `${resultContainerHeight}px`,
+            overflow: 'hidden',
+            alignItems: 'flex-end',
+          },
+        ],
+        {duration: 200, easing: STANDARD_EASING});
+
+    return [
+      bodyGapHeightAnimation,
+      resultContainerHeightAnimation,
+
+      // Fade out edit form.
+      this.fadeOutAndHide('#editContainer', 'flex', {duration: 200}),
+      this.fadeOutAndHide('#editContainer .footer', 'flex', {duration: 100}),
+      this.maintainStyles(
+          '#editContainer .footer', {opacity: 0},
+          {delay: 100, duration: 100, fill: 'none'}),
+
+      // Fade in result UI.
+      this.fadeIn(
+          '#resultContainer, #resultFooter', {delay: 100, duration: 100}),
+    ].flat();
+  }
 }
diff --git a/chrome/browser/resources/compose/animations/textarea_animator.ts b/chrome/browser/resources/compose/animations/textarea_animator.ts
index 580c17d..0e77d480 100644
--- a/chrome/browser/resources/compose/animations/textarea_animator.ts
+++ b/chrome/browser/resources/compose/animations/textarea_animator.ts
@@ -49,6 +49,46 @@
     ].flat();
   }
 
+  transitionToResult(bodyHeight: number): Animation[] {
+    const dimensionsAnimation = this.animate(
+        '#inputContainer textarea, #readonlyContainer',
+        [
+          {
+            height: `${bodyHeight}px`,
+            padding: 'var(--compose-textarea-input-padding)',
+          },
+          {
+            height: 'var(--compose-textarea-readonly-height)',
+            padding: 'var(--compose-textarea-readonly-padding)',
+          },
+        ],
+        {duration: 200, easing: STANDARD_EASING});
+
+    const colorAnimation = this.animate(
+        '#inputContainer textarea, #readonlyContainer',
+        [
+          {
+            background: 'transparent',
+          },
+          {
+            background: 'var(--compose-textarea-readonly-background)',
+            outlineColor: 'transparent',
+          },
+        ],
+        {duration: 100, easing: 'linear'});
+
+    return [
+      dimensionsAnimation,
+      colorAnimation,
+
+      // Hide scrollbar resulting from shrinking textarea.
+      this.maintainStyles(
+          '#inputContainer textarea', {overflow: 'hidden'}, {duration: 200}),
+      // Fade in edit button.
+      this.fadeIn('#editButton', {delay: 100, duration: 100}),
+    ].flat();
+  }
+
   transitionToReadonly(fromHeight?: number): Animation[] {
     const fromHeightValue =
         fromHeight ? `${fromHeight}px` : 'var(--compose-textarea-input-height)';
diff --git a/chrome/browser/resources/compose/app.ts b/chrome/browser/resources/compose/app.ts
index b9b5e582..ba6d02a 100644
--- a/chrome/browser/resources/compose/app.ts
+++ b/chrome/browser/resources/compose/app.ts
@@ -422,8 +422,13 @@
   }
 
   private onCancelEditClick_() {
+    const fullBodyHeight = this.$.body.offsetHeight;
+    const resultContainerHeight = this.$.resultContainer.offsetHeight;
     this.isEditingSubmittedInput_ = false;
     this.$.textarea.focusEditButton();
+    this.animator_.transitionFromEditingToResult(resultContainerHeight);
+    this.$.textarea.transitionToResult(fullBodyHeight);
+    this.$.editTextarea.transitionToResult(fullBodyHeight);
   }
 
   private onClose_(e: Event) {
diff --git a/chrome/browser/resources/compose/textarea.ts b/chrome/browser/resources/compose/textarea.ts
index 503557b..b8ca2d4 100644
--- a/chrome/browser/resources/compose/textarea.ts
+++ b/chrome/browser/resources/compose/textarea.ts
@@ -129,6 +129,10 @@
     this.animator_.transitionToEditing(bodyHeight);
   }
 
+  transitionToResult(bodyHeight: number) {
+    this.animator_.transitionToResult(bodyHeight);
+  }
+
   validate() {
     const value = this.$.input.value;
     const wordCount = value.match(/\S+/g)?.length || 0;
diff --git a/chrome/browser/resources/side_panel/read_anything/app.html b/chrome/browser/resources/side_panel/read_anything/app.html
index a30a4c3..c67cb52c 100644
--- a/chrome/browser/resources/side_panel/read_anything/app.html
+++ b/chrome/browser/resources/side_panel/read_anything/app.html
@@ -80,6 +80,7 @@
       preview-voice-playing="[[previewVoicePlaying]]"
       on-select-voice="onSelectVoice_"
       on-preview-voice="onPreviewVoice_"
+      on-voice-menu-close="onVoiceMenuClose_"
       id="toolbar">
     </read-anything-toolbar>
   </div>
diff --git a/chrome/browser/resources/side_panel/read_anything/app.ts b/chrome/browser/resources/side_panel/read_anything/app.ts
index 66de667..70a9a20 100644
--- a/chrome/browser/resources/side_panel/read_anything/app.ts
+++ b/chrome/browser/resources/side_panel/read_anything/app.ts
@@ -538,12 +538,11 @@
     event.preventDefault();
     event.stopPropagation();
 
+    this.stopSpeech();
 
     const defaultUtteranceSettings = this.defaultUtteranceSettings();
 
     // TODO(crbug.com/1474951): Finalize the default voice preview text.
-    // TODO(crbug.com/1474951): Call this.synth.cancel() to interrupt reading
-    // and reset the play icon.
     const utterance = new SpeechSynthesisUtterance(
         loadTimeData.getString('readingModeVoicePreviewText'));
     const voice = event.detail.previewVoice;
@@ -565,15 +564,35 @@
     this.synth.speak(utterance);
   }
 
+  private onVoiceMenuClose_(
+      event: CustomEvent<{voicePlayingWhenMenuOpened: boolean}>) {
+    event.preventDefault();
+    event.stopPropagation();
+
+    // TODO(b/323912186) Handle when menu is closed mid-preview and the user
+    // presses play/pause button.
+    if (this.paused && event.detail.voicePlayingWhenMenuOpened) {
+      this.playSpeech();
+    }
+  }
+
   stopSpeech(pausedFromPlayClickButton: boolean = false) {
-    // TODO(crbug.com/1474951): When pausing, can we pause on the previous
-    // word so that speech doesn't resume in the middle of the word?
-    this.synth.pause();
+    // TODO(crbug.com/1474951): When pausing, can we pause on a word boundary
+    // and continue playing from the previous word?
     this.paused = true;
     this.pausedFromPlayClickButton = pausedFromPlayClickButton;
 
-    // Restore links if they're enabled when speech pauses.
-    if (chrome.readingMode.linksEnabled) {
+    if (pausedFromPlayClickButton) {
+      this.synth.pause();
+    } else {
+      // Canceling clears all the Utterances that are queued up via synth.play()
+      this.synth.cancel();
+    }
+
+    // Restore links if they're enabled when speech pauses. Don't restore links
+    // if it's paused from a non-pause button (e.g. voice previews) so the links
+    // don't flash off and on.
+    if (chrome.readingMode.linksEnabled && pausedFromPlayClickButton) {
       this.updateContent();
       this.highlightNodes(chrome.readingMode.getCurrentText());
     }
@@ -607,11 +626,19 @@
     const container = shadowRoot.getElementById('container');
     assert(container);
     if (this.speechStarted && this.paused) {
-      this.synth.resume();
+      if (this.pausedFromPlayClickButton) {
+        this.synth.resume();
+      } else {
+        this.highlightAndPlayMessage();
+      }
+
+      const pausedFromPlayClickButton = this.pausedFromPlayClickButton;
       this.paused = false;
       this.pausedFromPlayClickButton = false;
-      // Hide links when speech resumes.
-      if (chrome.readingMode.linksEnabled) {
+
+      // Hide links when speech resumes. We only hide links when the page was
+      // paused from the play/pause button.
+      if (chrome.readingMode.linksEnabled && pausedFromPlayClickButton) {
         this.updateContent();
       }
 
@@ -899,6 +926,7 @@
   private clearReadAloudState() {
     this.speechStarted = false;
     this.paused = true;
+    this.pausedFromPlayClickButton = false;
     this.previousHighlight_ = [];
   }
 
diff --git a/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.html b/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.html
index 0028057..40e65398 100644
--- a/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.html
+++ b/chrome/browser/resources/side_panel/read_anything/read_anything_toolbar.html
@@ -143,6 +143,7 @@
       id="voiceSelectionMenu"
       selected-voice="[[selectedVoice]]"
       available-voices="[[availableVoices]]"
+      paused="[[paused]]"
       preview-voice-playing="[[previewVoicePlaying]]">
     </voice-selection-menu>
     <cr-icon-button
diff --git a/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.html b/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.html
index 02040ac..3921fed 100644
--- a/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.html
+++ b/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.html
@@ -51,7 +51,7 @@
   iron-icon="read-anything:voice-selection">
 </cr-icon-button>
 
-<cr-action-menu id="voiceSelectionMenu">
+<cr-action-menu id="voiceSelectionMenu" on-close="onClose_">
   <template is="dom-repeat" items="[[voiceSelectionOptions_]]">
     <!--  TODO(crbug.com/1474951): show a header for each locale group before
           listing the languages of the locale -->
diff --git a/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.ts b/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.ts
index 56c5adf3..60aab41 100644
--- a/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.ts
+++ b/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.ts
@@ -34,6 +34,12 @@
 
 // TODO add tests for this component
 export class VoiceSelectionMenuElement extends VoiceSelectionMenuElementBase {
+  // If Read Aloud is in the paused state. This is set from the parent element
+  // via one way data binding.
+  private readonly paused: boolean;
+
+  private voicePlayingWhenMenuOpened_: boolean = false;
+
   static get is() {
     return 'voice-selection-menu';
   }
@@ -47,6 +53,7 @@
       selectedVoice: Object,
       availableVoices: Array,
       previewVoicePlaying: Object,
+      paused: Boolean,
       voiceSelectionOptions_: {
         type: Object,
         computed:
@@ -72,6 +79,8 @@
     const target = event.target as HTMLElement;
     const minY = target.getBoundingClientRect().bottom;
 
+    this.voicePlayingWhenMenuOpened_ = !this.paused;
+
     this.$.voiceSelectionMenu.showAt(target, {
       minY: minY,
       left: 0,
@@ -107,6 +116,16 @@
       },
     }));
   }
+
+  private onClose_() {
+    this.dispatchEvent(new CustomEvent('voice-menu-close', {
+      bubbles: true,
+      composed: true,
+      detail: {
+        voicePlayingWhenMenuOpened: this.voicePlayingWhenMenuOpened_,
+      },
+    }));
+  }
 }
 
 function voicesAreEqual(
diff --git a/chrome/browser/safe_browsing/download_protection/file_analyzer.cc b/chrome/browser/safe_browsing/download_protection/file_analyzer.cc
index c181a40..83415fc 100644
--- a/chrome/browser/safe_browsing/download_protection/file_analyzer.cc
+++ b/chrome/browser/safe_browsing/download_protection/file_analyzer.cc
@@ -86,7 +86,8 @@
     StartExtractDmgFeatures();
 #endif
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
-  } else if (inspection_type == DownloadFileType::OFFICE_DOCUMENT) {
+  } else if (inspection_type == DownloadFileType::OFFICE_DOCUMENT &&
+             !base::FeatureList::IsEnabled(kMaldocaSkipCheck)) {
     StartExtractDocumentFeatures();
 #endif
   } else if (base::FeatureList::IsEnabled(kSevenZipEvaluationEnabled) &&
@@ -270,10 +271,11 @@
     bool download_file_has_koly_signature) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  if (download_file_has_koly_signature)
+  if (download_file_has_koly_signature) {
     StartExtractDmgFeatures();
-  else
+  } else {
     StartExtractFileFeatures();
+  }
 }
 
 void FileAnalyzer::OnDmgAnalysisFinished(
diff --git a/chrome/browser/ui/android/toolbar/java/res/layout/toolbar_tablet.xml b/chrome/browser/ui/android/toolbar/java/res/layout/toolbar_tablet.xml
index c8b6447..4cbe04e 100644
--- a/chrome/browser/ui/android/toolbar/java/res/layout/toolbar_tablet.xml
+++ b/chrome/browser/ui/android/toolbar/java/res/layout/toolbar_tablet.xml
@@ -82,7 +82,9 @@
             android:paddingStart="@dimen/toolbar_tab_switcher_button_padding"
             android:layout_gravity="top"
             android:contentDescription="@string/accessibility_toolbar_btn_tabswitcher_toggle_default"
-            android:visibility="visible" />
+            android:visibility="visible"
+            app:menuMaxWidth="@dimen/tab_switcher_menu_width"
+            app:menuVerticalOverlapAnchor="false" />
 
         <include layout="@layout/menu_button"/>
     </LinearLayout>
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
index 3499957f..6d36a61 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
@@ -675,6 +675,13 @@
     }
 
     @Override
+    void setOnTabSwitcherLongClickHandler(OnLongClickListener listener) {
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.TABLET_TAB_SWITCHER_LONG_PRESS_MENU)) {
+            mSwitcherButton.setOnTabSwitcherLongClickHandler(listener);
+        }
+    }
+
+    @Override
     void onHomeButtonUpdate(boolean homeButtonEnabled) {
         mHomeButton.setVisibility(homeButtonEnabled ? VISIBLE : GONE);
     }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTabletUnitTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTabletUnitTest.java
index 59f40ad..e1fd15a 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTabletUnitTest.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTabletUnitTest.java
@@ -43,6 +43,7 @@
 import org.robolectric.shadows.ShadowToast;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.Features;
 import org.chromium.base.test.util.Features.DisableFeatures;
 import org.chromium.base.test.util.Features.EnableFeatures;
@@ -574,6 +575,19 @@
         }
     }
 
+    @Test
+    @Features.EnableFeatures(ChromeFeatureList.TABLET_TAB_SWITCHER_LONG_PRESS_MENU)
+    public void longPressTabSwitcherMenu() {
+        CallbackHelper callback = new CallbackHelper();
+        mToolbarTablet.setOnTabSwitcherLongClickHandler(
+                (v) -> {
+                    callback.notifyCalled();
+                    return true;
+                });
+        mTabSwitcherButton.performLongClick();
+        Assert.assertEquals("Long press callback not triggered.", 1, callback.getCallCount());
+    }
+
     private void longClickAndVerifyToast(int viewId, int stringId) {
         mToolbarTablet.onLongClick(mToolbarTablet.findViewById(viewId));
         assertTrue(
diff --git a/chrome/browser/ui/ash/api/tasks/chrome_tasks_delegate.cc b/chrome/browser/ui/ash/api/tasks/chrome_tasks_delegate.cc
index 55f20b9..edee9985dd 100644
--- a/chrome/browser/ui/ash/api/tasks/chrome_tasks_delegate.cc
+++ b/chrome/browser/ui/ash/api/tasks/chrome_tasks_delegate.cc
@@ -105,11 +105,6 @@
 
 void ChromeTasksDelegate::UpdateClientForProfileSwitch(
     const AccountId& account_id) {
-  // Cleanup before switching clients.
-  if (active_account_id_.is_valid()) {
-    SendCompletedTasks();
-  }
-
   // Do not create a client for guest profiles and don't create a new client for
   // an account that has already been registered.
   if (user_manager::UserManager::IsInitialized() &&
@@ -141,22 +136,6 @@
   client->GetTasks(task_list_id, std::move(callback));
 }
 
-void ChromeTasksDelegate::MarkAsCompleted(const std::string& task_list_id,
-                                          const std::string& task_id,
-                                          bool completed) {
-  CHECK(active_account_id_.is_valid());
-  TasksClientImpl* client = GetActiveAccountClient();
-  CHECK(client);
-  client->MarkAsCompleted(task_list_id, task_id, completed);
-}
-
-void ChromeTasksDelegate::SendCompletedTasks() {
-  CHECK(active_account_id_.is_valid());
-  TasksClientImpl* client = GetActiveAccountClient();
-  CHECK(client);
-  client->OnGlanceablesBubbleClosed();
-}
-
 void ChromeTasksDelegate::AddTask(const std::string& task_list_id,
                                   const std::string& title) {
   CHECK(active_account_id_.is_valid());
@@ -165,13 +144,15 @@
   client->AddTask(task_list_id, title, base::DoNothing());
 }
 
-void ChromeTasksDelegate::UpdateTaskTitle(const std::string& task_list_id,
-                                          const std::string& task_id,
-                                          const std::string& title) {
+void ChromeTasksDelegate::UpdateTask(const std::string& task_list_id,
+                                     const std::string& task_id,
+                                     const std::string& title,
+                                     bool completed) {
   CHECK(active_account_id_.is_valid());
   TasksClientImpl* client = GetActiveAccountClient();
   CHECK(client);
-  client->UpdateTask(task_list_id, task_id, title, base::DoNothing());
+  client->UpdateTask(task_list_id, task_id, title, completed,
+                     base::DoNothing());
 }
 
 TasksClientImpl* ChromeTasksDelegate::GetActiveAccountClient() const {
diff --git a/chrome/browser/ui/ash/api/tasks/chrome_tasks_delegate.h b/chrome/browser/ui/ash/api/tasks/chrome_tasks_delegate.h
index 86c3504a..c68d7f54 100644
--- a/chrome/browser/ui/ash/api/tasks/chrome_tasks_delegate.h
+++ b/chrome/browser/ui/ash/api/tasks/chrome_tasks_delegate.h
@@ -27,15 +27,12 @@
   void GetTaskLists(TasksClient::GetTaskListsCallback callback) override;
   void GetTasks(const std::string& task_list_id,
                 TasksClient::GetTasksCallback callback) override;
-  void MarkAsCompleted(const std::string& task_list_id,
-                       const std::string& task_id,
-                       bool completed) override;
-  void SendCompletedTasks() override;
   void AddTask(const std::string& task_list_id,
                const std::string& title) override;
-  void UpdateTaskTitle(const std::string& task_list_id,
-                       const std::string& task_id,
-                       const std::string& title) override;
+  void UpdateTask(const std::string& task_list_id,
+                  const std::string& task_id,
+                  const std::string& title,
+                  bool completed) override;
 
  private:
   // Returns the `TasksClientImpl` associated with the `active_account_id_`.
diff --git a/chrome/browser/ui/ash/birch/birch_keyed_service_unittest.cc b/chrome/browser/ui/ash/birch/birch_keyed_service_unittest.cc
index 29c4e90..a26788c 100644
--- a/chrome/browser/ui/ash/birch/birch_keyed_service_unittest.cc
+++ b/chrome/browser/ui/ash/birch/birch_keyed_service_unittest.cc
@@ -329,11 +329,11 @@
   auto& tabs = Shell::Get()->birch_model()->GetTabsForTest();
   ASSERT_EQ(tabs.size(), 2u);
 
-  EXPECT_EQ(tabs[0].title, base::UTF16ToUTF8(kTabTitle1));
+  EXPECT_EQ(tabs[0].title, kTabTitle1);
   EXPECT_EQ(tabs[0].url, GURL(kExampleURL1));
   EXPECT_EQ(tabs[0].session_name, kSessionName1);
 
-  EXPECT_EQ(tabs[1].title, base::UTF16ToUTF8(kTabTitle2));
+  EXPECT_EQ(tabs[1].title, kTabTitle2);
   EXPECT_EQ(tabs[1].url, GURL(kExampleURL2));
   EXPECT_EQ(tabs[1].session_name, kSessionName2);
 }
diff --git a/chrome/browser/ui/ash/birch/birch_recent_tabs_provider.cc b/chrome/browser/ui/ash/birch/birch_recent_tabs_provider.cc
index ca7074c..7d868c7 100644
--- a/chrome/browser/ui/ash/birch/birch_recent_tabs_provider.cc
+++ b/chrome/browser/ui/ash/birch/birch_recent_tabs_provider.cc
@@ -44,9 +44,9 @@
         const sessions::SerializedNavigationEntry& current_navigation =
             tab->navigations.at(tab->normalized_navigation_index());
         items.emplace_back(
-            base::UTF16ToUTF8(current_navigation.title()),
-            current_navigation.virtual_url(), current_navigation.timestamp(),
-            current_navigation.favicon_url(), session->GetSessionName());
+            current_navigation.title(), current_navigation.virtual_url(),
+            current_navigation.timestamp(), current_navigation.favicon_url(),
+            session->GetSessionName());
       }
     }
   }
diff --git a/chrome/browser/ui/ash/faster_split_screen_browsertest.cc b/chrome/browser/ui/ash/faster_split_screen_browsertest.cc
index c1fd84f3..32f40ec7 100644
--- a/chrome/browser/ui/ash/faster_split_screen_browsertest.cc
+++ b/chrome/browser/ui/ash/faster_split_screen_browsertest.cc
@@ -20,6 +20,7 @@
 #include "content/public/test/test_navigation_observer.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/views/controls/button/button.h"
+#include "ui/views/view_utils.h"
 
 namespace {
 
@@ -76,7 +77,12 @@
   auto* overview_grid =
       ash::OverviewController::Get()->overview_session()->GetGridWithRootWindow(
           window->GetRootWindow());
-  auto* settings_button = overview_grid->GetSettingsButtonForTesting();
+  ASSERT_TRUE(overview_grid);
+  auto* faster_splitview_widget =
+      overview_grid->faster_splitview_widget_for_testing();
+  ASSERT_TRUE(faster_splitview_widget);
+  auto* settings_button = views::AsViewClass<ash::IconButton>(
+      faster_splitview_widget->GetContentsView()->children()[1]);
   ASSERT_TRUE(settings_button);
 
   // Setup navigation observer to wait for the OS Settings page.
diff --git a/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl.cc b/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl.cc
index d90d2ce4..5a7bdfe 100644
--- a/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl.cc
+++ b/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl.cc
@@ -85,7 +85,7 @@
                      }) != root_task->links().end();
     const bool has_notes = !root_task->notes().empty();
     converted_tasks.push_back(std::make_unique<api::Task>(
-        root_task->id(), root_task->title(), completed, root_task->due(),
+        root_task->id(), root_task->title(), root_task->due(), completed,
         has_subtasks, has_email_link, has_notes, root_task->updated()));
   }
 
@@ -189,6 +189,7 @@
     const std::string& task_list_id,
     const std::string& task_id,
     const std::string& title,
+    bool completed,
     api::TasksClient::OnTaskSavedCallback callback) {
   CHECK(!task_list_id.empty());
   CHECK(!task_id.empty());
@@ -197,7 +198,10 @@
 
   auto* const request_sender = GetRequestSender();
   request_sender->StartRequestWithAuthRetry(std::make_unique<PatchTaskRequest>(
-      request_sender, task_list_id, task_id, TaskRequestPayload{.title = title},
+      request_sender, task_list_id, task_id,
+      TaskRequestPayload{.title = title,
+                         .status = completed ? TaskStatus::kCompleted
+                                             : TaskStatus::kNeedsAction},
       base::BindOnce(&TasksClientImpl::OnTaskUpdated,
                      weak_factory_.GetWeakPtr(), task_list_id,
                      base::Time::Now(), std::move(callback))));
@@ -458,7 +462,7 @@
   const auto* const task = iter->second.AddAt(
       /*index=*/0,
       std::make_unique<api::Task>(result.value()->id(), result.value()->title(),
-                                  /*completed=*/false, /*due=*/std::nullopt,
+                                  /*due=*/std::nullopt, /*completed=*/false,
                                   /*has_subtasks=*/false,
                                   /*has_email_link=*/false, /*has_notes=*/false,
                                   result.value()->updated()));
@@ -486,17 +490,22 @@
     return;
   }
 
-  const auto task_iter = std::find_if(
-      tasks_iter->second.begin(), tasks_iter->second.end(),
-      [&result](const auto& task) { return task->id == result->get()->id(); });
+  Task* result_data = result->get();
+  const auto task_iter =
+      std::find_if(tasks_iter->second.begin(), tasks_iter->second.end(),
+                   [&result_data](const auto& task) {
+                     return task->id == result_data->id();
+                   });
   if (task_iter == tasks_iter->second.end()) {
     std::move(callback).Run(/*task=*/nullptr);
     return;
   }
 
-  task_iter->get()->title = result->get()->title();
-  task_iter->get()->updated = result->get()->updated();
-  std::move(callback).Run(/*task=*/task_iter->get());
+  ash::api::Task* task = task_iter->get();
+  task->title = result_data->title();
+  task->completed = result_data->status() == TaskStatus::kCompleted;
+  task->updated = result_data->updated();
+  std::move(callback).Run(/*task=*/task);
 }
 
 google_apis::RequestSender* TasksClientImpl::GetRequestSender() {
diff --git a/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl.h b/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl.h
index e1cd3c41..25d8b08 100644
--- a/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl.h
+++ b/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl.h
@@ -67,6 +67,7 @@
   void UpdateTask(const std::string& task_list_id,
                   const std::string& task_id,
                   const std::string& title,
+                  bool completed,
                   api::TasksClient::OnTaskSavedCallback callback) override;
   void OnGlanceablesBubbleClosed(
       api::TasksClient::OnAllPendingCompletedTasksSavedCallback callback =
diff --git a/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl_unittest.cc b/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl_unittest.cc
index 809460c..0c995563 100644
--- a/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl_unittest.cc
+++ b/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl_unittest.cc
@@ -26,6 +26,7 @@
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/gaia_urls_overrider_for_testing.h"
 #include "google_apis/tasks/tasks_api_requests.h"
+#include "google_apis/tasks/tasks_api_task_status.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
@@ -1813,7 +1814,7 @@
             "kind": "tasks#task",
             "id": "task-id",
             "title": "Updated title",
-            "status": "needsAction"
+            "status": "completed"
           }
         )"))));
 
@@ -1835,12 +1836,13 @@
   // Update the task.
   TestFuture<const api::Task*> update_task_future;
   client()->UpdateTask("task-list-id", "task-id", "Updated title",
-                       update_task_future.GetCallback());
+                       /*completed=*/true, update_task_future.GetCallback());
   ASSERT_TRUE(update_task_future.Wait());
 
   // Make sure `tasks` contains the update.
   EXPECT_EQ(tasks->GetItemAt(0), update_task_future.Get());
   EXPECT_EQ(tasks->GetItemAt(0)->title, "Updated title");
+  EXPECT_EQ(tasks->GetItemAt(0)->completed, true);
 
   histogram_tester()->ExpectTotalCount(
       "Ash.Glanceables.Api.Tasks.PatchTask.Latency", /*expected_count=*/1);
@@ -1862,7 +1864,7 @@
 
   TestFuture<const api::Task*> update_task_future;
   client()->UpdateTask("task-list-id", "task-id", "Updated title",
-                       update_task_future.GetCallback());
+                       /*completed=*/false, update_task_future.GetCallback());
 
   ASSERT_TRUE(update_task_future.Wait());
   EXPECT_FALSE(update_task_future.Get());
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc b/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc
index 2ac0e43ea..8535976 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_ui_browsertest.cc
@@ -628,15 +628,8 @@
   raw_ptr<DropTargetView> drop_target_view_ = nullptr;
 };
 
-// Flaky on ChromeOS bots: crbug.com/1338054
-#if BUILDFLAG(IS_CHROMEOS)
-#define MAYBE_DragAndDrop DISABLED_DragAndDrop
-#else
-#define MAYBE_DragAndDrop DragAndDrop
-#endif
 // Verifies that drag-and-drop of holding space items works.
-IN_PROC_BROWSER_TEST_P(HoldingSpaceUiDragAndDropBrowserTest,
-                       MAYBE_DragAndDrop) {
+IN_PROC_BROWSER_TEST_P(HoldingSpaceUiDragAndDropBrowserTest, DragAndDrop) {
   ui::ScopedAnimationDurationScaleMode scoped_animation_duration_scale_mode(
       ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
 
diff --git a/chrome/browser/ui/quick_answers/ui/rich_answers_view.cc b/chrome/browser/ui/quick_answers/ui/rich_answers_view.cc
index 103b67b..e73a9fa 100644
--- a/chrome/browser/ui/quick_answers/ui/rich_answers_view.cc
+++ b/chrome/browser/ui/quick_answers/ui/rich_answers_view.cc
@@ -147,6 +147,7 @@
   rich_answers_view->SetPaintToLayer();
   rich_answers_view->layer()->SetRoundedCornerRadius(
       gfx::RoundedCornersF(kRoundedCornerRadius));
+  rich_answers_view->layer()->SetIsFastRoundedCorner(true);
 
   return widget;
 }
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_browsertest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_browsertest.cc
index d18bc5aa..e5c0429f 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_browsertest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_browsertest.cc
@@ -458,7 +458,7 @@
     PrerenderBookmarkBarNavigationTestBase::SetUpOnMainThread();
     ukm_entry_builder_ =
         std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>(
-            chrome_preloading_predictor::kPointerDownOnBookmarkBar);
+            chrome_preloading_predictor::kMouseHoverOrMouseDownOnBookmarkBar);
   }
 
  private:
@@ -525,7 +525,8 @@
       "Prerender.Experimental.PrerenderHostFinalStatus.Embedder_BookmarkBar",
       kFinalStatusActivated, 1);
   histogram_tester.ExpectUniqueSample(
-      "Preloading.Prerender.Attempt.PointerDownOnBookmarkBar.TriggeringOutcome",
+      "Preloading.Prerender.Attempt.MouseHoverOrMouseDownOnBookmarkBar."
+      "TriggeringOutcome",
       kPreloadingTriggeringOutcomeSuccess, 1);
   // Navigate away to flush the metrics and check.
   ASSERT_TRUE(
@@ -602,7 +603,7 @@
     PrerenderBookmarkBarNavigationTestBase::SetUpOnMainThread();
     ukm_entry_builder_ =
         std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>(
-            chrome_preloading_predictor::kMouseHoverOnBookmarkBar);
+            chrome_preloading_predictor::kMouseHoverOrMouseDownOnBookmarkBar);
   }
 
   void TriggerPrerenderByMouseHoverOnBookmark(bool expect_completion) {
@@ -685,7 +686,8 @@
       "Prerender.Experimental.PrerenderHostFinalStatus.Embedder_BookmarkBar",
       kFinalStatusActivated, 1);
   histogram_tester.ExpectUniqueSample(
-      "Preloading.Prerender.Attempt.MouseHoverOnBookmarkBar.TriggeringOutcome",
+      "Preloading.Prerender.Attempt.MouseHoverOrMouseDownOnBookmarkBar."
+      "TriggeringOutcome",
       kPreloadingTriggeringOutcomeSuccess, 1);
   ASSERT_EQ(bookmark_navigation_list().size(), 2u);
   for (int i = 0; i < 2; ++i) {
@@ -776,7 +778,8 @@
       "Prerender.Experimental.PrerenderHostFinalStatus.Embedder_BookmarkBar",
       kFinalStatusActivated, 1);
   histogram_tester.ExpectBucketCount(
-      "Preloading.Prerender.Attempt.MouseHoverOnBookmarkBar.TriggeringOutcome",
+      "Preloading.Prerender.Attempt.MouseHoverOrMouseDownOnBookmarkBar."
+      "TriggeringOutcome",
       kPreloadingTriggeringOutcomeSuccess, 1);
 }
 
@@ -804,12 +807,13 @@
                                        /*flags=*/ui::EF_NONE,
                                        /*changed_button_flags=*/ui::EF_NONE));
 
-  // Normal navigation is not in `kPointerDownOnBookmarkBar` predictor's domain.
+  // Normal navigation is not in `kMouseHoverOrMouseDownOnBookmarkBar`
+  // predictor's domain.
   histogram_tester.ExpectBucketCount(
-      "Preloading.Predictor.PointerDownOnBookmarkBar.Recall",
+      "Preloading.Predictor.MouseHoverOrMouseDownOnBookmarkBar.Recall",
       /*content::PredictorConfusionMatrix::kTruePositive*/ 0, 0);
   histogram_tester.ExpectBucketCount(
-      "Preloading.Predictor.PointerDownOnBookmarkBar.Recall",
+      "Preloading.Predictor.MouseHoverOrMouseDownOnBookmarkBar.Recall",
       /*content::PredictorConfusionMatrix::kFalseNegative*/ 3, 0);
 
   // A `PAGE_TRANSITION_AUTO_BOOKMARK` navigation should be in the predictor's
@@ -820,7 +824,7 @@
                         ui::PAGE_TRANSITION_AUTO_BOOKMARK);
   ui_test_utils::NavigateToURL(&params);
   histogram_tester.ExpectBucketCount(
-      "Preloading.Predictor.PointerDownOnBookmarkBar.Recall",
+      "Preloading.Predictor.MouseHoverOrMouseDownOnBookmarkBar.Recall",
       /*content::PredictorConfusionMatrix::kFalseNegative*/ 3, 1);
 }
 
@@ -885,7 +889,7 @@
     PrerenderBookmarkBarNavigationTestBase::SetUpOnMainThread();
     ukm_entry_builder_ =
         std::make_unique<content::test::PreloadingAttemptUkmEntryBuilder>(
-            chrome_preloading_predictor::kPointerDownOnBookmarkBar);
+            chrome_preloading_predictor::kMouseHoverOrMouseDownOnBookmarkBar);
   }
 
   void ClickOnBookmarkBarLink() {
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_button.cc b/chrome/browser/ui/views/bookmarks/bookmark_button.cc
index 7af3e52..d6c04dd1 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_button.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_button.cc
@@ -177,7 +177,7 @@
       content::PreloadingData* preloading_data =
           content::PreloadingData::GetOrCreateForWebContents(web_contents);
       preloading_data->SetIsNavigationInDomainCallback(
-          chrome_preloading_predictor::kPointerDownOnBookmarkBar,
+          chrome_preloading_predictor::kMouseHoverOrMouseDownOnBookmarkBar,
           base::BindRepeating(
               [](content::NavigationHandle* navigation_handle) -> bool {
                 return ui::PageTransitionCoreTypeIs(
@@ -213,8 +213,7 @@
   if (event.IsOnlyLeftMouseButton() &&
       base::FeatureList::IsEnabled(features::kBookmarkTriggerForPrerender2) &&
       kPrerenderBookmarkBarOnMousePressedTrigger.Get()) {
-    StartPrerendering(chrome_preloading_predictor::kPointerDownOnBookmarkBar,
-                      *url_);
+    StartPrerendering(*url_);
   }
   return result;
 }
@@ -233,8 +232,7 @@
   if (kPrerenderStartDelayOnMouseHoverByMiliseconds.Get() -
           kPreconnectStartDelayOnMouseHoverByMiliseconds.Get() <=
       0) {
-    StartPrerendering(chrome_preloading_predictor::kMouseHoverOnBookmarkBar,
-                      url);
+    StartPrerendering(url);
   } else {
     auto* loading_predictor =
         predictors::LoadingPredictorFactory::GetForProfile(browser_->profile());
@@ -248,14 +246,12 @@
         base::Milliseconds(
             kPrerenderStartDelayOnMouseHoverByMiliseconds.Get() -
             kPreconnectStartDelayOnMouseHoverByMiliseconds.Get()),
-        base::BindRepeating(
-            &BookmarkButton::StartPrerendering, base::Unretained(this),
-            chrome_preloading_predictor::kMouseHoverOnBookmarkBar, url));
+        base::BindRepeating(&BookmarkButton::StartPrerendering,
+                            base::Unretained(this), url));
   }
 }
 
-void BookmarkButton::StartPrerendering(content::PreloadingPredictor predictor,
-                                       GURL url) {
+void BookmarkButton::StartPrerendering(GURL url) {
   // TODO(https://crbug.com/1422819): Prerender only for https scheme, and add
   // an enum metric to report the protocol scheme.
   CHECK(base::FeatureList::IsEnabled(features::kBookmarkTriggerForPrerender2));
@@ -265,8 +261,7 @@
     PrerenderManager::CreateForWebContents(&(*prerender_web_contents_));
     auto* prerender_manager =
         PrerenderManager::FromWebContents(&(*prerender_web_contents_));
-    prerender_handle_ =
-        prerender_manager->StartPrerenderBookmark(url, predictor);
+    prerender_handle_ = prerender_manager->StartPrerenderBookmark(url);
   }
 }
 
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_button.h b/chrome/browser/ui/views/bookmarks/bookmark_button.h
index c273e23..8b6f656 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_button.h
+++ b/chrome/browser/ui/views/bookmarks/bookmark_button.h
@@ -66,7 +66,7 @@
 
  private:
   void StartPreconnecting(GURL url);
-  void StartPrerendering(content::PreloadingPredictor predictor, GURL url);
+  void StartPrerendering(GURL url);
 
   // A cached value of maximum width for tooltip to skip generating
   // new tooltip text.
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc
index 72de179c..1ae0f53 100644
--- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc
+++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_bar.cc
@@ -717,7 +717,11 @@
   }
 
   if (overflow_menu_->GetWidget()) {
-    bubble_delegate_->SizeToContents();
+    if (overflow_menu_->children().empty()) {
+      overflow_menu_->GetWidget()->Close();
+    } else {
+      bubble_delegate_->SizeToContents();
+    }
   }
 }
 
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_interactive_uitest.cc b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_interactive_uitest.cc
index 06c7ab39..407bf4c 100644
--- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_interactive_uitest.cc
+++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_interactive_uitest.cc
@@ -647,3 +647,64 @@
           ui::Accelerator(ui::KeyboardCode::VKEY_ESCAPE, ui::EF_NONE)),
       WaitForHide(kSavedTabGroupOverflowMenuId));
 }
+
+IN_PROC_BROWSER_TEST_F(SavedTabGroupInteractiveTest,
+                       OverflowMenuClosesWhenNoMoreButtons) {
+  // Add 5 additional tabs to the browser.
+  ASSERT_TRUE(
+      AddTabAtIndex(0, GURL(url::kAboutBlankURL), ui::PAGE_TRANSITION_TYPED));
+  ASSERT_TRUE(
+      AddTabAtIndex(0, GURL(url::kAboutBlankURL), ui::PAGE_TRANSITION_TYPED));
+  ASSERT_TRUE(
+      AddTabAtIndex(0, GURL(url::kAboutBlankURL), ui::PAGE_TRANSITION_TYPED));
+  ASSERT_TRUE(
+      AddTabAtIndex(0, GURL(url::kAboutBlankURL), ui::PAGE_TRANSITION_TYPED));
+  ASSERT_EQ(5, browser()->tab_strip_model()->count());
+
+  // Add each tab to a separate group.
+  const tab_groups::TabGroupId group_1 =
+      browser()->tab_strip_model()->AddToNewGroup({0});
+  const tab_groups::TabGroupId group_2 =
+      browser()->tab_strip_model()->AddToNewGroup({1});
+  const tab_groups::TabGroupId group_3 =
+      browser()->tab_strip_model()->AddToNewGroup({2});
+  const tab_groups::TabGroupId group_4 =
+      browser()->tab_strip_model()->AddToNewGroup({3});
+  const tab_groups::TabGroupId group_5 =
+      browser()->tab_strip_model()->AddToNewGroup({4});
+
+  RunTestSequence(
+      // Show the bookmarks bar where the buttons will be displayed.
+      FinishTabstripAnimations(), ShowBookmarksBar(),
+      // Ensure no saved group buttons in the bookmarks bar are present.
+      EnsureNotPresent(kSavedTabGroupButtonElementId),
+
+      // Add views until we get an overflow button.
+      SaveGroupAndCloseEditorBubble(group_1), FinishTabstripAnimations(),
+      SaveGroupAndCloseEditorBubble(group_2), FinishTabstripAnimations(),
+      SaveGroupAndCloseEditorBubble(group_3), FinishTabstripAnimations(),
+      SaveGroupAndCloseEditorBubble(group_4), FinishTabstripAnimations(),
+      SaveGroupAndCloseEditorBubble(group_5), FinishTabstripAnimations(),
+      WaitForShow(kSavedTabGroupOverflowButtonElementId), FlushEvents(),
+
+      // Show the overflow menu.
+      PressButton(kSavedTabGroupOverflowButtonElementId),
+      WaitForShow(kSavedTabGroupOverflowMenuId, true), Do([=]() {
+        BrowserView::GetBrowserViewForBrowser(browser())
+            ->GetWidget()
+            ->LayoutRootViewIfNecessary();
+      }),
+      FlushEvents(),
+
+      // Verify the overflow menu expands if another group is added.
+      UnsaveGroupViaModel(group_5), Do([=]() {
+        BrowserView::GetBrowserViewForBrowser(browser())
+            ->GetWidget()
+            ->LayoutRootViewIfNecessary();
+      }),
+      FlushEvents(),
+
+      // Ensure the menu is no longer visible / present.
+      WaitForHide(kSavedTabGroupOverflowMenuId),
+      EnsureNotPresent(kSavedTabGroupOverflowMenuId));
+}
diff --git a/chrome/browser/ui/webui/accessibility/accessibility_ui.cc b/chrome/browser/ui/webui/accessibility/accessibility_ui.cc
index 66254978..a2c6fc54 100644
--- a/chrome/browser/ui/webui/accessibility/accessibility_ui.cc
+++ b/chrome/browser/ui/webui/accessibility/accessibility_ui.cc
@@ -95,7 +95,7 @@
 static const char kInternal[] = "internal";
 static const char kNative[] = "native";
 static const char kPage[] = "page";
-static const char kPDF[] = "pdf";
+static const char kPDFPrinting[] = "pdfPrinting";
 static const char kScreenReader[] = "screenreader";
 static const char kShowOrRefreshTree[] = "showOrRefreshTree";
 static const char kText[] = "text";
@@ -208,7 +208,7 @@
   bool text = mode.has_mode(ui::AXMode::kInlineTextBoxes);
   bool screenreader = mode.has_mode(ui::AXMode::kScreenReader);
   bool html = mode.has_mode(ui::AXMode::kHTML);
-  bool pdf = mode.has_mode(ui::AXMode::kPDF);
+  bool pdf_printing = mode.has_mode(ui::AXMode::kPDFPrinting);
 
   // The "native" and "web" flags are disabled if
   // --disable-renderer-accessibility is set.
@@ -223,8 +223,8 @@
            is_web_enabled ? (screenreader ? kOn : kOff) : kDisabled);
   data.Set(kHTML, is_web_enabled ? (html ? kOn : kOff) : kDisabled);
 
-  // The "pdf" flag is independent of the others.
-  data.Set(kPDF, pdf ? kOn : kOff);
+  // The "pdfPrinting" flag is independent of the others.
+  data.Set(kPDFPrinting, pdf_printing ? kOn : kOff);
 
   // The "Top Level Widgets" section is only relevant if views accessibility is
   // enabled.
diff --git a/chrome/browser/ui/webui/ash/settings/integration_tests/swap_primary_mouse_button_interactive_uitest.cc b/chrome/browser/ui/webui/ash/settings/integration_tests/swap_primary_mouse_button_interactive_uitest.cc
new file mode 100644
index 0000000..0567eac4
--- /dev/null
+++ b/chrome/browser/ui/webui/ash/settings/integration_tests/swap_primary_mouse_button_interactive_uitest.cc
@@ -0,0 +1,113 @@
+// 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.
+
+#include "ash/constants/ash_features.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/browser/ui/settings_window_manager_chromeos.h"
+#include "chrome/test/base/chromeos/crosier/interactive_ash_test.h"
+#include "ui/base/interaction/element_identifier.h"
+#include "ui/events/devices/device_data_manager_test_api.h"
+#include "ui/events/devices/input_device.h"
+
+namespace ash {
+
+namespace {
+
+constexpr char kDeviceSectionPath[] = "device";
+
+class DeviceSettingsSwapPrimaryMouseButtonInteractiveUiTest
+    : public InteractiveAshTest {
+ public:
+  DeviceSettingsSwapPrimaryMouseButtonInteractiveUiTest() {
+    feature_list_.InitWithFeatures({features::kInputDeviceSettingsSplit},
+                                   {features::kPeripheralCustomization});
+  }
+
+  // Query to pierce through Shadow DOM to find the mouse row.
+  const DeepQuery kMouseRowQuery{
+      "os-settings-ui",       "os-settings-main",   "main-page-container",
+      "settings-device-page", "#perDeviceMouseRow",
+  };
+
+  const DeepQuery kMouseSwapButtonDropdownQuery{
+      "os-settings-ui",
+      "os-settings-main",
+      "main-page-container",
+      "settings-device-page",
+      "settings-per-device-mouse",
+      "settings-per-device-mouse-subsection",
+      "#mouseSwapButtonDropdown",
+      "#dropdownMenu",
+  };
+
+  const DeepQuery kCursorAcceleartorToggleQuery{
+      "os-settings-ui",
+      "os-settings-main",
+      "main-page-container",
+      "settings-device-page",
+      "settings-per-device-mouse",
+      "settings-per-device-mouse-subsection",
+      "#mouseAcceleration",
+      "#control",
+  };
+
+  void SetUpOnMainThread() override {
+    InteractiveAshTest::SetUpOnMainThread();
+
+    // Set up context for element tracking for InteractiveBrowserTest.
+    SetupContextWidget();
+
+    // Ensure the OS Settings system web app (SWA) is installed.
+    InstallSystemApps();
+
+    // Initialize mouse.
+    ui::DeviceDataManagerTestApi().SetMouseDevices(
+        {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")});
+    ui::DeviceDataManagerTestApi().OnDeviceListsComplete();
+  }
+
+ protected:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(DeviceSettingsSwapPrimaryMouseButtonInteractiveUiTest,
+                       SwapPrimaryMouseButton) {
+  DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kOsSettingsWebContentsId);
+  DEFINE_LOCAL_CUSTOM_ELEMENT_EVENT_TYPE(kCursorAccelerationToggleEnabledEvent);
+  StateChange cursor_acceleration_toggle_enabled;
+  cursor_acceleration_toggle_enabled.type =
+      StateChange::Type::kExistsAndConditionTrue;
+  cursor_acceleration_toggle_enabled.event =
+      kCursorAccelerationToggleEnabledEvent;
+  cursor_acceleration_toggle_enabled.where = kCursorAcceleartorToggleQuery;
+  cursor_acceleration_toggle_enabled.test_function = "el => !el.disabled";
+
+  RunTestSequence(
+      InstrumentNextTab(kOsSettingsWebContentsId, AnyBrowser()), Do([&]() {
+        chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
+            GetActiveUserProfile(), kDeviceSectionPath);
+      }),
+      WaitForShow(kOsSettingsWebContentsId),
+      WaitForWebContentsReady(kOsSettingsWebContentsId,
+                              chrome::GetOSSettingsUrl(kDeviceSectionPath)),
+      Log("Waiting for per device mouse row to be visible"),
+      WaitForElementExists(kOsSettingsWebContentsId, kMouseRowQuery),
+      ClickElement(kOsSettingsWebContentsId, kMouseRowQuery),
+      Log("Waiting for swap primary mouse toggle to be visible"),
+      WaitForElementExists(kOsSettingsWebContentsId,
+                           kMouseSwapButtonDropdownQuery),
+      Log("Selecting 'Right button' from the dropdown menu"),
+      ExecuteJsAt(kOsSettingsWebContentsId, kMouseSwapButtonDropdownQuery,
+                  "(el) => {el.selectedIndex = 1; el.dispatchEvent(new "
+                  "Event('change'));}"),
+      Log("Verifying that right clicking behavior has changed"),
+      MoveMouseTo(kOsSettingsWebContentsId, kCursorAcceleartorToggleQuery),
+      ClickMouse(ui_controls::RIGHT),
+      WaitForStateChange(kOsSettingsWebContentsId,
+                         cursor_acceleration_toggle_enabled));
+}
+
+}  // namespace
+}  // namespace ash
diff --git a/chrome/browser/ui/webui/net_internals/OWNERS b/chrome/browser/ui/webui/net_internals/OWNERS
index 53e68eb7..28361a0 100644
--- a/chrome/browser/ui/webui/net_internals/OWNERS
+++ b/chrome/browser/ui/webui/net_internals/OWNERS
@@ -1 +1 @@
-mmenke@chromium.org
+file://services/network/OWNERS
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc
index 4a40ec0..5accb4fd 100644
--- a/chrome/browser/ui/webui/settings/about_handler.cc
+++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -67,6 +67,7 @@
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/ash/tpm_firmware_update.h"
+#include "chrome/browser/ui/webui/ash/extended_updates/extended_updates_dialog.h"
 #include "chrome/browser/ui/webui/ash/image_source.h"
 #include "chrome/browser/ui/webui/help/help_utils_chromeos.h"
 #include "chrome/browser/ui/webui/help/version_updater_chromeos.h"
@@ -289,6 +290,11 @@
                                           base::Unretained(this)));
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   web_ui()->RegisterMessageCallback(
+      "openExtendedUpdatesDialog",
+      base::BindRepeating(&AboutHandler::HandleOpenExtendedUpdatesDialog,
+                          base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
       "openDiagnostics",
       base::BindRepeating(&AboutHandler::HandleOpenDiagnostics,
                           base::Unretained(this)));
@@ -474,6 +480,12 @@
 }
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+void AboutHandler::HandleOpenExtendedUpdatesDialog(
+    const base::Value::List& args) {
+  DCHECK(args.empty());
+  ash::extended_updates::ExtendedUpdatesDialog::Show();
+}
+
 void AboutHandler::HandleOpenDiagnostics(const base::Value::List& args) {
   DCHECK(args.empty());
   chrome::ShowDiagnosticsApp(profile_);
diff --git a/chrome/browser/ui/webui/settings/about_handler.h b/chrome/browser/ui/webui/settings/about_handler.h
index c8384152..9cdfa37 100644
--- a/chrome/browser/ui/webui/settings/about_handler.h
+++ b/chrome/browser/ui/webui/settings/about_handler.h
@@ -84,6 +84,9 @@
   void HandleOpenHelpPage(const base::Value::List& args);
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+  // Opens the Extended Updates dialog. |args| must be empty.
+  void HandleOpenExtendedUpdatesDialog(const base::Value::List& args);
+
   // Checks if ReleaseNotes is enabled.
   void HandleGetEnabledReleaseNotes(const base::Value::List& args);
 
diff --git a/chrome/browser/usb/COMMON_METADATA b/chrome/browser/usb/COMMON_METADATA
index 536f4da..8aa2b3e 100644
--- a/chrome/browser/usb/COMMON_METADATA
+++ b/chrome/browser/usb/COMMON_METADATA
@@ -2,3 +2,6 @@
   component: "Blink>USB"
 }
 team_email: "webusb@chromium.org"
+buganizer_public: {
+  component_id: 1456830
+}
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 29f661d..febd3ea 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1707163073-ba7cb4460930a55402519dcdd56add2981a5d707.profdata
+chrome-mac-arm-main-1707177403-4a0d6c36070e061fe8cc29b0efbd3a1898fac03c.profdata
diff --git a/chrome/common/extensions/api/context_menus.json b/chrome/common/extensions/api/context_menus.json
index 5ede00e..744f3ab 100644
--- a/chrome/common/extensions/api/context_menus.json
+++ b/chrome/common/extensions/api/context_menus.json
@@ -95,6 +95,89 @@
             "description": "A flag indicating the state of a checkbox or radio item after it is clicked."
           }
         }
+      },
+      {
+        "id": "CreateProperties",
+        "type": "object",
+        "description": "Properties of the new context menu item.",
+        "properties": {
+          "type": {
+            "$ref": "ItemType",
+            "optional": true,
+            "description": "The type of menu item. Defaults to <code>normal</code>."
+          },
+          "id": {
+            "type": "string",
+            "optional": true,
+            "description": "The unique ID to assign to this item. Mandatory for event pages. Cannot be the same as another ID for this extension."
+          },
+          "title": {
+            "type": "string",
+            "optional": true,
+            "description": "The text to display in the item; this is <em>required</em> unless <code>type</code> is <code>separator</code>. When the context is <code>selection</code>, use <code>%s</code> within the string to show the selected text. For example, if this parameter's value is \"Translate '%s' to Pig Latin\" and the user selects the word \"cool\", the context menu item for the selection is \"Translate 'cool' to Pig Latin\"."
+          },
+          "checked": {
+            "type": "boolean",
+            "optional": true,
+            "description": "The initial state of a checkbox or radio button: <code>true</code> for selected, <code>false</code> for unselected. Only one radio button can be selected at a time in a given group."
+          },
+          "contexts": {
+            "type": "array",
+            "items": {
+              "$ref": "ContextType"
+            },
+            "minItems": 1,
+            "optional": true,
+            "description": "List of contexts this menu item will appear in. Defaults to <code>['page']</code>."
+          },
+          "visible": {
+            "type": "boolean",
+            "optional": true,
+            "description": "Whether the item is visible in the menu."
+          },
+          "onclick": {
+            "type": "function",
+            "optional": true,
+            "description": "A function that is called back when the menu item is clicked. This is not available inside of a service worker; instead, they should register a listener for $(ref:contextMenus.onClicked).",
+            "parameters": [
+              {
+                "name": "info",
+                "$ref": "OnClickData",
+                "description": "Information about the item clicked and the context where the click happened."
+              },
+              {
+                "name": "tab",
+                "$ref": "tabs.Tab",
+                "description": "The details of the tab where the click took place. This parameter is not present for platform apps."
+              }
+            ]
+          },
+          "parentId": {
+            "choices": [
+              { "type": "integer" },
+              { "type": "string" }
+            ],
+            "optional": true,
+            "description": "The ID of a parent menu item; this makes the item a child of a previously added item."
+          },
+          "documentUrlPatterns": {
+            "type": "array",
+            "items": {"type": "string"},
+            "optional": true,
+            "description": "Restricts the item to apply only to documents or frames whose URL matches one of the given patterns. For details on pattern formats, see <a href='/docs/extensions/develop/concepts/match-patterns'>Match Patterns</a>."
+          },
+          "targetUrlPatterns": {
+            "type": "array",
+            "items": {"type": "string"},
+            "optional": true,
+            "description": "Similar to <code>documentUrlPatterns</code>, filters based on the <code>src</code> attribute of <code>img</code>, <code>audio</code>, and <code>video</code> tags and the <code>href</code> attribute of <code>a</code> tags."
+          },
+          "enabled": {
+            "type": "boolean",
+            "optional": true,
+            "description": "Whether this context menu item is enabled or disabled. Defaults to <code>true</code>."
+          }
+        }
       }
     ],
     "functions": [
@@ -111,86 +194,8 @@
         },
         "parameters": [
           {
-            "type": "object",
-            "name": "createProperties",
-            "properties": {
-              "type": {
-                "$ref": "ItemType",
-                "optional": true,
-                "description": "The type of menu item. Defaults to <code>normal</code>."
-              },
-              "id": {
-                "type": "string",
-                "optional": true,
-                "description": "The unique ID to assign to this item. Mandatory for event pages. Cannot be the same as another ID for this extension."
-              },
-              "title": {
-                "type": "string",
-                "optional": true,
-                "description": "The text to display in the item; this is <em>required</em> unless <code>type</code> is <code>separator</code>. When the context is <code>selection</code>, use <code>%s</code> within the string to show the selected text. For example, if this parameter's value is \"Translate '%s' to Pig Latin\" and the user selects the word \"cool\", the context menu item for the selection is \"Translate 'cool' to Pig Latin\"."
-              },
-              "checked": {
-                "type": "boolean",
-                "optional": true,
-                "description": "The initial state of a checkbox or radio button: <code>true</code> for selected, <code>false</code> for unselected. Only one radio button can be selected at a time in a given group."
-              },
-              "contexts": {
-                "type": "array",
-                "items": {
-                  "$ref": "ContextType"
-                },
-                "minItems": 1,
-                "optional": true,
-                "description": "List of contexts this menu item will appear in. Defaults to <code>['page']</code>."
-              },
-              "visible": {
-                "type": "boolean",
-                "optional": true,
-                "description": "Whether the item is visible in the menu."
-              },
-              "onclick": {
-                "type": "function",
-                "optional": true,
-                "description": "A function that is called back when the menu item is clicked. This is not available inside of a service worker; instead, they should register a listener for $(ref:contextMenus.onClicked).",
-                "parameters": [
-                  {
-                    "name": "info",
-                    "$ref": "OnClickData",
-                    "description": "Information about the item clicked and the context where the click happened."
-                  },
-                  {
-                    "name": "tab",
-                    "$ref": "tabs.Tab",
-                    "description": "The details of the tab where the click took place. This parameter is not present for platform apps."
-                  }
-                ]
-              },
-              "parentId": {
-                "choices": [
-                  { "type": "integer" },
-                  { "type": "string" }
-                ],
-                "optional": true,
-                "description": "The ID of a parent menu item; this makes the item a child of a previously added item."
-              },
-              "documentUrlPatterns": {
-                "type": "array",
-                "items": {"type": "string"},
-                "optional": true,
-                "description": "Restricts the item to apply only to documents or frames whose URL matches one of the given patterns. For details on pattern formats, see <a href='/docs/extensions/develop/concepts/match-patterns'>Match Patterns</a>."
-              },
-              "targetUrlPatterns": {
-                "type": "array",
-                "items": {"type": "string"},
-                "optional": true,
-                "description": "Similar to <code>documentUrlPatterns</code>, filters based on the <code>src</code> attribute of <code>img</code>, <code>audio</code>, and <code>video</code> tags and the <code>href</code> attribute of <code>a</code> tags."
-              },
-              "enabled": {
-                "type": "boolean",
-                "optional": true,
-                "description": "Whether this context menu item is enabled or disabled. Defaults to <code>true</code>."
-              }
-            }
+            "$ref": "CreateProperties",
+            "name": "createProperties"
           }
         ],
         "returns_async": {
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index e0d631d8..1395e07 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -3301,6 +3301,8 @@
 // latter if necessary. The timestamp therefore represents the "freshness" of
 // the CWS information saved.
 inline constexpr char kCWSInfoTimestamp[] = "extensions.cws_info_timestamp";
+inline constexpr char kCWSInfoFetchErrorTimestamp[] =
+    "extensions.cws_info_fetch_error_timestamp";
 
 // A bool value for running GarbageCollectStoragePartitionCommand.
 inline constexpr char kShouldGarbageCollectStoragePartitions[] =
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index 9c82ba7..16d9a63 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -448,8 +448,6 @@
   chrome_extensions_renderer_client->RenderThreadStarted();
   WebSecurityPolicy::RegisterURLSchemeAsExtension(
       WebString::FromASCII(extensions::kExtensionScheme));
-  WebSecurityPolicy::RegisterURLSchemeAsCodeCacheWithHashing(
-      WebString::FromASCII(extensions::kExtensionScheme));
 #endif
 
 #if BUILDFLAG(ENABLE_SPELLCHECK)
diff --git a/chrome/renderer/wallet/boarding_pass_extractor.cc b/chrome/renderer/wallet/boarding_pass_extractor.cc
index cf4cc436..a424ad3 100644
--- a/chrome/renderer/wallet/boarding_pass_extractor.cc
+++ b/chrome/renderer/wallet/boarding_pass_extractor.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/renderer/wallet/boarding_pass_extractor.h"
 
+#include "base/metrics/histogram_macros.h"
 #include "chrome/common/chrome_isolated_world_ids.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_thread.h"
@@ -170,6 +171,9 @@
       .SetDetected(!boarding_passes.empty())
       .Record(ukm_recorder_.get());
 
+  UMA_HISTOGRAM_BOOLEAN("Android.Wallet.BoardingPass.Detected",
+                        !boarding_passes.empty());
+
   std::move(callback).Run(std::move(boarding_passes));
 }
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 84edf522..b7065f0 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3640,7 +3640,6 @@
         "../browser/extensions/background_script_executor_browsertest.cc",
         "../browser/extensions/background_scripts_apitest.cc",
         "../browser/extensions/background_xhr_browsertest.cc",
-        "../browser/extensions/cache_wasm_extension_browsertest.cc",
         "../browser/extensions/calculator_app_browsertest.cc",
         "../browser/extensions/chrome_app_api_browsertest.cc",
         "../browser/extensions/chrome_test_extension_loader_browsertest.cc",
@@ -3985,7 +3984,6 @@
       data += [
         "//chrome/test/data/extensions/",
         "//extensions/test/data/",
-        "//third_party/blink/web_tests/http/tests/wasm/resources/large.wasm",
       ]
 
       if (enable_plugins) {
@@ -11078,6 +11076,7 @@
           "../browser/ui/webui/ash/settings/integration_tests/open_keyboard_subpage_interactive_uitest.cc",
           "../browser/ui/webui/ash/settings/integration_tests/open_touchpad_subpage_interactive_uitest.cc",
           "../browser/ui/webui/ash/settings/integration_tests/privacy_hub_interactive_uitest.cc",
+          "../browser/ui/webui/ash/settings/integration_tests/swap_primary_mouse_button_interactive_uitest.cc",
           "../browser/ui/webui/ash/settings/integration_tests/trackpoint_enabled_interactive_uitest.cc",
           "../browser/ui/webui/ash/settings/pages/device/integration_tests/audio_page_interactive_uitest.cc",
           "../browser/ui/webui/ash/shortcut_customization/integration_tests/add_accelerator_disruptive_interactive_uitest.cc",
diff --git a/chrome/test/data/extensions/api_test/cookies/api/background.js b/chrome/test/data/extensions/api_test/cookies/api/background.js
index cabab3b3..897c36e 100644
--- a/chrome/test/data/extensions/api_test/cookies/api/background.js
+++ b/chrome/test/data/extensions/api_test/cookies/api/background.js
@@ -501,6 +501,23 @@
                                   chrome.test.assertEq(5, cookies.length);
                                 }));
 
+          // Confirm that passing an undefined top level site, returns
+          // cookies with and without partition keys.
+          chrome.cookies.getAll(
+              {partitionKey: {topLevelSite: undefined}},
+              pass(function(cookies) {
+                chrome.test.assertEq(5, cookies.length);
+              }));
+
+          // Confirm that passing an empty string for top level site,
+          // returns unpartitioned cookies.
+          chrome.cookies.getAll(
+              {partitionKey: {topLevelSite: ''}}, pass(function(cookies) {
+                chrome.test.assertEq(1, cookies.length);
+                chrome.test.assertEq(TEST_BASIC_COOKIE.name, cookies[0].name);
+                chrome.test.assertEq(null, cookies[0].partitionKey);
+              }));
+
           // Confirm that passing an empty object will only get
           // cookies with no partition key.
           chrome.cookies.getAll(
diff --git a/chrome/test/data/pdf/layout_test.ts b/chrome/test/data/pdf/layout_test.ts
index 312b16e..7c0db69 100644
--- a/chrome/test/data/pdf/layout_test.ts
+++ b/chrome/test/data/pdf/layout_test.ts
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {PdfScriptingApi} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_scripting_api.js';
 import {PdfViewerElement} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js';
 
 // Tests common to all PDFs.
@@ -49,11 +48,8 @@
   ],
 };
 
-const scriptingAPI = new PdfScriptingApi(window, window);
-scriptingAPI.setLoadCompleteCallback((success) => {
-  if (success && document.title in perLayoutTests) {
-    chrome.test.runTests(tests.concat(perLayoutTests[document.title]!));
-  } else {
-    chrome.test.fail(document.title);
-  }
-});
+if (document.title in perLayoutTests) {
+  chrome.test.runTests(tests.concat(perLayoutTests[document.title]!));
+} else {
+  chrome.test.fail(document.title);
+}
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts
index ae7ca05..874e74b0 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts
@@ -928,6 +928,15 @@
         acceleratorConfigResult, expectedErrorMessage);
   });
 
+  test('ValidateNonStandardWithSearch', async () => {
+    const acceleratorConfigResult =
+        AcceleratorConfigResult.kNonStandardWithSearch;
+    const expectedErrorMessage =
+        '] is not available with the launcher key. Press a new shortcut.';
+    await validateAcceleratorInDialog(
+        acceleratorConfigResult, expectedErrorMessage);
+  });
+
   test('DisableDefaultAccelerator', async () => {
     page = initShortcutCustomizationAppElement();
     await flushTasks();
diff --git a/chrome/test/data/webui/cr_elements/cr_expand_button_test.ts b/chrome/test/data/webui/cr_elements/cr_expand_button_test.ts
index 697954a..4f8ba91 100644
--- a/chrome/test/data/webui/cr_elements/cr_expand_button_test.ts
+++ b/chrome/test/data/webui/cr_elements/cr_expand_button_test.ts
@@ -8,6 +8,7 @@
 import {CrExpandButtonElement} from 'chrome://resources/cr_elements/cr_expand_button/cr_expand_button.js';
 import {CrIconButtonElement} from 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {eventToPromise} from 'chrome://webui-test/test_util.js';
 // clang-format on
 
 suite('cr-expand-button', function() {
@@ -16,41 +17,58 @@
   const expandTitle = 'expand title';
   const collapseTitle = 'collapse title';
 
-  setup(() => {
+  setup(async () => {
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
     button = document.createElement('cr-expand-button');
     document.body.appendChild(button);
-    icon = button.shadowRoot!.querySelector<CrIconButtonElement>('#icon')!;
+    icon = button.$.icon;
+    await button.updateComplete;
   });
 
-  test('setting |aria-label| label', () => {
+  test('setting |aria-label| label', async () => {
     assertFalse(!!button.ariaLabel);
     assertEquals('label', icon.getAttribute('aria-labelledby'));
     assertEquals(null, icon.getAttribute('aria-label'));
     const ariaLabel = 'aria-label label';
     button.ariaLabel = ariaLabel;
+    await button.updateComplete;
     assertEquals(null, icon.getAttribute('aria-labelledby'));
     assertEquals(ariaLabel, icon.getAttribute('aria-label'));
   });
 
-  test('changing |expanded|', () => {
+  test('changing |expanded|', async () => {
     button.expandTitle = expandTitle;
     button.collapseTitle = collapseTitle;
+    await button.updateComplete;
     assertFalse(button.expanded);
     assertEquals(expandTitle, button.title);
     assertEquals('false', icon.getAttribute('aria-expanded'));
     assertEquals('cr:expand-more', icon.ironIcon);
     button.expanded = true;
+    await button.updateComplete;
     assertEquals(collapseTitle, button.title);
     assertEquals('true', icon.getAttribute('aria-expanded'));
     assertEquals('cr:expand-less', icon.ironIcon);
   });
 
-  test('changing |disabled|', () => {
+  test('expanded-changed event fires', async () => {
+    let whenFired = eventToPromise('expanded-changed', button);
+    button.expanded = true;
+    let event = await whenFired;
+    assertTrue(event.detail.value);
+
+    whenFired = eventToPromise('expanded-changed', button);
+    button.expanded = false;
+    event = await whenFired;
+    assertFalse(event.detail.value);
+  });
+
+  test('changing |disabled|', async () => {
     assertFalse(button.disabled);
     assertEquals('false', icon.getAttribute('aria-expanded'));
     assertFalse(icon.disabled);
     button.disabled = true;
+    await button.updateComplete;
     assertEquals('false', icon.getAttribute('aria-expanded'));
     assertTrue(icon.disabled);
   });
@@ -66,25 +84,29 @@
     assertEquals(labelId, icon.getAttribute('aria-labelledby'));
   });
 
-  test('setting |expand-icon| and |collapse-icon|', () => {
+  test('setting |expand-icon| and |collapse-icon|', async () => {
     const expandIconName = 'cr:arrow-drop-down';
     button.setAttribute('expand-icon', expandIconName);
     const collapseIconName = 'cr:arrow-drop-up';
     button.setAttribute('collapse-icon', collapseIconName);
+    await button.updateComplete;
 
     assertFalse(button.expanded);
     assertEquals(expandIconName, icon.ironIcon);
     button.expanded = true;
+    await button.updateComplete;
     assertEquals(collapseIconName, icon.ironIcon);
   });
 
-  test('setting |expand-title| and |collapse-title|', () => {
+  test('setting |expand-title| and |collapse-title|', async () => {
     assertFalse(button.expanded);
     button.expandTitle = expandTitle;
+    await button.updateComplete;
     assertEquals(expandTitle, button.title);
 
     button.click();
     button.collapseTitle = collapseTitle;
+    await button.updateComplete;
     assertEquals(collapseTitle, button.title);
   });
 });
diff --git a/chrome/test/data/webui/extensions/review_panel_test.ts b/chrome/test/data/webui/extensions/review_panel_test.ts
index 09c2fca0..090bc35 100644
--- a/chrome/test/data/webui/extensions/review_panel_test.ts
+++ b/chrome/test/data/webui/extensions/review_panel_test.ts
@@ -7,7 +7,6 @@
 
 import {ExtensionsHatsBrowserProxyImpl, ExtensionsReviewPanelElement, PluralStringProxyImpl} from 'chrome://extensions/extensions.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
 import {TestPluralStringProxy} from 'chrome://webui-test/test_plural_string_proxy.js';
@@ -72,7 +71,7 @@
     assertTrue(isVisible(safetyHubHeader));
   });
 
-  test('CollapsibleList', function() {
+  test('CollapsibleList', async function() {
     const expandButton = element.$.expandButton;
     assertTrue(!!expandButton);
 
@@ -85,7 +84,7 @@
 
     // User collapses the list.
     expandButton.click();
-    flush();
+    await expandButton.updateComplete;
 
     // Button and list are collapsed.
     assertFalse(expandButton.expanded);
@@ -93,7 +92,7 @@
 
     // User expands the list.
     expandButton.click();
-    flush();
+    await expandButton.updateComplete;
 
     // Button and list are expanded.
     assertTrue(expandButton.expanded);
diff --git a/chrome/test/data/webui/extensions/site_permissions_site_group_test.ts b/chrome/test/data/webui/extensions/site_permissions_site_group_test.ts
index e94f0f3..79e4363 100644
--- a/chrome/test/data/webui/extensions/site_permissions_site_group_test.ts
+++ b/chrome/test/data/webui/extensions/site_permissions_site_group_test.ts
@@ -53,8 +53,10 @@
     const sitesList =
         element.shadowRoot!.querySelector<HTMLElement>('#sites-list');
     assertFalse(isVisible(sitesList));
-    element.shadowRoot!.querySelector<HTMLElement>('cr-expand-button')!.click();
-    flush();
+    const expandButton = element.shadowRoot!.querySelector('cr-expand-button');
+    assertTrue(!!expandButton);
+    expandButton.click();
+    await expandButton.updateComplete;
 
     assertTrue(isVisible(sitesList));
     const expandedSites =
@@ -96,8 +98,10 @@
     assertEquals('google.ca', element.$.etldOrSite.innerText);
     assertEquals('', element.$.etldOrSiteSubtext.innerText);
 
-    element.shadowRoot!.querySelector<HTMLElement>('cr-expand-button')!.click();
-    flush();
+    const expandButton = element.shadowRoot!.querySelector('cr-expand-button');
+    assertTrue(!!expandButton);
+    expandButton.click();
+    await expandButton.updateComplete;
 
     assertTrue(isVisible(
         element.shadowRoot!.querySelector<HTMLElement>('#sites-list')));
diff --git a/chrome/test/data/webui/password_manager/checkup_details_section_test.ts b/chrome/test/data/webui/password_manager/checkup_details_section_test.ts
index 552bf34..77be369 100644
--- a/chrome/test/data/webui/password_manager/checkup_details_section_test.ts
+++ b/chrome/test/data/webui/password_manager/checkup_details_section_test.ts
@@ -261,6 +261,7 @@
     assertFalse(isVisible(listItemElements[0]));
 
     dismissedButton.click();
+    await dismissedButton.updateComplete;
 
     assertTrue(isVisible(listItemElements[0]));
   });
diff --git a/chrome/test/data/webui/settings/collapse_radio_button_test.ts b/chrome/test/data/webui/settings/collapse_radio_button_test.ts
index f6de942..b342319e 100644
--- a/chrome/test/data/webui/settings/collapse_radio_button_test.ts
+++ b/chrome/test/data/webui/settings/collapse_radio_button_test.ts
@@ -83,33 +83,33 @@
 
   // When the button is not selected clicking the expand icon should still
   // open the iron collapse.
-  test('openOnExpandHit', function() {
+  test('openOnExpandHit', async function() {
     const collapse =
         collapseRadioButton.shadowRoot!.querySelector('iron-collapse')!;
     collapseRadioButton.checked = false;
     flush();
     assertFalse(collapse.opened);
-    collapseRadioButton.shadowRoot!.querySelector('cr-expand-button')!.click();
-    flush();
+    collapseRadioButton.$.expandButton.click();
+    await collapseRadioButton.$.expandButton.updateComplete;
     assertTrue(collapse.opened);
   });
 
   // When the button is selected clicking the expand icon should still close
   // the iron collapse.
-  test('closeOnExpandHitWhenSelected', function() {
+  test('closeOnExpandHitWhenSelected', async function() {
     const collapse =
         collapseRadioButton.shadowRoot!.querySelector('iron-collapse')!;
     collapseRadioButton.checked = true;
     flush();
     assertTrue(collapse.opened);
-    collapseRadioButton.shadowRoot!.querySelector('cr-expand-button')!.click();
-    flush();
+    collapseRadioButton.$.expandButton.click();
+    await collapseRadioButton.$.expandButton.updateComplete;
     assertFalse(collapse.opened);
   });
 
   // When the noAutomaticCollapse flag if set, the expand arrow should expand
   // the radio button immediately.
-  test('openOnExpandHitWhenNoAutomaticCollapse', function() {
+  test('openOnExpandHitWhenNoAutomaticCollapse', async function() {
     const collapse =
         collapseRadioButton.shadowRoot!.querySelector('iron-collapse')!;
     collapseRadioButton.checked = false;
@@ -120,14 +120,14 @@
     flush();
     assertFalse(collapse.opened);
 
-    collapseRadioButton.shadowRoot!.querySelector('cr-expand-button')!.click();
-    flush();
+    collapseRadioButton.$.expandButton.click();
+    await collapseRadioButton.$.expandButton.updateComplete;
     assertTrue(collapse.opened);
   });
 
   // When the noAutomaticCollapse flag if set, the expand arrow should collapse
   // the radio button immediately.
-  test('closeOnExpandHitWhenSelectedWhenNoAutomaticCollapse', function() {
+  test('closeOnExpandHitWhenSelectedWhenNoAutomaticCollapse', async function() {
     const collapse =
         collapseRadioButton.shadowRoot!.querySelector('iron-collapse')!;
     collapseRadioButton.checked = true;
@@ -138,8 +138,8 @@
     flush();
     assertTrue(collapse.opened);
 
-    collapseRadioButton.shadowRoot!.querySelector('cr-expand-button')!.click();
-    flush();
+    collapseRadioButton.$.expandButton.click();
+    await collapseRadioButton.$.expandButton.updateComplete;
     assertFalse(collapse.opened);
   });
 
@@ -153,7 +153,7 @@
     assertFalse(isChildVisible(collapseRadioButton, '.separator'));
   });
 
-  test('openOnExpandHitWhenDisabled', function() {
+  test('openOnExpandHitWhenDisabled', async function() {
     collapseRadioButton.checked = false;
     collapseRadioButton.disabled = true;
     const collapse =
@@ -161,9 +161,9 @@
 
     flush();
     assertFalse(collapse.opened);
-    collapseRadioButton.shadowRoot!.querySelector('cr-expand-button')!.click();
+    collapseRadioButton.$.expandButton.click();
 
-    flush();
+    await collapseRadioButton.$.expandButton.updateComplete;
     assertTrue(collapse.opened);
   });
 
diff --git a/chrome/test/data/webui/settings/get_most_chrome_page_test.ts b/chrome/test/data/webui/settings/get_most_chrome_page_test.ts
index 9c28582b..afd7cec 100644
--- a/chrome/test/data/webui/settings/get_most_chrome_page_test.ts
+++ b/chrome/test/data/webui/settings/get_most_chrome_page_test.ts
@@ -34,17 +34,19 @@
     flush();
   });
 
-  test('Basic', function() {
+  test('Basic', async function() {
     const rows = testElement.shadowRoot!.querySelectorAll('cr-expand-button');
     assertTrue(rows.length > 0);
-    rows.forEach((row) => {
+    for (const row of rows) {
       const ironCollapse = row.nextElementSibling as IronCollapseElement;
       assertTrue(!!ironCollapse);
 
       assertFalse(ironCollapse.opened);
       row.click();
+      await row.updateComplete;
+
       assertTrue(ironCollapse.opened);
-    });
+    }
   });
 
   test('HatsSurveyRequested', async function() {
diff --git a/chrome/test/data/webui/settings/people_page_sync_page_test.ts b/chrome/test/data/webui/settings/people_page_sync_page_test.ts
index d57b329..377d510 100644
--- a/chrome/test/data/webui/settings/people_page_sync_page_test.ts
+++ b/chrome/test/data/webui/settings/people_page_sync_page_test.ts
@@ -8,7 +8,7 @@
 import {webUIListenerCallback} from 'chrome://resources/js/cr.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import type {CrInputElement, SettingsSyncEncryptionOptionsElement, SettingsSyncPageElement} from 'chrome://settings/lazy_load.js';
+import type {CrExpandButtonElement, CrInputElement, SettingsSyncEncryptionOptionsElement, SettingsSyncPageElement} from 'chrome://settings/lazy_load.js';
 // <if expr="not chromeos_ash">
 import type {CrDialogElement} from 'chrome://settings/lazy_load.js';
 // </if>
@@ -247,15 +247,17 @@
     assertTrue(spinnerPage.hidden);
   });
 
-  test('EncryptionExpandButton', function() {
+  test('EncryptionExpandButton', async function() {
     const encryptionDescription =
-        syncPage.shadowRoot!.querySelector<HTMLElement>(
-            '#encryptionDescription')!;
+        syncPage.shadowRoot!.querySelector<CrExpandButtonElement>(
+            '#encryptionDescription');
+    assertTrue(!!encryptionDescription);
     const encryptionCollapse = syncPage.$.encryptionCollapse;
 
     // No encryption with custom passphrase.
     assertFalse(encryptionCollapse.opened);
     encryptionDescription.click();
+    await encryptionDescription.updateComplete;
     assertTrue(encryptionCollapse.opened);
 
     // Push sync prefs with |prefs.encryptAllData| unchanged. The encryption
@@ -265,6 +267,7 @@
     assertTrue(encryptionCollapse.opened);
 
     encryptionDescription.click();
+    await encryptionDescription.updateComplete;
     assertFalse(encryptionCollapse.opened);
 
     // Data encrypted with custom passphrase.
diff --git a/chrome/test/data/webui/settings/performance_page_test.ts b/chrome/test/data/webui/settings/performance_page_test.ts
index 7e64e3e..04bf1aa 100644
--- a/chrome/test/data/webui/settings/performance_page_test.ts
+++ b/chrome/test/data/webui/settings/performance_page_test.ts
@@ -493,9 +493,11 @@
     assertFalse(exceptionList.$.expandButton.hidden);
 
     exceptionList.$.expandButton.click();
+    await exceptionList.$.expandButton.updateComplete;
     assertTrue(exceptionList.$.collapse.opened);
 
     exceptionList.$.expandButton.click();
+    await exceptionList.$.expandButton.updateComplete;
     assertFalse(exceptionList.$.collapse.opened);
 
     exceptionList.$.addButton.click();
diff --git a/chrome/test/data/webui/settings/review_notification_permissions_test.ts b/chrome/test/data/webui/settings/review_notification_permissions_test.ts
index 655966c..a93b906 100644
--- a/chrome/test/data/webui/settings/review_notification_permissions_test.ts
+++ b/chrome/test/data/webui/settings/review_notification_permissions_test.ts
@@ -476,7 +476,7 @@
 
     // User collapses the list.
     expandButton.click();
-    flush();
+    await expandButton.updateComplete;
     await assertMetricsInteraction(
         SafetyCheckNotificationsModuleInteractions.MINIMIZE);
 
@@ -486,7 +486,7 @@
 
     // User expands the list.
     expandButton.click();
-    flush();
+    await expandButton.updateComplete;
 
     // Button and list are expanded.
     assertTrue(expandButton.expanded);
diff --git a/chrome/test/data/webui/settings/security_page_test.ts b/chrome/test/data/webui/settings/security_page_test.ts
index c496c14..0ff9209b 100644
--- a/chrome/test/data/webui/settings/security_page_test.ts
+++ b/chrome/test/data/webui/settings/security_page_test.ts
@@ -494,7 +494,7 @@
 
   test(
       'SafeBrowsingRadio_ManuallyExpandedRemainExpandedOnRepeatSelection',
-      function() {
+      async function() {
         page.$.safeBrowsingStandard.click();
         flush();
         assertEquals(
@@ -506,7 +506,7 @@
         // Expanding another radio button should not collapse already expanded
         // option.
         page.$.safeBrowsingEnhanced.$.expandButton.click();
-        flush();
+        await page.$.safeBrowsingEnhanced.$.expandButton.updateComplete;
         assertTrue(page.$.safeBrowsingStandard.expanded);
         assertTrue(page.$.safeBrowsingEnhanced.expanded);
 
@@ -528,7 +528,7 @@
             page.prefs.generated.safe_browsing.value);
 
         page.$.safeBrowsingEnhanced.$.expandButton.click();
-        flush();
+        await page.$.safeBrowsingEnhanced.$.expandButton.updateComplete;
         assertTrue(page.$.safeBrowsingStandard.expanded);
         assertTrue(page.$.safeBrowsingEnhanced.expanded);
 
diff --git a/chrome/test/data/webui/settings/site_settings_page_test.ts b/chrome/test/data/webui/settings/site_settings_page_test.ts
index d21ff73..a1b6c20 100644
--- a/chrome/test/data/webui/settings/site_settings_page_test.ts
+++ b/chrome/test/data/webui/settings/site_settings_page_test.ts
@@ -6,7 +6,7 @@
 import {webUIListenerCallback} from 'chrome://resources/js/cr.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import type {SettingsSiteSettingsPageElement} from 'chrome://settings/lazy_load.js';
+import type {CrExpandButtonElement, SettingsSiteSettingsPageElement} from 'chrome://settings/lazy_load.js';
 import {ContentSetting, CookieControlsMode, ContentSettingsTypes, defaultSettingLabel, SettingsState, SafetyHubBrowserProxyImpl, SafetyHubEvent} from 'chrome://settings/lazy_load.js';
 import type {CrLinkRowElement, SettingsToggleButtonElement} from 'chrome://settings/settings.js';
 import {Router, routes} from 'chrome://settings/settings.js';
@@ -176,20 +176,26 @@
         notificationsLinkRow.subLabel);
   });
 
-  test('ProtectedContentRow', function() {
+  test('ProtectedContentRow', async function() {
     setupPage();
-    page.shadowRoot!.querySelector<HTMLElement>('#expandContent')!.click();
-    flush();
+    const expandButton =
+        page.shadowRoot!.querySelector<CrExpandButtonElement>('#expandContent');
+    assertTrue(!!expandButton);
+    expandButton.click();
+    await expandButton.updateComplete;
     assertTrue(isChildVisible(
         page.shadowRoot!.querySelector('#advancedContentList')!,
         '#protected-content'));
   });
 
   // TODO(crbug/1378703): Remove after crbug/1378703 launched.
-  test('SiteDataLinkRow', function() {
+  test('SiteDataLinkRow', async function() {
     setupPage();
-    page.shadowRoot!.querySelector<HTMLElement>('#expandContent')!.click();
-    flush();
+    const expandButton =
+        page.shadowRoot!.querySelector<CrExpandButtonElement>('#expandContent');
+    assertTrue(!!expandButton);
+    expandButton.click();
+    await expandButton.updateComplete;
 
     assertTrue(isChildVisible(
         page.shadowRoot!.querySelector('#advancedContentList')!, '#site-data'));
diff --git a/chrome/test/data/webui/settings/speed_page_test.ts b/chrome/test/data/webui/settings/speed_page_test.ts
index ffafdcf..48933a249 100644
--- a/chrome/test/data/webui/settings/speed_page_test.ts
+++ b/chrome/test/data/webui/settings/speed_page_test.ts
@@ -108,31 +108,33 @@
     assertTrue(speedPage.$.preloadingExtended.expanded);
   });
 
-  test('testPreloadPagesStandardExpand', function() {
+  test('testPreloadPagesStandardExpand', async function() {
     // By default, the preloadingStandard option will be selected and collapsed.
     assertFalse(speedPage.$.preloadingStandard.expanded);
 
-    speedPage.$.preloadingStandard.$.expandButton.click();
-    flush();
+    const expandButton = speedPage.$.preloadingStandard.$.expandButton;
+    expandButton.click();
+    await expandButton.updateComplete;
 
     assertTrue(speedPage.$.preloadingStandard.expanded);
 
-    speedPage.$.preloadingStandard.$.expandButton.click();
-    flush();
+    expandButton.click();
+    await expandButton.updateComplete;
 
     assertFalse(speedPage.$.preloadingStandard.expanded);
   });
 
-  test('testPreloadPagesExtendedExpand', function() {
+  test('testPreloadPagesExtendedExpand', async function() {
     assertFalse(speedPage.$.preloadingExtended.expanded);
 
-    speedPage.$.preloadingExtended.$.expandButton.click();
-    flush();
+    const expandButton = speedPage.$.preloadingExtended.$.expandButton;
+    expandButton.click();
+    await expandButton.updateComplete;
 
     assertTrue(speedPage.$.preloadingExtended.expanded);
 
-    speedPage.$.preloadingExtended.$.expandButton.click();
-    flush();
+    expandButton.click();
+    await expandButton.updateComplete;
 
     assertFalse(speedPage.$.preloadingExtended.expanded);
   });
diff --git a/chrome/test/data/webui/settings/storage_access_site_list_entry_test.ts b/chrome/test/data/webui/settings/storage_access_site_list_entry_test.ts
index d5d46c0..eb0bba6 100644
--- a/chrome/test/data/webui/settings/storage_access_site_list_entry_test.ts
+++ b/chrome/test/data/webui/settings/storage_access_site_list_entry_test.ts
@@ -7,8 +7,7 @@
 // clang-format off
 import 'chrome://settings/lazy_load.js';
 
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import type {StorageAccessStaticSiteListEntry, StorageAccessSiteException, StorageAccessSiteListEntryElement} from 'chrome://settings/lazy_load.js';
+import type {CrExpandButtonElement, StorageAccessStaticSiteListEntry, StorageAccessSiteException, StorageAccessSiteListEntryElement} from 'chrome://settings/lazy_load.js';
 import {ContentSetting, ContentSettingsTypes, SiteSettingsPrefsBrowserProxyImpl} from 'chrome://settings/lazy_load.js';
 import {assertEquals, assertDeepEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
@@ -110,9 +109,11 @@
         secondLine.textContent!.trim());
 
     const expandButton =
-        testElement.shadowRoot.querySelector<HTMLElement>('#expandButton');
+        testElement.shadowRoot.querySelector<CrExpandButtonElement>(
+            '#expandButton');
     assertTrue(!!expandButton);
     expandButton.click();
+    await expandButton.updateComplete;
 
     // Validate the row description when opened.
     assertEquals(
@@ -124,10 +125,11 @@
 
     assertTrue(!!testElement.shadowRoot);
     const expandButton =
-        testElement.shadowRoot.querySelector<HTMLElement>('#expandButton');
+        testElement.shadowRoot.querySelector<CrExpandButtonElement>(
+            '#expandButton');
     assertTrue(!!expandButton);
     expandButton.click();
-    flush();
+    await expandButton.updateComplete;
 
     // Validate that the nested site entries are created on the collapsible
     // element.
@@ -237,7 +239,8 @@
 
     assertTrue(!!testElement.shadowRoot);
     const expandButton =
-        testElement.shadowRoot.querySelector<HTMLElement>('#expandButton');
+        testElement.shadowRoot.querySelector<CrExpandButtonElement>(
+            '#expandButton');
     assertTrue(!!expandButton);
 
     // Validate expand button aria-label when closed.
@@ -247,6 +250,7 @@
         expectedExpandOpenArialLabel, expandButton.getAttribute('aria-label'));
 
     expandButton.click();
+    await expandButton.updateComplete;
 
     // Validate expand button aria-label when opened.
     const expectedExpandCloseArialLabel =
diff --git a/chrome/test/data/webui/settings/unused_site_permissions_test.ts b/chrome/test/data/webui/settings/unused_site_permissions_test.ts
index 77ee579..da7bf3cb 100644
--- a/chrome/test/data/webui/settings/unused_site_permissions_test.ts
+++ b/chrome/test/data/webui/settings/unused_site_permissions_test.ts
@@ -193,7 +193,7 @@
 
     // User collapses the list.
     expandButton.click();
-    flush();
+    await expandButton.updateComplete;
 
     // Button and list are collapsed.
     assertFalse(expandButton.expanded);
@@ -206,7 +206,7 @@
 
     // User expands the list.
     expandButton.click();
-    flush();
+    await expandButton.updateComplete;
 
     // Button and list are expanded.
     assertTrue(expandButton.expanded);
diff --git a/chrome/test/data/webui/tab_search/tab_search_page_test.ts b/chrome/test/data/webui/tab_search/tab_search_page_test.ts
index 0447cff..336a098 100644
--- a/chrome/test/data/webui/tab_search/tab_search_page_test.ts
+++ b/chrome/test/data/webui/tab_search/tab_search_page_test.ts
@@ -697,6 +697,7 @@
       recentlyClosedTabs: SAMPLE_RECENTLY_CLOSED_DATA,
       recentlyClosedSectionExpanded: true,
     }));
+    assertEquals(1, testProxy.getCallCount('saveRecentlyClosedExpandedPref'));
     assertEquals(3, queryRows().length);
 
     const recentlyClosedTitleItem = queryListTitle()[1];
@@ -707,15 +708,18 @@
     assertTrue(!!recentlyClosedTitleExpandButton);
 
     // Collapse the `Recently Closed` section and assert item count.
-    recentlyClosedTitleExpandButton!.click();
-    const [expanded] =
+    testProxy.resetResolver('saveRecentlyClosedExpandedPref');
+    recentlyClosedTitleExpandButton.click();
+    let [expanded] =
         await testProxy.whenCalled('saveRecentlyClosedExpandedPref');
     assertFalse(expanded);
     assertEquals(1, queryRows().length);
 
     // Expand the `Recently Closed` section and assert item count.
-    recentlyClosedTitleExpandButton!.click();
-    assertEquals(2, testProxy.getCallCount('saveRecentlyClosedExpandedPref'));
+    testProxy.resetResolver('saveRecentlyClosedExpandedPref');
+    recentlyClosedTitleExpandButton.click();
+    [expanded] = await testProxy.whenCalled('saveRecentlyClosedExpandedPref');
+    assertTrue(expanded);
     assertEquals(3, queryRows().length);
   });
 
diff --git a/chrome/updater/app/server/win/com_classes_legacy.cc b/chrome/updater/app/server/win/com_classes_legacy.cc
index 4181d3f6..383eb5b3 100644
--- a/chrome/updater/app/server/win/com_classes_legacy.cc
+++ b/chrome/updater/app/server/win/com_classes_legacy.cc
@@ -375,31 +375,32 @@
 
     auto result = base::MakeRefCounted<RegisterAppResult>();
     AppServerWin::PostRpcTask(base::BindOnce(
-        [](AppWebImplPtr obj, const std::wstring& brand_code,
-           const std::wstring& ap, scoped_refptr<RegisterAppResult> result) {
+        [](AppWebImplPtr obj, scoped_refptr<RegisterAppResult> result) {
           const base::ScopedClosureRunner signal_event(base::BindOnce(
               [](scoped_refptr<RegisterAppResult> result) {
                 result->completion_event.Signal();
               },
               result));
 
-          scoped_refptr<PersistedData> persisted_data =
-              GetAppServerWinInstance()->config()->GetUpdaterPersistedData();
-          if (persisted_data->GetProductVersion(obj->app_id_).IsValid()) {
-            return;
-          }
-
-          // Pre-register the app if there is no registration for it. This app
-          // registration is removed later if the app install does not happen.
-          result->new_install = true;
+          // Always update ap.
           RegistrationRequest request;
           request.app_id = obj->app_id_;
-          request.version = base::Version(kNullVersion);
-          request.brand_code = base::WideToASCII(brand_code);
-          request.ap = base::WideToASCII(ap);
+          request.ap = obj->ap_;
+
+          // Pre-register the app with a version of "0.0.0.0" if there is no
+          // registration for it. This app registration is removed later if
+          // the app install does not happen.
+          scoped_refptr<PersistedData> persisted_data =
+              GetAppServerWinInstance()->config()->GetUpdaterPersistedData();
+          if (!persisted_data->GetProductVersion(obj->app_id_).IsValid()) {
+            result->new_install = true;
+            request.brand_code = obj->brand_code_;
+            request.version = base::Version(kNullVersion);
+          }
+
           persisted_data->RegisterApp(request);
         },
-        AppWebImplPtr(this), brand_code, ap, result));
+        AppWebImplPtr(this), result));
 
     if (!result->completion_event.TimedWait(base::Seconds(60))) {
       return E_FAIL;
diff --git a/chrome/updater/update_service_impl.cc b/chrome/updater/update_service_impl.cc
index dc6cfe3..4df5495 100644
--- a/chrome/updater/update_service_impl.cc
+++ b/chrome/updater/update_service_impl.cc
@@ -889,10 +889,9 @@
     // registration is removed later if the app install encounters an error.
     config_->GetUpdaterPersistedData()->RegisterApp(registration);
   } else {
-    // Update brand and ap.
+    // Update ap.
     RegistrationRequest request;
     request.app_id = registration.app_id;
-    request.brand_code = registration.brand_code;
     request.ap = registration.ap;
     config_->GetUpdaterPersistedData()->RegisterApp(request);
   }
diff --git a/chromeos/ash/services/network_config/cros_network_config.cc b/chromeos/ash/services/network_config/cros_network_config.cc
index 50282f3..b1e9b88 100644
--- a/chromeos/ash/services/network_config/cros_network_config.cc
+++ b/chromeos/ash/services/network_config/cros_network_config.cc
@@ -3396,29 +3396,33 @@
     // Since rx_bytes may be larger than the maximum value representable by
     // uint32_t, we must check whether it was implicitly converted to a double
     // during D-Bus deserialization.
-    uint64_t rx_bytes;
-    const base::Value* rb = tc_dict.Find("rx_bytes");
-    DCHECK(rb);
-    if (rb->type() == base::Value::Type::INTEGER) {
-      rx_bytes = rb->GetInt();
-    } else if (rb->type() == base::Value::Type::DOUBLE) {
-      rx_bytes = std::floor(rb->GetDouble());
+    uint64_t rx_bytes = 0;
+    if (const base::Value* const rb = tc_dict.Find("rx_bytes")) {
+      if (rb->is_int()) {
+        rx_bytes = rb->GetInt();
+      } else if (rb->is_double()) {
+        rx_bytes = std::floor(rb->GetDouble());
+      } else {
+        LOG(ERROR) << "Unexpected type " << rb->type() << " for rx_bytes";
+      }
     } else {
-      NOTREACHED();
+      LOG(ERROR) << "Missing field: rx_bytes";
     }
 
     // Since tx_bytes may be larger than the maximum value representable by
     // uint32_t, we must check whether it was implicitly converted to a double
     // during D-Bus deserialization.
-    uint64_t tx_bytes;
-    const base::Value* tb = tc_dict.Find("tx_bytes");
-    DCHECK(tb);
-    if (tb->type() == base::Value::Type::INTEGER) {
-      tx_bytes = tb->GetInt();
-    } else if (tb->type() == base::Value::Type::DOUBLE) {
-      tx_bytes = std::floor(tb->GetDouble());
+    uint64_t tx_bytes = 0;
+    if (const base::Value* const tb = tc_dict.Find("tx_bytes")) {
+      if (tb->is_int()) {
+        tx_bytes = tb->GetInt();
+      } else if (tb->is_double()) {
+        tx_bytes = std::floor(tb->GetDouble());
+      } else {
+        LOG(ERROR) << "Unexpected type " << tb->type() << " for tx_bytes";
+      }
     } else {
-      NOTREACHED();
+      LOG(ERROR) << "Missing field: tx_bytes";
     }
 
     counters.push_back(mojom::TrafficCounter::New(
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index d8f61fd3..5973bc1b 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -4395,6 +4395,12 @@
             that includes a reserved key.">
           Shortcut not available. Press a new shortcut without <ph name="key">$1<ex>CapsLock</ex></ph>.
         </message>
+        <message name="IDS_SHORTCUT_CUSTOMIZATION_NON_STANDARD_KEY_WITH_SEARCH_MODIFIER"
+            desc="The status message that displays when user press a key combination
+            that includes a non-standard 101 key and the search modifier."
+            translateable="false">
+          <ph name="key">$1<ex>Volume Up</ex></ph> is not available with the <ph name="meta_key">$2<ex>search</ex></ph> key. Press a new shortcut.
+        </message>
         <message name="IDS_SHORTCUT_CUSTOMIZATION_NON_SEARCH_SHORTCUT_WARNING"
             desc="The status (warning) message that displays when user attempts to input a shortcut that does not include the search/launcher key.">
           Shortcut without <ph name="meta_key">$1<ex>search</ex></ph> key might conflict with some app's shortcut. Press this shortcut again to continue using it, or press a new shortcut using the <ph name="key">$1<ex>search</ex></ph> key.
diff --git a/chromeos/ui/frame/default_frame_header.cc b/chromeos/ui/frame/default_frame_header.cc
index 6a912de..c6a9b79 100644
--- a/chromeos/ui/frame/default_frame_header.cc
+++ b/chromeos/ui/frame/default_frame_header.cc
@@ -56,11 +56,8 @@
 // the window is a system web app.
 bool ShouldApplyDynamicColor(aura::Window* window) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (window->GetProperty(aura::client::kAppType) !=
-      static_cast<int>(ash::AppType::SYSTEM_APP)) {
-    return false;
-  }
-  return true;
+  return window->GetProperty(aura::client::kAppType) ==
+         static_cast<int>(ash::AppType::SYSTEM_APP);
 #else
   // Default frame is used for non-browser frames in Lacros. In Lacros, we
   // never need dynamic colors as we don't display SWAs. This will need to be
diff --git a/clank b/clank
index f1d1538..27098a2 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit f1d153819784da755404355b06bf9d91d1789b71
+Subproject commit 27098a272f4239731ab13adb3dd53bc91652c28f
diff --git a/components/autofill/core/browser/data_model/autofill_profile.cc b/components/autofill/core/browser/data_model/autofill_profile.cc
index 85fd1e85..3cf7a07 100644
--- a/components/autofill/core/browser/data_model/autofill_profile.cc
+++ b/components/autofill/core/browser/data_model/autofill_profile.cc
@@ -1267,8 +1267,8 @@
   return success;
 }
 
-bool AutofillProfile::HasStructuredData() {
-  return base::ranges::any_of(kStructuredDataTypes, [this](auto type) {
+bool AutofillProfile::HasStructuredData() const {
+  return base::ranges::any_of(kStructuredDataTypes, [this](FieldType type) {
     return !this->GetRawInfo(type).empty();
   });
 }
diff --git a/components/autofill/core/browser/data_model/autofill_profile.h b/components/autofill/core/browser/data_model/autofill_profile.h
index ad6950c..3d2c56a 100644
--- a/components/autofill/core/browser/data_model/autofill_profile.h
+++ b/components/autofill/core/browser/data_model/autofill_profile.h
@@ -250,7 +250,7 @@
   // Returns true if the profile contains any structured data. This can be any
   // name type but the full name, or for addresses, the street name or house
   // number.
-  bool HasStructuredData();
+  bool HasStructuredData() const;
 
   // Returns a constant reference to the |name_| field.
   const NameInfo& GetNameInfo() const { return name_; }
diff --git a/components/browser_ui/strings/android/browser_ui_strings.grd b/components/browser_ui/strings/android/browser_ui_strings.grd
index 502cca6..38f839f 100644
--- a/components/browser_ui/strings/android/browser_ui_strings.grd
+++ b/components/browser_ui/strings/android/browser_ui_strings.grd
@@ -1128,7 +1128,7 @@
 
       <!-- Magic stack strings -->
       <message name="IDS_HOME_MODULES_CONTEXT_MENU_HIDE_MODULE" desc="The context menu item to hide a module.">
-          Hide "<ph name="TITLE_OF_MODULE">%1$s<ex>Module Title</ex></ph>"
+          Hide <ph name="TITLE_OF_MODULE">%1$s<ex>Module Title</ex></ph>
       </message>
       <message name="IDS_HOME_MODULES_CONTEXT_MENU_CUSTOMIZE" desc="The context menu item to show the customize homepage settings.">
         Customize
diff --git a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_HOME_MODULES_CONTEXT_MENU_HIDE_MODULE.png.sha1 b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_HOME_MODULES_CONTEXT_MENU_HIDE_MODULE.png.sha1
index 86d96fd1..700f1a9 100644
--- a/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_HOME_MODULES_CONTEXT_MENU_HIDE_MODULE.png.sha1
+++ b/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_HOME_MODULES_CONTEXT_MENU_HIDE_MODULE.png.sha1
@@ -1 +1 @@
-bb460ee33f968cf6b86e4f62f9c0b2cbb9cb992c
\ No newline at end of file
+55cba5b65cca78be33f88f566b9c0012197cd8ff
\ No newline at end of file
diff --git a/components/enterprise/idle/metrics.h b/components/enterprise/idle/metrics.h
index 7dd1ba8..c3dba6f 100644
--- a/components/enterprise/idle/metrics.h
+++ b/components/enterprise/idle/metrics.h
@@ -15,7 +15,7 @@
 
 // IdleTimeout and IdleTimeout policies histogram names.
 inline constexpr char kUMAIdleTimeoutActionSuccessTime[] =
-    "Enterprise.IdleTimeoutPolicies.ActionTimeDuration.%s";
+    "Enterprise.IdleTimeoutPolicies.ActionTime.%s";
 inline constexpr char kUMAIdleTimeoutActionSuccesStatus[] =
     "Enterprise.IdleTimeoutPolicies.Success.%s";
 inline constexpr char kUMAIdleTimeoutActionCase[] =
diff --git a/components/facilitated_payments/core/browser/facilitated_payments_driver.cc b/components/facilitated_payments/core/browser/facilitated_payments_driver.cc
index 00c90d1..987ec84 100644
--- a/components/facilitated_payments/core/browser/facilitated_payments_driver.cc
+++ b/components/facilitated_payments/core/browser/facilitated_payments_driver.cc
@@ -15,7 +15,7 @@
 FacilitatedPaymentsDriver::~FacilitatedPaymentsDriver() = default;
 
 void FacilitatedPaymentsDriver::DidFinishLoad(const GURL& url) const {
-  manager_->DidFinishLoad(url);
+  manager_->DelayedCheckAllowlistAndTriggerPixCodeDetection(url);
 }
 
 }  // namespace payments::facilitated
diff --git a/components/facilitated_payments/core/browser/facilitated_payments_manager.cc b/components/facilitated_payments/core/browser/facilitated_payments_manager.cc
index 012eb59..1617c407 100644
--- a/components/facilitated_payments/core/browser/facilitated_payments_manager.cc
+++ b/components/facilitated_payments/core/browser/facilitated_payments_manager.cc
@@ -4,6 +4,8 @@
 
 #include "components/facilitated_payments/core/browser/facilitated_payments_manager.h"
 
+#include <algorithm>
+
 #include "base/check.h"
 #include "base/functional/callback_helpers.h"
 
@@ -17,41 +19,77 @@
   DCHECK(optimization_guide_decider_);
   // TODO(b/314826708): Check if at least 1 GPay linked PIX account is
   // available for the user. If not, do not register the PIX allowlist.
-  RegisterPixOptimizationGuide();
+  RegisterPixAllowlist();
 }
 
 FacilitatedPaymentsManager::~FacilitatedPaymentsManager() = default;
 
-void FacilitatedPaymentsManager::DidFinishLoad(const GURL& url) const {
-  if (!ShouldDetectPixCode(url)) {
-    return;
+void FacilitatedPaymentsManager::
+    DelayedCheckAllowlistAndTriggerPixCodeDetection(const GURL& url,
+                                                    int attempt_number) {
+  // TODO(b/300332597): If a page navigation takes place, it might be too late,
+  // and PIX code detection might have already run on the previous page. Find an
+  // earlier point in the page loading sequence of events where the timer could
+  // be stopped.
+  // Stop the timer in case it is running from a previous page load.
+  pix_code_detection_triggering_timer_.Stop();
+  switch (GetAllowlistCheckResult(url)) {
+    case optimization_guide::OptimizationGuideDecision::kTrue: {
+      // The PIX code detection should be triggered after `kPageLoadWaitTime`.
+      // Time spent waiting for the allowlist checking infra should be accounted
+      // for.
+      base::TimeDelta trigger_pix_code_detection_delay =
+          std::max(base::Seconds(0),
+                   kPageLoadWaitTime - (attempt_number - 1) *
+                                           kOptimizationGuideDeciderWaitTime);
+      pix_code_detection_triggering_timer_.Start(
+          FROM_HERE, trigger_pix_code_detection_delay,
+          base::BindOnce(&FacilitatedPaymentsManager::TriggerPixCodeDetection,
+                         weak_ptr_factory_.GetWeakPtr()));
+      break;
+    }
+    case optimization_guide::OptimizationGuideDecision::kUnknown: {
+      if (attempt_number >= kMaxAttemptsForAllowlistCheck) {
+        break;
+      }
+      pix_code_detection_triggering_timer_.Start(
+          FROM_HERE, kOptimizationGuideDeciderWaitTime,
+          base::BindOnce(&FacilitatedPaymentsManager::
+                             DelayedCheckAllowlistAndTriggerPixCodeDetection,
+                         weak_ptr_factory_.GetWeakPtr(), url,
+                         attempt_number + 1));
+      break;
+    }
+    case optimization_guide::OptimizationGuideDecision::kFalse:
+      break;
   }
+}
+
+void FacilitatedPaymentsManager::RegisterPixAllowlist() const {
+  optimization_guide_decider_->RegisterOptimizationTypes(
+      {optimization_guide::proto::PIX_PAYMENT_MERCHANT_ALLOWLIST});
+}
+
+optimization_guide::OptimizationGuideDecision
+FacilitatedPaymentsManager::GetAllowlistCheckResult(const GURL& url) const {
+  // Since the optimization guide decider integration corresponding to PIX
+  // merchant lists are allowlists for the question "Can this site be
+  // optimized?", a match on the allowlist answers the question with "yes".
+  // Therefore, `kTrue` indicates that `url` is allowed for running PIX code
+  // detection. If the optimization type was not registered in time when we
+  // queried it, it will be `kUnknown`.
+  return optimization_guide_decider_->CanApplyOptimization(
+      url, optimization_guide::proto::PIX_PAYMENT_MERCHANT_ALLOWLIST,
+      /*optimization_metadata=*/nullptr);
+}
+
+void FacilitatedPaymentsManager::TriggerPixCodeDetection() {
   driver_->TriggerPixCodeDetection(
       base::BindOnce(&FacilitatedPaymentsManager::ProcessPixCodeDetectionResult,
                      weak_ptr_factory_.GetWeakPtr()));
 }
 
-bool FacilitatedPaymentsManager::ShouldDetectPixCode(const GURL& url) const {
-  // Since the optimization guide decider integration corresponding to PIX
-  // merchant lists are allowlists for the question "Can this site be
-  // optimized?", a match on the allowlist answers the question with "yes".
-  // Therefore, ...::kTrue indicates that `url` is allowed for running PIX code
-  // detection. If the optimization type was not registered in time when we
-  // queried it, it will be `kUnknown`, so the default functionality in this
-  // case will be to not run PIX code detection on the webpage.
-  return optimization_guide_decider_->CanApplyOptimization(
-             url, optimization_guide::proto::PIX_PAYMENT_MERCHANT_ALLOWLIST,
-             /*optimization_metadata=*/nullptr) ==
-         optimization_guide::OptimizationGuideDecision::kTrue;
-}
-
 void FacilitatedPaymentsManager::ProcessPixCodeDetectionResult(
     bool pix_code_found) const {}
 
-void FacilitatedPaymentsManager::RegisterPixOptimizationGuide() const {
-  // Register the PIX allowlist.
-  optimization_guide_decider_->RegisterOptimizationTypes(
-      {optimization_guide::proto::PIX_PAYMENT_MERCHANT_ALLOWLIST});
-}
-
 }  // namespace payments::facilitated
diff --git a/components/facilitated_payments/core/browser/facilitated_payments_manager.h b/components/facilitated_payments/core/browser/facilitated_payments_manager.h
index 2faeb53..c29c3135 100644
--- a/components/facilitated_payments/core/browser/facilitated_payments_manager.h
+++ b/components/facilitated_payments/core/browser/facilitated_payments_manager.h
@@ -8,6 +8,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/raw_ref.h"
 #include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
 #include "components/facilitated_payments/core/browser/facilitated_payments_driver.h"
 #include "components/optimization_guide/core/optimization_guide_decider.h"
 
@@ -15,6 +16,11 @@
 
 namespace payments::facilitated {
 
+inline constexpr base::TimeDelta kPageLoadWaitTime = base::Seconds(2);
+inline constexpr base::TimeDelta kOptimizationGuideDeciderWaitTime =
+    base::Seconds(0.5);
+inline constexpr int kMaxAttemptsForAllowlistCheck = 6;
+
 class FacilitatedPaymentsDriver;
 
 // A cross-platform interface that manages the flow of PIX payments between the
@@ -30,33 +36,37 @@
       delete;
   virtual ~FacilitatedPaymentsManager();
 
-  // Initiates the PIX payments flow on the browser. It is invoked by the
-  // `FacilitatedPaymentsDriver` when the primary main frame has finished
-  // loading.
-  void DidFinishLoad(const GURL& url) const;
+  // Initiates the PIX payments flow on the browser. There are 2 steps involved:
+  // 1. Query the allowlist to check if PIX code detection should be run on the
+  // page. It is possible that the infrastructure that supports querying the
+  // allowlist is not ready when the page loads. In this case, we query again
+  // after `kOptimizationGuideDeciderWaitTime`, and repeat
+  // `kMaxAttemptsForAllowlistCheck` times. If the infrastructure is still not
+  // ready, we do not run PIX code detection. `attempt_number` is an internal
+  // counter for the number of attempts at querying.
+  // 2. Trigger PIX code detection on the page after `kPageLoadWaitTime`. The
+  // delay allows async content to load on the page. It also prevents PIX code
+  // detection negatively impacting page load performance.
+  void DelayedCheckAllowlistAndTriggerPixCodeDetection(const GURL& url,
+                                                       int attempt_number = 1);
 
  private:
   friend class FacilitatedPaymentsManagerTest;
   FRIEND_TEST_ALL_PREFIXES(FacilitatedPaymentsManagerTest,
-                           TestRegisterPixOptimizationGuide);
-  FRIEND_TEST_ALL_PREFIXES(FacilitatedPaymentsManagerTest,
-                           TestShouldDetectPixCode_UrlInAllowlist);
-  FRIEND_TEST_ALL_PREFIXES(FacilitatedPaymentsManagerTest,
-                           TestShouldDetectPixCode_UrlNotInAllowlist);
-  FRIEND_TEST_ALL_PREFIXES(
-      FacilitatedPaymentsManagerTest,
-      TestDidFinishLoad_UrlInAllowlist_PixCodeDetectionTriggered);
-  FRIEND_TEST_ALL_PREFIXES(
-      FacilitatedPaymentsManagerTest,
-      TestDidFinishLoad_UrlNotInAllowlist_PixCodeDetectionNotTriggered);
+                           TestRegisterPixAllowlist);
 
   // Register optimization guide deciders for PIX. It is an allowlist of URLs
   // where we attempt PIX code detection.
-  void RegisterPixOptimizationGuide() const;
+  void RegisterPixAllowlist() const;
 
-  // Returns whether PIX detection should be run on the page by querying the PIX
-  // allowlist. `url` is the page URL.
-  bool ShouldDetectPixCode(const GURL& url) const;
+  // Queries the allowlist for the `url`. The result could be:
+  // 1. In the allowlist
+  // 2. Not in the allowlist
+  // 3. Infra for querying is not ready
+  optimization_guide::OptimizationGuideDecision GetAllowlistCheckResult(
+      const GURL& url) const;
+
+  void TriggerPixCodeDetection();
 
   // Callback to be called after attempting PIX code detection. `pix_code_found`
   // informs whether or not PIX code was found on the page.
@@ -69,6 +79,8 @@
   raw_ptr<optimization_guide::OptimizationGuideDecider>
       optimization_guide_decider_ = nullptr;
 
+  base::OneShotTimer pix_code_detection_triggering_timer_;
+
   base::WeakPtrFactory<FacilitatedPaymentsManager> weak_ptr_factory_{this};
 };
 
diff --git a/components/facilitated_payments/core/browser/facilitated_payments_manager_unittest.cc b/components/facilitated_payments/core/browser/facilitated_payments_manager_unittest.cc
index 358410f..4644c7c 100644
--- a/components/facilitated_payments/core/browser/facilitated_payments_manager_unittest.cc
+++ b/components/facilitated_payments/core/browser/facilitated_payments_manager_unittest.cc
@@ -5,6 +5,7 @@
 #include "components/facilitated_payments/core/browser/facilitated_payments_manager.h"
 
 #include "base/functional/callback.h"
+#include "base/test/task_environment.h"
 #include "components/facilitated_payments/core/browser/facilitated_payments_driver.h"
 #include "components/optimization_guide/core/optimization_guide_decider.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -58,7 +59,13 @@
 
 class FacilitatedPaymentsManagerTest : public testing::Test {
  public:
-  FacilitatedPaymentsManagerTest() {
+  base::test::TaskEnvironment task_environment_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+
+  void SetUp() override {
+    attempt_number_ = 1;
+    allowlist_result_ = optimization_guide::OptimizationGuideDecision::kUnknown;
+    timer_.Stop();
     optimization_guide_decider_ =
         std::make_unique<MockOptimizationGuideDecider>();
     driver_ = std::make_unique<MockFacilitatedPaymentsDriver>(nullptr);
@@ -66,93 +73,253 @@
         driver_.get(), optimization_guide_decider_.get());
   }
 
+  optimization_guide::OptimizationGuideDecision& GetAllowlistCheckResult() {
+    return allowlist_result_;
+  }
+
+  // Sets the allowlist `decision` (true or false).
+  void SetAllowlistDecision(
+      optimization_guide::OptimizationGuideDecision decision) {
+    allowlist_result_ = decision;
+  }
+
+  // Sets allowlist `decision` after `delay`.
+  void SimulateDelayedAllowlistDecision(
+      base::TimeDelta delay,
+      optimization_guide::OptimizationGuideDecision decision) {
+    timer_.Start(
+        FROM_HERE, delay,
+        base::BindOnce(&FacilitatedPaymentsManagerTest::SetAllowlistDecision,
+                       base::Unretained(this), decision));
+  }
+
+  void FastForwardBy(base::TimeDelta duration) {
+    task_environment_.FastForwardBy(duration);
+    task_environment_.RunUntilIdle();
+  }
+
+  // Checks if allowlist decision (true or false) is made. If not,
+  // advances time by `kOptimizationGuideDeciderWaitTime` and checks again,
+  // `kMaxAttemptsForAllowlistCheck` times.
+  void AdvanceTimeToAllowlistDecisionReceivedOrMaxAttemptsReached() {
+    while (allowlist_result_ ==
+               optimization_guide::OptimizationGuideDecision::kUnknown &&
+           attempt_number_ < kMaxAttemptsForAllowlistCheck) {
+      FastForwardBy(kOptimizationGuideDeciderWaitTime);
+      ++attempt_number_;
+    }
+  }
+
+  // Advance to a point in time when PIX code detection should have been
+  // triggered.
+  void AdvanceTimeToPotentiallyTriggerPixCodeDetectionAfterDecision() {
+    // The PIX code detection is triggered at least `kPageLoadWaitTime` after
+    // page load.
+    base::TimeDelta time_to_trigger_pix_detection =
+        std::max(base::Seconds(0),
+                 kPageLoadWaitTime -
+                     (attempt_number_ - 1) * kOptimizationGuideDeciderWaitTime);
+    FastForwardBy(time_to_trigger_pix_detection);
+  }
+
  protected:
-  std::unique_ptr<MockFacilitatedPaymentsDriver> driver_;
+  optimization_guide::OptimizationGuideDecision allowlist_result_;
   std::unique_ptr<MockOptimizationGuideDecider> optimization_guide_decider_;
+  std::unique_ptr<MockFacilitatedPaymentsDriver> driver_;
   std::unique_ptr<FacilitatedPaymentsManager> manager_;
+
+ private:
+  int attempt_number_;  // Number of attempts at checking the allowlist.
+  base::OneShotTimer timer_;
 };
 
 // Test that the `PIX_PAYMENT_MERCHANT_ALLOWLIST` optimization type is
 // registered when RegisterPixOptimizationGuide is called.
-TEST_F(FacilitatedPaymentsManagerTest, TestRegisterPixOptimizationGuide) {
+TEST_F(FacilitatedPaymentsManagerTest, TestRegisterPixAllowlist) {
   EXPECT_CALL(*optimization_guide_decider_,
               RegisterOptimizationTypes(testing::ElementsAre(
                   optimization_guide::proto::PIX_PAYMENT_MERCHANT_ALLOWLIST)))
       .Times(1);
 
-  manager_->RegisterPixOptimizationGuide();
+  manager_->RegisterPixAllowlist();
 }
 
-// Test that `ShouldDetectPixCode` returns true for merchant websites not in the
-// allowlist.
-TEST_F(FacilitatedPaymentsManagerTest, TestShouldDetectPixCode_UrlInAllowlist) {
+// Test that the PIX code detection is triggered for webpages in the allowlist.
+TEST_F(
+    FacilitatedPaymentsManagerTest,
+    TestDelayedCheckAllowlistAndTriggerPixCodeDetection_InAllowlistDecision) {
   GURL url("https://example.com/");
-  ON_CALL(*optimization_guide_decider_,
-          CanApplyOptimization(
-              testing::Eq(url),
-              testing::Eq(
-                  optimization_guide::proto::PIX_PAYMENT_MERCHANT_ALLOWLIST),
-              testing::Matcher<optimization_guide::OptimizationMetadata*>(
-                  testing::Eq(nullptr))))
-      .WillByDefault(testing::Return(
-          optimization_guide::OptimizationGuideDecision::kTrue));
+  SetAllowlistDecision(optimization_guide::OptimizationGuideDecision::kTrue);
 
-  EXPECT_TRUE(manager_->ShouldDetectPixCode(url));
-}
-
-// Test that `ShouldDetectPixCode` returns false for merchant websites not in
-// the allowlist.
-TEST_F(FacilitatedPaymentsManagerTest,
-       TestShouldDetectPixCode_UrlNotInAllowlist) {
-  GURL url("https://example.com/");
-  ON_CALL(*optimization_guide_decider_,
-          CanApplyOptimization(
-              testing::Eq(url),
-              testing::Eq(
-                  optimization_guide::proto::PIX_PAYMENT_MERCHANT_ALLOWLIST),
-              testing::Matcher<optimization_guide::OptimizationMetadata*>(
-                  testing::Eq(nullptr))))
-      .WillByDefault(testing::Return(
-          optimization_guide::OptimizationGuideDecision::kFalse));
-
-  EXPECT_FALSE(manager_->ShouldDetectPixCode(url));
-}
-
-// Test that PIX code detection is triggered for webpages in the allowlist.
-TEST_F(FacilitatedPaymentsManagerTest,
-       TestDidFinishLoad_UrlInAllowlist_PixCodeDetectionTriggered) {
-  GURL url("https://example.com/");
-  ON_CALL(*optimization_guide_decider_,
-          CanApplyOptimization(
-              testing::Eq(url),
-              testing::Eq(
-                  optimization_guide::proto::PIX_PAYMENT_MERCHANT_ALLOWLIST),
-              testing::Matcher<optimization_guide::OptimizationMetadata*>(
-                  testing::Eq(nullptr))))
-      .WillByDefault(testing::Return(
-          optimization_guide::OptimizationGuideDecision::kTrue));
-
+  EXPECT_CALL(
+      *optimization_guide_decider_,
+      CanApplyOptimization(
+          testing::Eq(url),
+          testing::Eq(
+              optimization_guide::proto::PIX_PAYMENT_MERCHANT_ALLOWLIST),
+          testing::Matcher<optimization_guide::OptimizationMetadata*>(
+              testing::Eq(nullptr))))
+      .Times(1)
+      .WillOnce(testing::ReturnPointee(&allowlist_result_));
   EXPECT_CALL(*driver_, TriggerPixCodeDetection).Times(1);
-  manager_->DidFinishLoad(url);
+
+  manager_->DelayedCheckAllowlistAndTriggerPixCodeDetection(url);
+  AdvanceTimeToAllowlistDecisionReceivedOrMaxAttemptsReached();
+  AdvanceTimeToPotentiallyTriggerPixCodeDetectionAfterDecision();
 }
 
-// Test that PIX code detection is not triggered for webpages not in the
+// Test that the PIX code detection is not triggered for webpages not in the
 // allowlist.
-TEST_F(FacilitatedPaymentsManagerTest,
-       TestDidFinishLoad_UrlNotInAllowlist_PixCodeDetectionNotTriggered) {
+TEST_F(
+    FacilitatedPaymentsManagerTest,
+    TestDelayedCheckAllowlistAndTriggerPixCodeDetection_NotInAllowlistDecision) {
   GURL url("https://example.com/");
-  ON_CALL(*optimization_guide_decider_,
-          CanApplyOptimization(
-              testing::Eq(url),
-              testing::Eq(
-                  optimization_guide::proto::PIX_PAYMENT_MERCHANT_ALLOWLIST),
-              testing::Matcher<optimization_guide::OptimizationMetadata*>(
-                  testing::Eq(nullptr))))
-      .WillByDefault(testing::Return(
-          optimization_guide::OptimizationGuideDecision::kFalse));
+  SetAllowlistDecision(optimization_guide::OptimizationGuideDecision::kFalse);
 
+  EXPECT_CALL(
+      *optimization_guide_decider_,
+      CanApplyOptimization(
+          testing::Eq(url),
+          testing::Eq(
+              optimization_guide::proto::PIX_PAYMENT_MERCHANT_ALLOWLIST),
+          testing::Matcher<optimization_guide::OptimizationMetadata*>(
+              testing::Eq(nullptr))))
+      .Times(1)
+      .WillOnce(testing::ReturnPointee(&allowlist_result_));
   EXPECT_CALL(*driver_, TriggerPixCodeDetection).Times(0);
-  manager_->DidFinishLoad(url);
+
+  manager_->DelayedCheckAllowlistAndTriggerPixCodeDetection(url);
+  AdvanceTimeToAllowlistDecisionReceivedOrMaxAttemptsReached();
+  AdvanceTimeToPotentiallyTriggerPixCodeDetectionAfterDecision();
+}
+
+// Test that if the allowlist checking infra is not ready after
+// `kMaxAttemptsForAllowlistCheck` attempts, PIX code detection is not
+// triggered.
+TEST_F(
+    FacilitatedPaymentsManagerTest,
+    TestDelayedCheckAllowlistAndTriggerPixCodeDetection_DecisionDelay_NoDecision) {
+  GURL url("https://example.com/");
+
+  // The default decision is kUnknown.
+  // Allowlist check should be attempted once every
+  // `kOptimizationGuideDeciderWaitTime` until decision is received or
+  // `kMaxAttemptsForAllowlistCheck` attempts are made.
+  EXPECT_CALL(
+      *optimization_guide_decider_,
+      CanApplyOptimization(
+          testing::Eq(url),
+          testing::Eq(
+              optimization_guide::proto::PIX_PAYMENT_MERCHANT_ALLOWLIST),
+          testing::Matcher<optimization_guide::OptimizationMetadata*>(
+              testing::Eq(nullptr))))
+      .Times(kMaxAttemptsForAllowlistCheck)
+      .WillRepeatedly(testing::ReturnPointee(&allowlist_result_));
+  EXPECT_CALL(*driver_, TriggerPixCodeDetection).Times(0);
+
+  manager_->DelayedCheckAllowlistAndTriggerPixCodeDetection(url);
+  AdvanceTimeToAllowlistDecisionReceivedOrMaxAttemptsReached();
+  AdvanceTimeToPotentiallyTriggerPixCodeDetectionAfterDecision();
+}
+
+// Test that the allowlist decision infra is given some time (short) to start-up
+// and make decision.
+TEST_F(
+    FacilitatedPaymentsManagerTest,
+    TestDelayedCheckAllowlistAndTriggerPixCodeDetection_DecisionDelay_InAllowlistDecision) {
+  GURL url("https://example.com/");
+
+  // Simulate that the allowlist checking infra gets ready after 1.5s and
+  // returns positive decision.
+  base::TimeDelta decision_delay = base::Seconds(1.5);
+  SimulateDelayedAllowlistDecision(
+      decision_delay, optimization_guide::OptimizationGuideDecision::kTrue);
+
+  // Allowlist check should be attempted once every
+  // `kOptimizationGuideDeciderWaitTime` until decision is received.
+  EXPECT_CALL(
+      *optimization_guide_decider_,
+      CanApplyOptimization(
+          testing::Eq(url),
+          testing::Eq(
+              optimization_guide::proto::PIX_PAYMENT_MERCHANT_ALLOWLIST),
+          testing::Matcher<optimization_guide::OptimizationMetadata*>(
+              testing::Eq(nullptr))))
+      .Times(decision_delay / kOptimizationGuideDeciderWaitTime + 1)
+      .WillRepeatedly(testing::ReturnPointee(&allowlist_result_));
+  EXPECT_CALL(*driver_, TriggerPixCodeDetection).Times(1);
+
+  manager_->DelayedCheckAllowlistAndTriggerPixCodeDetection(url);
+  AdvanceTimeToAllowlistDecisionReceivedOrMaxAttemptsReached();
+  AdvanceTimeToPotentiallyTriggerPixCodeDetectionAfterDecision();
+}
+
+// Test that the allowlist decision infra is given some time (short) to start-up
+// and make decision.
+TEST_F(
+    FacilitatedPaymentsManagerTest,
+    TestDelayedCheckAllowlistAndTriggerPixCodeDetection_DecisionDelay_NotInAllowlistDecision) {
+  GURL url("https://example.com/");
+
+  // Simulate that the allowlist checking infra gets ready after 1.5s and
+  // returns negative decision.
+  base::TimeDelta decision_delay = base::Seconds(1.5);
+  SimulateDelayedAllowlistDecision(
+      decision_delay, optimization_guide::OptimizationGuideDecision::kFalse);
+
+  // Allowlist check should be attempted once every
+  // `kOptimizationGuideDeciderWaitTime` until decision is received.
+  EXPECT_CALL(
+      *optimization_guide_decider_,
+      CanApplyOptimization(
+          testing::Eq(url),
+          testing::Eq(
+              optimization_guide::proto::PIX_PAYMENT_MERCHANT_ALLOWLIST),
+          testing::Matcher<optimization_guide::OptimizationMetadata*>(
+              testing::Eq(nullptr))))
+      .Times(decision_delay / kOptimizationGuideDeciderWaitTime + 1)
+      .WillRepeatedly(testing::ReturnPointee(&allowlist_result_));
+  EXPECT_CALL(*driver_, TriggerPixCodeDetection).Times(0);
+
+  manager_->DelayedCheckAllowlistAndTriggerPixCodeDetection(url);
+  AdvanceTimeToAllowlistDecisionReceivedOrMaxAttemptsReached();
+  AdvanceTimeToPotentiallyTriggerPixCodeDetectionAfterDecision();
+}
+
+// Test that the allowlist decision infra is given some time (short) to start-up
+// and make decision. If the infra does not get ready within the given time,
+// then PIX code detection is not run even if the infra eventually returns a
+// decision.
+TEST_F(
+    FacilitatedPaymentsManagerTest,
+    TestDelayedCheckAllowlistAndTriggerPixCodeDetection_DecisionDelay_LongDelay_InAllowlistDecision) {
+  GURL url("https://example.com/");
+
+  // Simulate that the allowlist checking infra gets ready after 3.5s and
+  // returns positive decision.
+  base::TimeDelta decision_delay = base::Seconds(3.5);
+  SimulateDelayedAllowlistDecision(
+      decision_delay, optimization_guide::OptimizationGuideDecision::kTrue);
+
+  // The default decision is kUnknown.
+  // Allowlist check should be attempted once every
+  // `kOptimizationGuideDeciderWaitTime` until decision is received or
+  // `kMaxAttemptsForAllowlistCheck` attempts are made.
+  EXPECT_CALL(
+      *optimization_guide_decider_,
+      CanApplyOptimization(
+          testing::Eq(url),
+          testing::Eq(
+              optimization_guide::proto::PIX_PAYMENT_MERCHANT_ALLOWLIST),
+          testing::Matcher<optimization_guide::OptimizationMetadata*>(
+              testing::Eq(nullptr))))
+      .Times(kMaxAttemptsForAllowlistCheck)
+      .WillRepeatedly(testing::ReturnPointee(&allowlist_result_));
+  EXPECT_CALL(*driver_, TriggerPixCodeDetection).Times(0);
+
+  manager_->DelayedCheckAllowlistAndTriggerPixCodeDetection(url);
+  AdvanceTimeToAllowlistDecisionReceivedOrMaxAttemptsReached();
+  AdvanceTimeToPotentiallyTriggerPixCodeDetectionAfterDecision();
 }
 
 }  // namespace payments::facilitated
diff --git a/components/feed/core/v2/metrics_reporter.cc b/components/feed/core/v2/metrics_reporter.cc
index f17649f..26398d0 100644
--- a/components/feed/core/v2/metrics_reporter.cc
+++ b/components/feed/core/v2/metrics_reporter.cc
@@ -308,12 +308,6 @@
   base::UmaHistogramSparse(
       "ContentSuggestions.Feed.AllFeeds.FollowCount.Engaged2",
       subscription_count);
-  // TODO(b/228342051): The histogram below is being obsoleted because it has a
-  // misleading name. Once the new *.Engaged2 series collects a large enough
-  // sample history, it will be effectively removed/obsoleted.
-  base::UmaHistogramSparse(
-      "ContentSuggestions.Feed.WebFeed.FollowCount.Engaged",
-      subscription_count);
 }
 
 bool IsGoodExplicitInteraction(FeedUserActionType action) {
diff --git a/components/feed/core/v2/metrics_reporter_unittest.cc b/components/feed/core/v2/metrics_reporter_unittest.cc
index 9fa9a48..2e79e7d6 100644
--- a/components/feed/core/v2/metrics_reporter_unittest.cc
+++ b/components/feed/core/v2/metrics_reporter_unittest.cc
@@ -177,8 +177,6 @@
   histogram_.ExpectTotalCount(
       "ContentSuggestions.Feed.AllFeeds.FollowCount.Engaged2", 0);
   histogram_.ExpectTotalCount(
-      "ContentSuggestions.Feed.WebFeed.FollowCount.Engaged", 0);
-  histogram_.ExpectTotalCount(
       "ContentSuggestions.Feed.WebFeed.SortTypeWhenEngaged", 0);
 }
 
@@ -200,9 +198,6 @@
       "ContentSuggestions.Feed.AllFeeds.FollowCount.Engaged2",
       kSubscriptionCount, 1);
   histogram_.ExpectUniqueSample(
-      "ContentSuggestions.Feed.WebFeed.FollowCount.Engaged", kSubscriptionCount,
-      1);
-  histogram_.ExpectUniqueSample(
       "ContentSuggestions.Feed.WebFeed.SortTypeWhenEngaged",
       test_content_order_, 0);
 }
@@ -227,9 +222,6 @@
       "ContentSuggestions.Feed.AllFeeds.FollowCount.Engaged2",
       kSubscriptionCount, 1);
   histogram_.ExpectUniqueSample(
-      "ContentSuggestions.Feed.WebFeed.FollowCount.Engaged", kSubscriptionCount,
-      1);
-  histogram_.ExpectUniqueSample(
       "ContentSuggestions.Feed.WebFeed.SortTypeWhenEngaged",
       test_content_order_, 1);
 }
@@ -356,9 +348,6 @@
       "ContentSuggestions.Feed.AllFeeds.FollowCount.Engaged2",
       kSubscriptionCount, 1);
   histogram_.ExpectUniqueSample(
-      "ContentSuggestions.Feed.WebFeed.FollowCount.Engaged", kSubscriptionCount,
-      1);
-  histogram_.ExpectUniqueSample(
       "ContentSuggestions.Feed.WebFeed.SortTypeWhenEngaged",
       test_content_order_, 1);
 
@@ -393,9 +382,6 @@
       "ContentSuggestions.Feed.AllFeeds.FollowCount.Engaged2",
       kSubscriptionCount, 2);
   histogram_.ExpectUniqueSample(
-      "ContentSuggestions.Feed.WebFeed.FollowCount.Engaged", kSubscriptionCount,
-      2);
-  histogram_.ExpectUniqueSample(
       "ContentSuggestions.Feed.WebFeed.SortTypeWhenEngaged",
       test_content_order_, 1);
 }
@@ -672,9 +658,6 @@
       "ContentSuggestions.Feed.AllFeeds.FollowCount.Engaged2",
       kSubscriptionCount, 1);
   histogram_.ExpectUniqueSample(
-      "ContentSuggestions.Feed.WebFeed.FollowCount.Engaged", kSubscriptionCount,
-      1);
-  histogram_.ExpectUniqueSample(
       "ContentSuggestions.Feed.WebFeed.SortTypeWhenEngaged",
       test_content_order_, 0);
 }
@@ -704,9 +687,6 @@
       "ContentSuggestions.Feed.AllFeeds.FollowCount.Engaged2",
       kSubscriptionCount, 1);
   histogram_.ExpectUniqueSample(
-      "ContentSuggestions.Feed.WebFeed.FollowCount.Engaged", kSubscriptionCount,
-      1);
-  histogram_.ExpectUniqueSample(
       "ContentSuggestions.Feed.WebFeed.SortTypeWhenEngaged",
       test_content_order_, 1);
 }
diff --git a/components/optimization_guide/core/optimization_guide_store.h b/components/optimization_guide/core/optimization_guide_store.h
index fe7d828..126cb37a 100644
--- a/components/optimization_guide/core/optimization_guide_store.h
+++ b/components/optimization_guide/core/optimization_guide_store.h
@@ -378,7 +378,7 @@
   scoped_refptr<base::SequencedTaskRunner> store_task_runner_;
 
   // Pref service. Not owned. Guaranteed to outlive |this|.
-  raw_ptr<PrefService, DanglingUntriaged> pref_service_;
+  raw_ptr<PrefService> pref_service_;
 
   SEQUENCE_CHECKER(sequence_checker_);
 
diff --git a/components/optimization_guide/core/optimization_guide_store_unittest.cc b/components/optimization_guide/core/optimization_guide_store_unittest.cc
index 6f5fb3e..5e34afe 100644
--- a/components/optimization_guide/core/optimization_guide_store_unittest.cc
+++ b/components/optimization_guide/core/optimization_guide_store_unittest.cc
@@ -75,7 +75,6 @@
 
   void TearDown() override {
     last_loaded_hint_.reset();
-    pref_service_.reset();
   }
 
   // Initializes the entries contained within the database on startup.
diff --git a/components/optimization_guide/core/prediction_manager.cc b/components/optimization_guide/core/prediction_manager.cc
index b4a2abf..068280d6f 100644
--- a/components/optimization_guide/core/prediction_manager.cc
+++ b/components/optimization_guide/core/prediction_manager.cc
@@ -183,7 +183,6 @@
       prediction_model_store_(prediction_model_store),
       url_loader_factory_(url_loader_factory),
       optimization_guide_logger_(optimization_guide_logger),
-      pref_service_(pref_service),
       component_updates_enabled_provider_(component_updates_enabled_provider),
       prediction_model_fetch_timer_(
           pref_service,
diff --git a/components/optimization_guide/core/prediction_manager.h b/components/optimization_guide/core/prediction_manager.h
index f8260f1..793eb9e 100644
--- a/components/optimization_guide/core/prediction_manager.h
+++ b/components/optimization_guide/core/prediction_manager.h
@@ -337,9 +337,6 @@
   // and |this| are owned by the optimization guide keyed service.
   raw_ptr<OptimizationGuideLogger> optimization_guide_logger_;
 
-  // A reference to the PrefService for this profile. Not owned.
-  raw_ptr<PrefService, DanglingUntriaged> pref_service_ = nullptr;
-
   // The repeating callback that will be used to determine if component updates
   // are enabled.
   ComponentUpdatesEnabledProvider component_updates_enabled_provider_;
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal
index a1431631..30306f8 160000
--- a/components/optimization_guide/internal
+++ b/components/optimization_guide/internal
@@ -1 +1 @@
-Subproject commit a1431631ca51a2ed211beb9b2438e260fed5143d
+Subproject commit 30306f842234b68abc5fe490db53226b5cf9789c
diff --git a/components/pdf/renderer/pdf_accessibility_tree.cc b/components/pdf/renderer/pdf_accessibility_tree.cc
index ecd04d21..2cc1ddb 100644
--- a/components/pdf/renderer/pdf_accessibility_tree.cc
+++ b/components/pdf/renderer/pdf_accessibility_tree.cc
@@ -2366,13 +2366,6 @@
 }
 
 void PdfAccessibilityTree::AccessibilityModeChanged(const ui::AXMode& mode) {
-  if (!mode.has_mode(ui::AXMode::kPDF)) {
-    if (GetRenderAccessibility()) {
-      GetRenderAccessibility()->SetPluginTreeSource(nullptr);
-    }
-    return;
-  }
-
 #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
   if (!mode.has_mode(ui::AXMode::kPDFOcr)) {
     if (ocr_service_) {
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
index 0b51355..3f7ddb4b 100644
--- a/components/printing/renderer/print_render_frame_helper.cc
+++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -1680,7 +1680,8 @@
   // the scope of printing, because text drawing commands are only annotated
   // with a DOMNodeId if accessibility is enabled.
   if (delegate_->ShouldGenerateTaggedPDF())
-    snapshotter_ = render_frame()->CreateAXTreeSnapshotter(ui::AXMode::kPDF);
+    snapshotter_ =
+        render_frame()->CreateAXTreeSnapshotter(ui::AXMode::kPDFPrinting);
 
   mojom::PageSizeMarginsPtr default_page_layout =
       ComputePageLayoutForCss(print_preview_context_.prepared_frame(), 0,
@@ -2223,7 +2224,8 @@
   std::unique_ptr<content::AXTreeSnapshotter> snapshotter;
   ui::AXTreeUpdate accessibility_tree;
   if (generate_tagged_pdf) {
-    snapshotter = render_frame()->CreateAXTreeSnapshotter(ui::AXMode::kPDF);
+    snapshotter =
+        render_frame()->CreateAXTreeSnapshotter(ui::AXMode::kPDFPrinting);
     snapshotter->Snapshot(
         /*max_node_count=*/0,
         /*timeout=*/{},
diff --git a/components/safe_browsing/core/common/features.cc b/components/safe_browsing/core/common/features.cc
index 7e11244..3062507 100644
--- a/components/safe_browsing/core/common/features.cc
+++ b/components/safe_browsing/core/common/features.cc
@@ -124,6 +124,10 @@
              "TailoredSecurityLogAccountEnhancedProtectionStateInProtegoPings",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kMaldocaSkipCheck,
+             "MaldocaSkipCheck",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kMmapSafeBrowsingDatabase,
              "MmapSafeBrowsingDatabase",
 // TODO(crbug.com/1380507): Fix iOS tests with this enabled.
@@ -263,8 +267,7 @@
 
 BASE_FEATURE(kTailoredSecurityIntegration,
              "TailoredSecurityIntegration",
-             base::FEATURE_ENABLED_BY_DEFAULT
-);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 BASE_FEATURE(kTailoredSecurityUpdatedMessages,
              "TailoredSecurityUpdatedMessages",
diff --git a/components/safe_browsing/core/common/features.h b/components/safe_browsing/core/common/features.h
index c9cd78f..fbbe0cd5 100644
--- a/components/safe_browsing/core/common/features.h
+++ b/components/safe_browsing/core/common/features.h
@@ -108,6 +108,9 @@
 // Enable logging of the account enhanced protection setting in Protego pings.
 BASE_DECLARE_FEATURE(kLogAccountEnhancedProtectionStateInProtegoPings);
 
+// If enabled, do not run Maldoca over downloaded office documents.
+BASE_DECLARE_FEATURE(kMaldocaSkipCheck);
+
 // If enabled, the Safe Browsing database will be stored in a separate file and
 // mapped into memory.
 BASE_DECLARE_FEATURE(kMmapSafeBrowsingDatabase);
diff --git a/components/search/ntp_features.cc b/components/search/ntp_features.cc
index ac12a35..02c07889 100644
--- a/components/search/ntp_features.cc
+++ b/components/search/ntp_features.cc
@@ -396,6 +396,10 @@
              "NtpTabResumptionModule",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kNtpTabResumptionModuleCategories,
+             "NtpTabResumptionModuleCategories",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 const char kNtpModuleIgnoredCriteriaThreshold[] =
     "NtpModuleIgnoredCriteriaThreshold";
 const char kNtpModuleIgnoredHaTSDelayTimeParam[] =
@@ -467,6 +471,8 @@
 const char kNtpHistoryClustersModuleScoreThresholdParam[] =
     "NtpHistoryClustersModuleScoreThresholdParam";
 const char kNtpRealboxWidthBehaviorParam[] = "NtpRealboxWidthBehaviorParam";
+const char kNtpTabResumptionModuleCategoriesBlocklistParam[] =
+    "NtpTabResumptionModuleCategoriesBlocklistParam";
 const char kNtpTabResumptionModuleDataParam[] =
     "NtpTabResumptionModuleDataParam";
 const char kNtpTabResumptionModuleVisibilityThresholdDataParam[] =
diff --git a/components/search/ntp_features.h b/components/search/ntp_features.h
index e317d357..410d9bf 100644
--- a/components/search/ntp_features.h
+++ b/components/search/ntp_features.h
@@ -95,6 +95,7 @@
 BASE_DECLARE_FEATURE(kNtpHistoryClustersModuleIncludeSyncedVisits);
 BASE_DECLARE_FEATURE(kNtpHistoryClustersModuleEnableContentClustering);
 BASE_DECLARE_FEATURE(kNtpTabResumptionModule);
+BASE_DECLARE_FEATURE(kNtpTabResumptionModuleCategories);
 
 // Parameter for controlling the luminosity difference for NTP elements on light
 // backgrounds.
@@ -203,6 +204,9 @@
 extern const char kNtpHistoryClustersModuleRankingMetricsQueryDaysParam[];
 extern const char kNtpHistoryClustersModuleScoreThresholdParam[];
 extern const char kNtpRealboxWidthBehaviorParam[];
+// Parameter for determining the categories a tab must not fall into
+// to be shown.
+extern const char kNtpTabResumptionModuleCategoriesBlocklistParam[];
 extern const char kNtpTabResumptionModuleDataParam[];
 extern const char kNtpTabResumptionModuleVisibilityThresholdDataParam[];
 // Parameter determining the trigger delay of the Wallpaper Search HaTS survey.
diff --git a/components/services/storage/privileged/mojom/indexed_db_control.mojom b/components/services/storage/privileged/mojom/indexed_db_control.mojom
index f0f6cd4..ca50852 100644
--- a/components/services/storage/privileged/mojom/indexed_db_control.mojom
+++ b/components/services/storage/privileged/mojom/indexed_db_control.mojom
@@ -24,7 +24,7 @@
   FORCE_CLOSE_BACKING_STORE_FAILURE = 1,
   FORCE_CLOSE_INTERNALS_PAGE = 2,
   FORCE_CLOSE_COPY_ORIGIN = 3,
-  FORCE_SCHEMA_DOWNGRADE_INTERNALS_PAGE = 4,
+  // Deprecated: FORCE_SCHEMA_DOWNGRADE_INTERNALS_PAGE = 4,
   // Append new values here and update IDBContextForcedCloseReason in
   // enums.xml.
 };
diff --git a/components/services/storage/privileged/mojom/indexed_db_control_test.mojom b/components/services/storage/privileged/mojom/indexed_db_control_test.mojom
index 2a62a0c..45bf9cc1 100644
--- a/components/services/storage/privileged/mojom/indexed_db_control_test.mojom
+++ b/components/services/storage/privileged/mojom/indexed_db_control_test.mojom
@@ -7,12 +7,6 @@
 import "components/services/storage/public/mojom/buckets/bucket_locator.mojom";
 import "mojo/public/mojom/base/file_path.mojom";
 
-enum V2SchemaCorruptionStatus {
-  CORRUPTION_UNKNOWN,
-  CORRUPTION_NO,
-  CORRUPTION_YES,
-};
-
 enum FailClass {
   NOTHING,
   LEVELDB_ITERATOR,
@@ -50,14 +44,6 @@
   // Forgets the storage keys and sizes read from disk.
   ResetCachesForTesting() => ();
 
-  // Downgrades databases to V2.
-  ForceSchemaDowngradeForTesting(storage.mojom.BucketLocator bucket_locator) =>
-    (bool downgraded);
-
-  // Returns the corruption status for a given database.
-  HasV2SchemaCorruptionForTesting(storage.mojom.BucketLocator bucket_locator) =>
-      (V2SchemaCorruptionStatus status);
-
   // Does a direct write to a database with a given key/value pair.
   WriteToIndexedDBForTesting(storage.mojom.BucketLocator bucket_locator,
                              string key, string value) => ();
diff --git a/components/signin/public/base/signin_metrics.cc b/components/signin/public/base/signin_metrics.cc
index 3500222..d92c180 100644
--- a/components/signin/public/base/signin_metrics.cc
+++ b/components/signin/public/base/signin_metrics.cc
@@ -488,6 +488,10 @@
       base::RecordAction(
           base::UserMetricsAction("Signin_Signin_FromTabOrganization"));
       break;
+    case AccessPoint::ACCESS_POINT_TIPS_NOTIFICATION:
+      base::RecordAction(
+          base::UserMetricsAction("Signin_Signin_FromTipsNotification"));
+      break;
     case AccessPoint::ACCESS_POINT_MAX:
       NOTREACHED();
       break;
@@ -622,6 +626,10 @@
       base::RecordAction(base::UserMetricsAction(
           "Signin_Impression_FromChromeSigninInterceptBubble"));
       break;
+    case AccessPoint::ACCESS_POINT_TIPS_NOTIFICATION:
+      base::RecordAction(
+          base::UserMetricsAction("Signin_Impression_FromTipsNotification"));
+      break;
     case AccessPoint::ACCESS_POINT_ENTERPRISE_SIGNOUT_COORDINATOR:
     case AccessPoint::ACCESS_POINT_EXTENSIONS:
     case AccessPoint::ACCESS_POINT_SUPERVISED_USER:
diff --git a/components/signin/public/base/signin_metrics.h b/components/signin/public/base/signin_metrics.h
index ffa89b9..63c03e4 100644
--- a/components/signin/public/base/signin_metrics.h
+++ b/components/signin/public/base/signin_metrics.h
@@ -194,6 +194,8 @@
   ACCESS_POINT_TAB_ORGANIZATION = 56,
   // Access point for the Save to Drive feature on iOS.
   ACCESS_POINT_SAVE_TO_DRIVE_IOS = 57,
+  // Access point for the Tips Notification on iOS.
+  ACCESS_POINT_TIPS_NOTIFICATION = 58,
 
   // Add values above this line with a corresponding label to the
   // "SigninAccessPoint" enum in tools/metrics/histograms/enums.xml
diff --git a/components/signin/public/base/signin_metrics_unittest.cc b/components/signin/public/base/signin_metrics_unittest.cc
index 237d4f6..2829779 100644
--- a/components/signin/public/base/signin_metrics_unittest.cc
+++ b/components/signin/public/base/signin_metrics_unittest.cc
@@ -186,6 +186,8 @@
         return "RestorePrimaryAccountinfoOnProfileLoad";
       case AccessPoint::ACCESS_POINT_TAB_ORGANIZATION:
         return "TabOrganization";
+      case AccessPoint::ACCESS_POINT_TIPS_NOTIFICATION:
+        return "TipsNotification";
       case AccessPoint::ACCESS_POINT_MAX:
         NOTREACHED();
         return "";
diff --git a/components/sync/base/features.cc b/components/sync/base/features.cc
index a548ab05..5c7451f 100644
--- a/components/sync/base/features.cc
+++ b/components/sync/base/features.cc
@@ -243,4 +243,10 @@
              "SyncRememberCustomPassphraseAfterSignout",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+#if BUILDFLAG(IS_ANDROID)
+BASE_FEATURE(kWebApkBackupAndRestoreBackend,
+             "WebApkBackupAndRestoreBackend",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+#endif  // BUILDFLAG(IS_ANDROID)
+
 }  // namespace syncer
diff --git a/components/sync/base/features.h b/components/sync/base/features.h
index 9eb050d..9c63c21 100644
--- a/components/sync/base/features.h
+++ b/components/sync/base/features.h
@@ -233,6 +233,11 @@
 // it is cleared on sign-out.
 BASE_DECLARE_FEATURE(kSyncRememberCustomPassphraseAfterSignout);
 
+#if BUILDFLAG(IS_ANDROID)
+// If enabled, WebAPK data will be synced for Backup&Restore purposes.
+BASE_DECLARE_FEATURE(kWebApkBackupAndRestoreBackend);
+#endif  // BUILDFLAG(IS_ANDROID)
+
 }  // namespace syncer
 
 #endif  // COMPONENTS_SYNC_BASE_FEATURES_H_
diff --git a/components/system_cpu/BUILD.gn b/components/system_cpu/BUILD.gn
index f4c8c8d..dd7e851 100644
--- a/components/system_cpu/BUILD.gn
+++ b/components/system_cpu/BUILD.gn
@@ -8,7 +8,7 @@
   sources = [
     "cpu_probe.cc",
     "cpu_probe.h",
-    "pressure_sample.h",
+    "cpu_sample.h",
   ]
 
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
diff --git a/components/system_cpu/cpu_probe.cc b/components/system_cpu/cpu_probe.cc
index 32f674a..4c9bdb9c 100644
--- a/components/system_cpu/cpu_probe.cc
+++ b/components/system_cpu/cpu_probe.cc
@@ -54,19 +54,19 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Don't check `got_probe_baseline_` until the result is received since it
   // will be set asynchronously.
-  Update(base::BindOnce(&CpuProbe::OnPressureSampleAvailable, GetWeakPtr(),
+  Update(base::BindOnce(&CpuProbe::OnSampleAvailable, GetWeakPtr(),
                         std::move(callback)));
 }
 
 void CpuProbe::OnSamplingStarted(base::OnceClosure started_callback,
-                                 std::optional<PressureSample>) {
+                                 std::optional<CpuSample>) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   got_probe_baseline_ = true;
   std::move(started_callback).Run();
 }
 
-void CpuProbe::OnPressureSampleAvailable(SampleCallback callback,
-                                         std::optional<PressureSample> sample) {
+void CpuProbe::OnSampleAvailable(SampleCallback callback,
+                                 std::optional<CpuSample> sample) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   CHECK_EQ(got_probe_baseline_, true);
diff --git a/components/system_cpu/cpu_probe.h b/components/system_cpu/cpu_probe.h
index 5f81bf5d..e92f12d0 100644
--- a/components/system_cpu/cpu_probe.h
+++ b/components/system_cpu/cpu_probe.h
@@ -13,7 +13,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "base/thread_annotations.h"
-#include "components/system_cpu/pressure_sample.h"
+#include "components/system_cpu/cpu_sample.h"
 
 namespace system_cpu {
 
@@ -36,8 +36,7 @@
 // Instances are not thread-safe and should be used on the same sequence.
 class CpuProbe {
  public:
-  using SampleCallback =
-      base::OnceCallback<void(std::optional<PressureSample>)>;
+  using SampleCallback = base::OnceCallback<void(std::optional<CpuSample>)>;
 
   // Instantiates the CpuProbe subclass most suitable for the current platform.
   //
@@ -78,20 +77,20 @@
  private:
   // Called with the result of an Update() triggered by StartSampling(). Will do
   // some bookkeeping and then call `started_callback`, ignoring the
-  // PressureSample.
+  // CpuSample.
   void OnSamplingStarted(base::OnceClosure started_callback,
-                         std::optional<PressureSample>);
+                         std::optional<CpuSample>);
 
   // Called with the result of an Update() triggered by RequestSample(). Will do
   // some bookkeeping and then pass `sample` to `callback`.
-  void OnPressureSampleAvailable(SampleCallback callback,
-                                 std::optional<PressureSample> sample);
+  void OnSampleAvailable(SampleCallback callback,
+                         std::optional<CpuSample> sample);
 
   // True if the CpuProbe state will be reported after the next update.
   //
-  // The PressureSample reported by many CpuProbe implementations relies
+  // The CpuSample reported by many CpuProbe implementations relies
   // on the differences observed between two Update() calls. For this reason,
-  // the PressureSample reported after a first Update() call is not
+  // the CpuSample reported after a first Update() call is not
   // reported via the SampleCallback.
   bool got_probe_baseline_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
 };
diff --git a/components/system_cpu/cpu_probe_linux.cc b/components/system_cpu/cpu_probe_linux.cc
index e4685843..ec0a92e 100644
--- a/components/system_cpu/cpu_probe_linux.cc
+++ b/components/system_cpu/cpu_probe_linux.cc
@@ -18,7 +18,7 @@
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "components/system_cpu/core_times.h"
-#include "components/system_cpu/pressure_sample.h"
+#include "components/system_cpu/cpu_sample.h"
 #include "components/system_cpu/procfs_stat_cpu_parser.h"
 
 namespace system_cpu {
@@ -34,7 +34,7 @@
   BlockingTaskRunnerHelper(const BlockingTaskRunnerHelper&) = delete;
   BlockingTaskRunnerHelper& operator=(const BlockingTaskRunnerHelper&) = delete;
 
-  std::optional<PressureSample> Update();
+  std::optional<CpuSample> Update();
 
  private:
   // Called when a core is seen the first time in /proc/stat.
@@ -61,8 +61,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
-std::optional<PressureSample>
-CpuProbeLinux::BlockingTaskRunnerHelper::Update() {
+std::optional<CpuSample> CpuProbeLinux::BlockingTaskRunnerHelper::Update() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!stat_parser_.Update()) {
@@ -96,8 +95,7 @@
   }
 
   if (utilization_cores > 0) {
-    return PressureSample{.cpu_utilization =
-                              utilization_sum / utilization_cores};
+    return CpuSample{.cpu_utilization = utilization_sum / utilization_cores};
   } else {
     return std::nullopt;
   }
diff --git a/components/system_cpu/cpu_probe_linux_unittest.cc b/components/system_cpu/cpu_probe_linux_unittest.cc
index 1ab97b6d..a478b6b 100644
--- a/components/system_cpu/cpu_probe_linux_unittest.cc
+++ b/components/system_cpu/cpu_probe_linux_unittest.cc
@@ -16,7 +16,7 @@
 #include "base/test/test_timeouts.h"
 #include "base/threading/platform_thread.h"
 #include "components/system_cpu/cpu_probe.h"
-#include "components/system_cpu/pressure_sample.h"
+#include "components/system_cpu/cpu_sample.h"
 #include "components/system_cpu/pressure_test_support.h"
 #include "components/system_cpu/procfs_stat_cpu_parser.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -71,7 +71,7 @@
 
   base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
 
-  std::optional<PressureSample> sample = probe_->UpdateAndWaitForSample();
+  std::optional<CpuSample> sample = probe_->UpdateAndWaitForSample();
   ASSERT_TRUE(sample.has_value());
   EXPECT_GE(sample->cpu_utilization, 0.0);
   EXPECT_LE(sample->cpu_utilization, 1.0);
@@ -105,7 +105,7 @@
 procs_blocked 600
 softirq 900 901 902 903 904 905 906 907 908 909 910
 )"));
-  std::optional<PressureSample> sample = probe_->UpdateAndWaitForSample();
+  std::optional<CpuSample> sample = probe_->UpdateAndWaitForSample();
   ASSERT_TRUE(sample.has_value());
   EXPECT_EQ(sample->cpu_utilization, 0.25);
 }
@@ -124,7 +124,7 @@
 cpu 0 0 0 0 0 0 0 0 0 0
 cpu0 100 0 0 300 0 0 0 0 0 0
 )"));
-  std::optional<PressureSample> sample = probe_->UpdateAndWaitForSample();
+  std::optional<CpuSample> sample = probe_->UpdateAndWaitForSample();
   ASSERT_TRUE(sample.has_value());
   EXPECT_EQ(sample->cpu_utilization, 0.25);
 
@@ -135,7 +135,7 @@
 cpu 0 0 0 0 0 0 0 0 0 0
 cpu0 200 100 0 500 0 0 0 0 0 0
 )"));
-  std::optional<PressureSample> sample2 = probe_->UpdateAndWaitForSample();
+  std::optional<CpuSample> sample2 = probe_->UpdateAndWaitForSample();
   ASSERT_TRUE(sample2.has_value());
   EXPECT_EQ(sample2->cpu_utilization, 0.5);
 }
@@ -173,7 +173,7 @@
 procs_blocked 600
 softirq 900 901 902 903 904 905 906 907 908 909 910
 )"));
-  std::optional<PressureSample> sample = probe_->UpdateAndWaitForSample();
+  std::optional<CpuSample> sample = probe_->UpdateAndWaitForSample();
   ASSERT_TRUE(sample.has_value());
   EXPECT_EQ(sample->cpu_utilization, 0.375);
 }
@@ -197,7 +197,7 @@
 cpu0 110 20 0 330 0 0 0 0 0 0
 cpu1 140 150 0 260 0 0 0 0 0 0
 )"));
-  std::optional<PressureSample> sample = probe_->UpdateAndWaitForSample();
+  std::optional<CpuSample> sample = probe_->UpdateAndWaitForSample();
   ASSERT_TRUE(sample.has_value());
   EXPECT_EQ(sample->cpu_utilization, 0.375);
 }
@@ -224,7 +224,7 @@
 cpu 0 0 0 0 0 0 0 0 0 0
 cpu0 110 20 0 330 0 0 0 0 0 0
 )"));
-  std::optional<PressureSample> sample = probe_->UpdateAndWaitForSample();
+  std::optional<CpuSample> sample = probe_->UpdateAndWaitForSample();
   ASSERT_TRUE(sample.has_value());
   EXPECT_EQ(sample->cpu_utilization, 0.25);
 
@@ -239,7 +239,7 @@
 cpu0 210 20 0 630 0 0 0 0 0 0
 cpu1 140 150 0 260 0 0 0 0 0 0
 )"));
-  std::optional<PressureSample> sample2 = probe_->UpdateAndWaitForSample();
+  std::optional<CpuSample> sample2 = probe_->UpdateAndWaitForSample();
   ASSERT_TRUE(sample2.has_value());
   EXPECT_EQ(sample2->cpu_utilization, 0.375);
 }
@@ -263,7 +263,7 @@
 cpu0 110 20 0 330 0 0 0 0 0 0
 cpu1 100 100 0 200 0 0 0 0 0 0
 )"));
-  std::optional<PressureSample> sample = probe_->UpdateAndWaitForSample();
+  std::optional<CpuSample> sample = probe_->UpdateAndWaitForSample();
   ASSERT_TRUE(sample.has_value());
   EXPECT_EQ(sample->cpu_utilization, 0.25);
 
@@ -278,7 +278,7 @@
 cpu0 210 120 0 530 0 0 0 0 0 0
 cpu1 200 100 0 500 0 0 0 0 0 0
 )"));
-  std::optional<PressureSample> sample2 = probe_->UpdateAndWaitForSample();
+  std::optional<CpuSample> sample2 = probe_->UpdateAndWaitForSample();
   ASSERT_TRUE(sample2.has_value());
   EXPECT_EQ(sample2->cpu_utilization, 0.375);
 }
@@ -304,7 +304,7 @@
 cpu 0 0 0 0 0 0 0 0 0 0
 cpu0 200 0 0 600 0 0 0 0 0 0
 )"));
-  std::optional<PressureSample> sample = probe_->UpdateAndWaitForSample();
+  std::optional<CpuSample> sample = probe_->UpdateAndWaitForSample();
   ASSERT_TRUE(sample.has_value());
   EXPECT_EQ(sample->cpu_utilization, 0.25);
 }
@@ -330,7 +330,7 @@
 cpu 0 0 0 0 0 0 0 0 0 0
 cpu0 110 120 0 230 0 0 0 0 0 0
 )"));
-  std::optional<PressureSample> sample2 = probe_->UpdateAndWaitForSample();
+  std::optional<CpuSample> sample2 = probe_->UpdateAndWaitForSample();
   ASSERT_TRUE(sample2.has_value());
   EXPECT_EQ(sample2->cpu_utilization, 0.5);
 }
@@ -351,7 +351,7 @@
 cpu0 10 20 0 130 0 0 0 0 0 0
 cpu1 140 50 0 60 0 0 0 0 0 0
 )"));
-  std::optional<PressureSample> sample = probe_->UpdateAndWaitForSample();
+  std::optional<CpuSample> sample = probe_->UpdateAndWaitForSample();
   ASSERT_TRUE(sample.has_value());
   EXPECT_EQ(sample->cpu_utilization, 0.5);
 
@@ -362,7 +362,7 @@
 cpu0 10 20 0 230 0 0 0 0 0 0
 cpu1 140 50 0 60 0 0 0 0 0 0
 )"));
-  std::optional<PressureSample> sample2 = probe_->UpdateAndWaitForSample();
+  std::optional<CpuSample> sample2 = probe_->UpdateAndWaitForSample();
   ASSERT_TRUE(sample2.has_value());
   EXPECT_EQ(sample2->cpu_utilization, 0.0);
 
@@ -384,7 +384,7 @@
 cpu0 110 10 0 530 0 0 0 0 0 0
 cpu1 130 40 0 50 0 0 0 0 0 0
 )"));
-  std::optional<PressureSample> sample3 = probe_->UpdateAndWaitForSample();
+  std::optional<CpuSample> sample3 = probe_->UpdateAndWaitForSample();
   ASSERT_TRUE(sample3.has_value());
   EXPECT_EQ(sample3->cpu_utilization, 0.25);
 }
diff --git a/components/system_cpu/cpu_probe_mac.cc b/components/system_cpu/cpu_probe_mac.cc
index af8f0d03..3e73774d 100644
--- a/components/system_cpu/cpu_probe_mac.cc
+++ b/components/system_cpu/cpu_probe_mac.cc
@@ -18,8 +18,8 @@
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "components/system_cpu/core_times.h"
+#include "components/system_cpu/cpu_sample.h"
 #include "components/system_cpu/host_processor_info_scanner.h"
-#include "components/system_cpu/pressure_sample.h"
 
 namespace system_cpu {
 
@@ -34,7 +34,7 @@
   BlockingTaskRunnerHelper(const BlockingTaskRunnerHelper&) = delete;
   BlockingTaskRunnerHelper& operator=(const BlockingTaskRunnerHelper&) = delete;
 
-  std::optional<PressureSample> Update();
+  std::optional<CpuSample> Update();
 
  private:
   // Called when a core is seen the first time.
@@ -57,7 +57,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
-std::optional<PressureSample> CpuProbeMac::BlockingTaskRunnerHelper::Update() {
+std::optional<CpuSample> CpuProbeMac::BlockingTaskRunnerHelper::Update() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   processor_info_scanner_.Update();
@@ -89,8 +89,7 @@
   }
 
   if (utilization_cores > 0) {
-    return PressureSample{.cpu_utilization =
-                              utilization_sum / utilization_cores};
+    return CpuSample{.cpu_utilization = utilization_sum / utilization_cores};
   } else {
     return std::nullopt;
   }
diff --git a/components/system_cpu/cpu_probe_mac_unittest.cc b/components/system_cpu/cpu_probe_mac_unittest.cc
index 80c9615d..9909e0c 100644
--- a/components/system_cpu/cpu_probe_mac_unittest.cc
+++ b/components/system_cpu/cpu_probe_mac_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/test/test_timeouts.h"
 #include "base/threading/platform_thread.h"
 #include "components/system_cpu/cpu_probe.h"
-#include "components/system_cpu/pressure_sample.h"
+#include "components/system_cpu/cpu_sample.h"
 #include "components/system_cpu/pressure_test_support.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -38,7 +38,7 @@
 
   base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
 
-  std::optional<PressureSample> sample = probe_->UpdateAndWaitForSample();
+  std::optional<CpuSample> sample = probe_->UpdateAndWaitForSample();
   ASSERT_TRUE(sample.has_value());
   EXPECT_GE(sample->cpu_utilization, 0.0);
   EXPECT_LE(sample->cpu_utilization, 1.0);
diff --git a/components/system_cpu/cpu_probe_unittest.cc b/components/system_cpu/cpu_probe_unittest.cc
index 3854236..a29ed47 100644
--- a/components/system_cpu/cpu_probe_unittest.cc
+++ b/components/system_cpu/cpu_probe_unittest.cc
@@ -19,7 +19,7 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "components/system_cpu/cpu_probe.h"
-#include "components/system_cpu/pressure_sample.h"
+#include "components/system_cpu/cpu_sample.h"
 #include "components/system_cpu/pressure_test_support.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -40,7 +40,7 @@
     run_loop.Run();
   }
 
-  void CollectorCallback(std::optional<PressureSample> sample) {
+  void CollectorCallback(std::optional<CpuSample> sample) {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     if (sample.has_value()) {
       samples_.push_back(sample->cpu_utilization);
@@ -77,8 +77,7 @@
 TEST_F(CpuProbeTest, RequestSample) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  static_cast<FakeCpuProbe*>(cpu_probe_.get())
-      ->SetLastSample(PressureSample{0.9});
+  static_cast<FakeCpuProbe*>(cpu_probe_.get())->SetLastSample(CpuSample{0.9});
   cpu_probe_->StartSampling();
   WaitForUpdate();
 
@@ -88,13 +87,13 @@
 TEST_F(CpuProbeTest, RepeatedSamples) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  std::vector<PressureSample> samples = {
+  std::vector<CpuSample> samples = {
       // Value right after construction.
-      PressureSample{0.6},
+      CpuSample{0.6},
       // Value after first Update(), should be discarded.
-      PressureSample{0.9},
+      CpuSample{0.9},
       // Value after second Update(), should be reported.
-      PressureSample{0.4},
+      CpuSample{0.4},
   };
 
   base::RunLoop run_loop;
@@ -110,15 +109,14 @@
 TEST_F(CpuProbeTest, DestroyWhileSampling) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  static_cast<FakeCpuProbe*>(cpu_probe_.get())
-      ->SetLastSample(PressureSample{0.9});
+  static_cast<FakeCpuProbe*>(cpu_probe_.get())->SetLastSample(CpuSample{0.9});
   cpu_probe_->StartSampling();
 
   // Test passes as long as it doesn't crash.
   base::RunLoop run_loop;
   cpu_probe_->RequestSample(base::BindOnce(
       [](base::ScopedClosureRunner quit_closure_runner,
-         std::optional<PressureSample>) {
+         std::optional<CpuSample>) {
         // `quit_closure_runner` will run the bound `quit_closure` when the
         // callback is destroyed. The callback function shouldn't actually
         // execute because the CpuProbe is destroyed before the RunLoop
@@ -134,13 +132,13 @@
 TEST_F(CpuProbeDeathTest, DISABLED_CpuUtilizationTooLarge) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  std::vector<PressureSample> samples = {
+  std::vector<CpuSample> samples = {
       // Value right after construction.
-      PressureSample{0.6},
+      CpuSample{0.6},
       // Value after first Update(), should be discarded.
-      PressureSample{0.9},
+      CpuSample{0.9},
       // Crash expected.
-      PressureSample{1.1},
+      CpuSample{1.1},
   };
 
   base::RunLoop run_loop;
@@ -155,13 +153,13 @@
 TEST_F(CpuProbeDeathTest, DISABLED_CpuUtilizationTooSmall) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  std::vector<PressureSample> samples = {
+  std::vector<CpuSample> samples = {
       // Value right after construction.
-      PressureSample{0.6},
+      CpuSample{0.6},
       // Value after first Update(), should be discarded.
-      PressureSample{0.9},
+      CpuSample{0.9},
       // Crash expected.
-      PressureSample{-0.5},
+      CpuSample{-0.5},
   };
 
   base::RunLoop run_loop;
@@ -176,8 +174,7 @@
 TEST_F(CpuProbeDeathTest, DISABLED_RequestSampleWithoutStartSampling) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  static_cast<FakeCpuProbe*>(cpu_probe_.get())
-      ->SetLastSample(PressureSample{0.9});
+  static_cast<FakeCpuProbe*>(cpu_probe_.get())->SetLastSample(CpuSample{0.9});
   EXPECT_CHECK_DEATH(WaitForUpdate());
 }
 
diff --git a/components/system_cpu/cpu_probe_win.cc b/components/system_cpu/cpu_probe_win.cc
index 6978407d..4026124 100644
--- a/components/system_cpu/cpu_probe_win.cc
+++ b/components/system_cpu/cpu_probe_win.cc
@@ -18,7 +18,7 @@
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "base/win/scoped_pdh_query.h"
-#include "components/system_cpu/pressure_sample.h"
+#include "components/system_cpu/cpu_sample.h"
 
 namespace system_cpu {
 
@@ -45,7 +45,7 @@
   BlockingTaskRunnerHelper(const BlockingTaskRunnerHelper&) = delete;
   BlockingTaskRunnerHelper& operator=(const BlockingTaskRunnerHelper&) = delete;
 
-  std::optional<PressureSample> Update();
+  std::optional<CpuSample> Update();
 
  private:
   SEQUENCE_CHECKER(sequence_checker_);
@@ -73,7 +73,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
-std::optional<PressureSample> CpuProbeWin::BlockingTaskRunnerHelper::Update() {
+std::optional<CpuSample> CpuProbeWin::BlockingTaskRunnerHelper::Update() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   PDH_STATUS pdh_status;
@@ -136,7 +136,7 @@
     return std::nullopt;
   }
 
-  return PressureSample{counter_value.doubleValue / 100.0};
+  return CpuSample{counter_value.doubleValue / 100.0};
 }
 
 // static
diff --git a/components/system_cpu/cpu_probe_win_unittest.cc b/components/system_cpu/cpu_probe_win_unittest.cc
index 3c36ee1..6f52734 100644
--- a/components/system_cpu/cpu_probe_win_unittest.cc
+++ b/components/system_cpu/cpu_probe_win_unittest.cc
@@ -37,7 +37,7 @@
 
   base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
 
-  std::optional<PressureSample> sample = probe_->UpdateAndWaitForSample();
+  std::optional<CpuSample> sample = probe_->UpdateAndWaitForSample();
   ASSERT_TRUE(sample.has_value());
   EXPECT_GE(sample->cpu_utilization, 0.0);
   EXPECT_LE(sample->cpu_utilization, 1.0);
diff --git a/components/system_cpu/pressure_sample.h b/components/system_cpu/cpu_sample.h
similarity index 71%
rename from components/system_cpu/pressure_sample.h
rename to components/system_cpu/cpu_sample.h
index 7370e3e..682a579 100644
--- a/components/system_cpu/pressure_sample.h
+++ b/components/system_cpu/cpu_sample.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_SYSTEM_CPU_PRESSURE_SAMPLE_H_
-#define COMPONENTS_SYSTEM_CPU_PRESSURE_SAMPLE_H_
+#ifndef COMPONENTS_SYSTEM_CPU_CPU_SAMPLE_H_
+#define COMPONENTS_SYSTEM_CPU_CPU_SAMPLE_H_
 
 namespace system_cpu {
 
 // Represents availability of compute resources measured over a period of time.
-struct PressureSample {
+struct CpuSample {
   // Average utilization of all CPU cores.
   //
   // Values use a scale from 0.0 (no utilization) to 1.0 (100% utilization).
@@ -17,4 +17,4 @@
 
 }  // namespace system_cpu
 
-#endif  // COMPONENTS_SYSTEM_CPU_PRESSURE_SAMPLE_H_
+#endif  // COMPONENTS_SYSTEM_CPU_CPU_SAMPLE_H_
diff --git a/components/system_cpu/pressure_test_support.cc b/components/system_cpu/pressure_test_support.cc
index 2586082..b462d7e 100644
--- a/components/system_cpu/pressure_test_support.cc
+++ b/components/system_cpu/pressure_test_support.cc
@@ -33,12 +33,12 @@
   return weak_factory_.GetWeakPtr();
 }
 
-void FakeCpuProbe::SetLastSample(std::optional<PressureSample> sample) {
+void FakeCpuProbe::SetLastSample(std::optional<CpuSample> sample) {
   base::AutoLock auto_lock(lock_);
   last_sample_ = sample;
 }
 
-StreamingCpuProbe::StreamingCpuProbe(std::vector<PressureSample> samples,
+StreamingCpuProbe::StreamingCpuProbe(std::vector<CpuSample> samples,
                                      base::OnceClosure callback)
     : samples_(std::move(samples)), done_callback_(std::move(callback)) {
   CHECK_GT(samples_.size(), 0u);
diff --git a/components/system_cpu/pressure_test_support.h b/components/system_cpu/pressure_test_support.h
index 21a61db..2546fb2 100644
--- a/components/system_cpu/pressure_test_support.h
+++ b/components/system_cpu/pressure_test_support.h
@@ -18,11 +18,11 @@
 #include "base/test/test_future.h"
 #include "base/thread_annotations.h"
 #include "components/system_cpu/cpu_probe.h"
-#include "components/system_cpu/pressure_sample.h"
+#include "components/system_cpu/cpu_sample.h"
 
 namespace system_cpu {
 
-// Test double for platform specific CpuProbe that stores the PressureSample in
+// Test double for platform specific CpuProbe that stores the CpuSample in
 // a TestFuture.
 template <typename T,
           typename = std::enable_if_t<std::is_base_of_v<CpuProbe, T>>>
@@ -35,14 +35,14 @@
 
   // Tests the internals of each platform CPU probe by calling Update() directly
   // instead of using the public interface.
-  std::optional<PressureSample> UpdateAndWaitForSample() {
+  std::optional<CpuSample> UpdateAndWaitForSample() {
     T::Update(sample_.GetCallback());
     // Blocks until the sample callback is invoked.
     return sample_.Take();
   }
 
  private:
-  base::test::TestFuture<std::optional<PressureSample>> sample_;
+  base::test::TestFuture<std::optional<CpuSample>> sample_;
 };
 
 // Test double for CpuProbe that always returns a predetermined value.
@@ -56,11 +56,11 @@
   base::WeakPtr<CpuProbe> GetWeakPtr() final;
 
   // Can be called from any thread.
-  void SetLastSample(std::optional<PressureSample> sample);
+  void SetLastSample(std::optional<CpuSample> sample);
 
  private:
   base::Lock lock_;
-  std::optional<PressureSample> last_sample_ GUARDED_BY_CONTEXT(lock_);
+  std::optional<CpuSample> last_sample_ GUARDED_BY_CONTEXT(lock_);
 
   base::WeakPtrFactory<FakeCpuProbe> weak_factory_{this};
 };
@@ -69,7 +69,7 @@
 // Update().
 class StreamingCpuProbe final : public CpuProbe {
  public:
-  StreamingCpuProbe(std::vector<PressureSample>, base::OnceClosure);
+  StreamingCpuProbe(std::vector<CpuSample>, base::OnceClosure);
 
   ~StreamingCpuProbe() final;
 
@@ -78,11 +78,11 @@
   base::WeakPtr<CpuProbe> GetWeakPtr() final;
 
  private:
-  std::vector<PressureSample> samples_ GUARDED_BY_CONTEXT(sequence_checker_);
+  std::vector<CpuSample> samples_ GUARDED_BY_CONTEXT(sequence_checker_);
   size_t sample_index_ GUARDED_BY_CONTEXT(sequence_checker_) = 0;
 
   // This closure is called on an Update() call after the expected number of
-  // samples has been taken by PressureSampler.
+  // samples has been taken by CpuSampler.
   base::OnceClosure done_callback_;
 
   base::WeakPtrFactory<StreamingCpuProbe> weak_factory_{this};
diff --git a/components/viz/COMMON_METADATA b/components/viz/COMMON_METADATA
index f7e4412..5c9475b 100644
--- a/components/viz/COMMON_METADATA
+++ b/components/viz/COMMON_METADATA
@@ -1,5 +1,7 @@
-monorail {
+monorail: {
   component: "Internals>Compositing"
 }
-
 team_email: "graphics-dev@chromium.org"
+buganizer_public: {
+  component_id: 1456836
+}
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 2eb3d4c..da0ca95a 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -566,10 +566,6 @@
   SharedQuadState shared_quad_state;
   cc::FilterOperations filters;
   cc::FilterOperations backdrop_filters;
-
-  // Represents the number of |OverlayLock|s (i.e. number of distinct frames)
-  // that reference this.
-  int ref_count = 0;
 };
 #endif
 
@@ -1234,16 +1230,15 @@
   MaybeDecrementSolidColorBuffers(committed_overlay_locks_);
 #endif  // BUILDFLAG(IS_OZONE)
 
-#if BUILDFLAG(IS_APPLE)
-  // On macOS, we don't want to release |committed_overlay_locks_| right away
-  // because CoreAnimation can hold the overlay images for potentially several
-  // frames. We depend on the output device to signal the return of overlays via
-  // |DidReceiveReleasedOverlays| to know when it's safe to release the locks.
+  // Right now, only macOS and Ozone need to return mailboxes of released
+  // overlays, so we should not release |committed_overlay_locks_| here. The
+  // resources in it will be released in DidReceiveReleasedOverlays() later.
+#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
   for (auto lock_iter = committed_overlay_locks_.begin();
        lock_iter != read_fence_lock_iter; ++lock_iter) {
     awaiting_release_overlay_locks_.insert(std::move(*lock_iter));
   }
-#endif  // BUILDFLAG(IS_APPLE)
+#endif  // BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
 
   // Current pending locks should have been committed by the next time
   // SwapBuffers() is completed.
@@ -1267,25 +1262,39 @@
 
 void SkiaRenderer::DidReceiveReleasedOverlays(
     const std::vector<gpu::Mailbox>& released_overlays) {
-#if BUILDFLAG(IS_APPLE)
   DisplayResourceProvider::ScopedBatchReturnResources returner(
       resource_provider_.get(), /*allow_access_to_gpu_thread=*/true);
 
+  // This method is only called on macOS and Ozone right now.
+#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
   for (const auto& mailbox : released_overlays) {
+    // If this mailbox is for render pass overlay, mark the released render pass
+    // overlay backing as available to be re-used.
+    auto it =
+        base::ranges::find(in_flight_render_pass_overlay_backings_, mailbox,
+                           [](const RenderPassOverlayParams& overlay) {
+                             return overlay.render_pass_backing.mailbox;
+                           });
+    if (it != in_flight_render_pass_overlay_backings_.end()) {
+      available_render_pass_overlay_backings_.push_back(*it);
+      in_flight_render_pass_overlay_backings_.erase(it);
+    }
+
     auto iter = base::ranges::find(awaiting_release_overlay_locks_, mailbox,
                                    &OverlayLock::mailbox);
     if (iter == awaiting_release_overlay_locks_.end()) {
+// TODO(crbug.com/1299794): Re-enable this DCHECK on Ozone.
+#if !BUILDFLAG(IS_OZONE)
       // The released overlay should always be found as awaiting to be released.
       DLOG(FATAL) << "Got an unexpected mailbox";
+#endif  // !BUILDFLAG(IS_OZONE)
       continue;
     }
     awaiting_release_overlay_locks_.erase(iter);
   }
 #else
-  // Only macOS has the requirement of polling the OS compositor to check if the
-  // overlay images have been released.
   NOTREACHED();
-#endif
+#endif  // BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
 }
 
 bool SkiaRenderer::FlippedFramebuffer() const {
@@ -2892,12 +2901,10 @@
       continue;
     }
 
-#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
+#if BUILDFLAG(IS_OZONE) || BUILDFLAG(IS_APPLE)
     if (overlay.rpdq) {
       PrepareRenderPassOverlay(&overlay);
-      if (!overlay.mailbox.IsZero()) {
-        locks.emplace_back(this, overlay.mailbox);
-      }
+      locks.emplace_back(overlay.mailbox);
       continue;
     }
 #else
@@ -2918,7 +2925,7 @@
         overlay.resource_size_in_pixels = gfx::Size(1, 1);
         // This can now be treated as a regular overlay with a mailbox backing.
         overlay.is_solid_color = false;
-        locks.emplace_back(this, overlay.mailbox);
+        locks.emplace_back(overlay.mailbox);
       }
 #else
       // All other platforms that support solid color overlays don't need fake
@@ -4127,75 +4134,6 @@
 }
 #endif  // BUILDFLAG(IS_OZONE)
 
-#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
-SkiaRenderer::ScopedInFlightRenderPassOverlayBackingRef::
-    ScopedInFlightRenderPassOverlayBackingRef(SkiaRenderer* renderer,
-                                              const gpu::Mailbox& mailbox)
-    : renderer_(renderer), mailbox_(mailbox) {
-  CHECK(renderer_);
-  CHECK(!mailbox_.IsZero());
-
-  auto it =
-      base::ranges::find(renderer_->in_flight_render_pass_overlay_backings_,
-                         mailbox_, [](const RenderPassOverlayParams& overlay) {
-                           return overlay.render_pass_backing.mailbox;
-                         });
-  CHECK(it != renderer_->in_flight_render_pass_overlay_backings_.end());
-
-  it->ref_count++;
-}
-
-SkiaRenderer::ScopedInFlightRenderPassOverlayBackingRef::
-    ~ScopedInFlightRenderPassOverlayBackingRef() {
-  if (!renderer_ && mailbox_.IsZero()) {
-    return;
-  }
-
-  auto it =
-      base::ranges::find(renderer_->in_flight_render_pass_overlay_backings_,
-                         mailbox_, [](const RenderPassOverlayParams& overlay) {
-                           return overlay.render_pass_backing.mailbox;
-                         });
-  CHECK(it != renderer_->in_flight_render_pass_overlay_backings_.end());
-
-  // Render pass overlay backings can be reused across multiple frames so we
-  // only want to mark them as available when we're releasing lock holding the
-  // last reference.
-  CHECK_GT(it->ref_count, 0);
-  it->ref_count--;
-  if (it->ref_count == 0) {
-    renderer_->available_render_pass_overlay_backings_.push_back(*it);
-    renderer_->in_flight_render_pass_overlay_backings_.erase(it);
-  }
-}
-
-SkiaRenderer::ScopedInFlightRenderPassOverlayBackingRef::
-    ScopedInFlightRenderPassOverlayBackingRef(
-        SkiaRenderer::ScopedInFlightRenderPassOverlayBackingRef&& other) {
-  // This is an RAII type so we depend on the move operators to clear the
-  // |other| binding so we don't to unintentional work in the dtor. We need to
-  // manually implement the move operators since neither |raw_ptr| nor
-  // |gpu::Mailbox| guarantees a move operation that default initializes the
-  // original binding.
-  renderer_ = other.renderer_;
-  other.renderer_ = nullptr;
-  mailbox_ = other.mailbox_;
-  other.mailbox_ = gpu::Mailbox();
-}
-
-SkiaRenderer::ScopedInFlightRenderPassOverlayBackingRef&
-SkiaRenderer::ScopedInFlightRenderPassOverlayBackingRef::
-    ScopedInFlightRenderPassOverlayBackingRef::operator=(
-        SkiaRenderer::ScopedInFlightRenderPassOverlayBackingRef&& other) {
-  // Manually implemented, see move ctor.
-  renderer_ = other.renderer_;
-  other.renderer_ = nullptr;
-  mailbox_ = other.mailbox_;
-  other.mailbox_ = gpu::Mailbox();
-  return *this;
-}
-#endif  // BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
-
 SkiaRenderer::OverlayLock::OverlayLock(
     DisplayResourceProvider* resource_provider,
     ResourceId resource_id) {
@@ -4224,18 +4162,15 @@
 }
 
 #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
-SkiaRenderer::OverlayLock::OverlayLock(SkiaRenderer* renderer,
-                                       const gpu::Mailbox& mailbox) {
-  render_pass_lock.emplace(renderer, mailbox);
+SkiaRenderer::OverlayLock::OverlayLock(gpu::Mailbox mailbox) {
+  render_pass_lock.emplace(mailbox);
 }
-#endif  // BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
 
-#if BUILDFLAG(IS_APPLE)
 bool SkiaRenderer::OverlayLockComparator::operator()(
     const OverlayLock& lhs,
     const OverlayLock& rhs) const {
   return lhs.mailbox() < rhs.mailbox();
 }
-#endif  // BUILDFLAG(IS_APPLE)
+#endif  // BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
 
 }  // namespace viz
diff --git a/components/viz/service/display/skia_renderer.h b/components/viz/service/display/skia_renderer.h
index 88e829dd..65544ee0 100644
--- a/components/viz/service/display/skia_renderer.h
+++ b/components/viz/service/display/skia_renderer.h
@@ -394,21 +394,6 @@
   // Specific for SkDDL.
   const raw_ptr<SkiaOutputSurface> skia_output_surface_;
 
-#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
-  // Tracks RenderPassDrawQuad and render pass overlay backings that are
-  // currently in use and available for re-using via mailboxes.
-  // RenderPassBacking.generate_mipmap is not used.
-  // Since OverlayLocks for render passes can refer to these, they must be
-  // declared before anything owning OverlayLocks to ensure a safe destruction
-  // order.
-  std::vector<RenderPassOverlayParams> in_flight_render_pass_overlay_backings_;
-  std::vector<RenderPassOverlayParams> available_render_pass_overlay_backings_;
-
-  // A feature flag that allows unchanged render pass draw quad in the overlay
-  // list to skip.
-  const bool can_skip_render_pass_overlay_;
-#endif  // BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
-
   // Lock set for resources that are used for the current frame. All resources
   // in this set will be unlocked with a sync token when the frame is done in
   // the compositor thread. And the sync token will be released when the DDL
@@ -417,42 +402,12 @@
   std::optional<DisplayResourceProviderSkia::LockSetForExternalUse>
       lock_set_for_external_use_;
 
-#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
-  // A reference to an entry in |in_flight_render_pass_overlay_backings_|. If
-  // this is the last reference, the backing will be moved to
-  // |available_render_pass_overlay_backings_| on destruction.
-  class ScopedInFlightRenderPassOverlayBackingRef {
-   public:
-    ScopedInFlightRenderPassOverlayBackingRef(SkiaRenderer* renderer,
-                                              const gpu::Mailbox& mailbox);
-    ~ScopedInFlightRenderPassOverlayBackingRef();
-
-    ScopedInFlightRenderPassOverlayBackingRef(
-        ScopedInFlightRenderPassOverlayBackingRef&& other);
-    ScopedInFlightRenderPassOverlayBackingRef& operator=(
-        ScopedInFlightRenderPassOverlayBackingRef&& other);
-
-    ScopedInFlightRenderPassOverlayBackingRef(
-        const ScopedInFlightRenderPassOverlayBackingRef&) = delete;
-    ScopedInFlightRenderPassOverlayBackingRef& operator=(
-        const ScopedInFlightRenderPassOverlayBackingRef&) = delete;
-
-    const gpu::Mailbox& mailbox() const { return mailbox_; }
-
-   private:
-    raw_ptr<SkiaRenderer> renderer_ = nullptr;
-
-    // The mailbox of the |RenderPassOverlayParams|'s backing.
-    gpu::Mailbox mailbox_;
-  };
-#endif  // BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
-
   struct OverlayLock {
     OverlayLock(DisplayResourceProvider* resource_provider,
                 ResourceId resource_id);
 
 #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
-    OverlayLock(SkiaRenderer* renderer, const gpu::Mailbox& mailbox);
+    explicit OverlayLock(gpu::Mailbox mailbox);
 #endif  // BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
 
     ~OverlayLock();
@@ -466,7 +421,7 @@
     const gpu::Mailbox& mailbox() const {
 #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
       if (render_pass_lock.has_value()) {
-        return render_pass_lock->mailbox();
+        return *render_pass_lock;
       }
 #endif  // BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
 
@@ -498,7 +453,7 @@
         resource_lock;
 
 #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
-    std::optional<ScopedInFlightRenderPassOverlayBackingRef> render_pass_lock;
+    std::optional<gpu::Mailbox> render_pass_lock;
 #endif  // BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
   };
 
@@ -513,7 +468,7 @@
   base::circular_deque<std::vector<OverlayLock>>
       read_lock_release_fence_overlay_locks_;
 
-#if BUILDFLAG(IS_APPLE)
+#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
   class OverlayLockComparator {
    public:
     using is_transparent = void;
@@ -524,7 +479,17 @@
   // mailbox() as the unique key.
   base::flat_set<OverlayLock, OverlayLockComparator>
       awaiting_release_overlay_locks_;
-#endif  // BUILDFLAG(IS_APPLE)
+
+  // Tracks RenderPassDrawQuad and render pass overlay backings that are
+  // currently in use and available for re-using via mailboxes.
+  // RenderPassBacking.generate_mipmap is not used.
+  std::vector<RenderPassOverlayParams> in_flight_render_pass_overlay_backings_;
+  std::vector<RenderPassOverlayParams> available_render_pass_overlay_backings_;
+
+  // A feature flag that allows unchanged render pass draw quad in the overlay
+  // list to skip.
+  const bool can_skip_render_pass_overlay_;
+#endif  // BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
 
   const bool is_using_raw_draw_;
 
diff --git a/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc b/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc
index d4f77d0f..07d77ca4 100644
--- a/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc
+++ b/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc
@@ -586,9 +586,9 @@
       return false;
     }
 
-    // macOS needs to signal to SkiaRenderer that render pass overlay resources
-    // can be unlocked and returned.
-#if BUILDFLAG(IS_APPLE)
+    // Right now, only macOS and LaCros needs to return maliboxes of released
+    // overlays, so SkiaRenderer can unlock resources for them.
+#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_OZONE)
     // The root render pass buffers are managed by SkiaRenderer so we don't need
     // to explicitly return them via callback.
     if (!overlay.IsRootRenderPass()) {
diff --git a/content/browser/accessibility/snapshot_ax_tree_browsertest.cc b/content/browser/accessibility/snapshot_ax_tree_browsertest.cc
index 4b59dc51..f1c88eb3 100644
--- a/content/browser/accessibility/snapshot_ax_tree_browsertest.cc
+++ b/content/browser/accessibility/snapshot_ax_tree_browsertest.cc
@@ -400,7 +400,7 @@
   web_contents->RequestAXTreeSnapshot(
       base::BindOnce(&AXTreeSnapshotWaiter::ReceiveSnapshot,
                      base::Unretained(&waiter)),
-      ui::AXMode::kPDF,
+      ui::AXMode::kPDFPrinting,
       /* max_nodes= */ 0,
       /* timeout= */ {});
   waiter.Wait();
diff --git a/content/browser/attribution_reporting/COMMON_METADATA b/content/browser/attribution_reporting/COMMON_METADATA
index de41146..9da8f7c 100644
--- a/content/browser/attribution_reporting/COMMON_METADATA
+++ b/content/browser/attribution_reporting/COMMON_METADATA
@@ -1,4 +1,7 @@
-monorail {
+monorail: {
   component: "Internals>AttributionReporting"
 }
 team_email: "privacy-sandbox-dev@chromium.org"
+buganizer_public: {
+  component_id: 1456103
+}
diff --git a/content/browser/code_cache/generated_code_cache.cc b/content/browser/code_cache/generated_code_cache.cc
index f9e76bf..326ac3cc 100644
--- a/content/browser/code_cache/generated_code_cache.cc
+++ b/content/browser/code_cache/generated_code_cache.cc
@@ -23,7 +23,6 @@
 #include "net/base/network_isolation_key.h"
 #include "net/base/url_util.h"
 #include "net/http/http_cache.h"
-#include "third_party/blink/public/common/scheme_registry.h"
 #include "url/gurl.h"
 
 using storage::BigIOBuffer;
@@ -51,8 +50,7 @@
       resource_url.SchemeIs(content::kChromeUIScheme) ||
       resource_url.SchemeIs(content::kChromeUIUntrustedScheme);
   DCHECK(resource_url.SchemeIsHTTPOrHTTPS() ||
-         resource_url_is_chrome_or_chrome_untrusted ||
-         blink::CommonSchemeRegistry::IsExtensionScheme(resource_url.scheme()));
+         resource_url_is_chrome_or_chrome_untrusted);
 
   // |origin_lock| should be either empty or should have
   // Http/Https/chrome/chrome-untrusted schemes and it should not be a URL with
@@ -61,12 +59,10 @@
   bool origin_lock_is_chrome_or_chrome_untrusted =
       origin_lock.SchemeIs(content::kChromeUIScheme) ||
       origin_lock.SchemeIs(content::kChromeUIUntrustedScheme);
-  DCHECK(
-      origin_lock.is_empty() ||
-      ((origin_lock.SchemeIsHTTPOrHTTPS() ||
-        origin_lock_is_chrome_or_chrome_untrusted ||
-        blink::CommonSchemeRegistry::IsExtensionScheme(origin_lock.scheme())) &&
-       !url::Origin::Create(origin_lock).opaque()));
+  DCHECK(origin_lock.is_empty() ||
+         ((origin_lock.SchemeIsHTTPOrHTTPS() ||
+           origin_lock_is_chrome_or_chrome_untrusted) &&
+          !url::Origin::Create(origin_lock).opaque()));
 
   // The chrome and chrome-untrusted schemes are only used with the WebUI
   // code cache type.
diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc
index 1af937c..b581eec 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -1027,20 +1027,12 @@
       return IOErrorStatus();
     }
   } else {
-    if (db_schema_version > indexed_db::kLatestKnownSchemaVersion)
+    if (db_schema_version > indexed_db::kLatestKnownSchemaVersion ||
+        db_schema_version < indexed_db::kEarliestSupportedSchemaVersion) {
       return InternalInconsistencyStatus();
+    }
 
     // Upgrade old backing store.
-    if (s.ok() && db_schema_version < 1) {
-      s = MigrateToV1(write_batch.get());
-    }
-    if (s.ok() && db_schema_version < 2) {
-      s = MigrateToV2(write_batch.get());
-      db_data_version = latest_known_data_version;
-    }
-    if (s.ok() && db_schema_version < 3) {
-      s = MigrateToV3(write_batch.get());
-    }
     if (s.ok() && db_schema_version < 4) {
       s = MigrateToV4(write_batch.get());
     }
@@ -1322,44 +1314,6 @@
   return Status::OK();
 }
 
-Status IndexedDBBackingStore::RevertSchemaToV2() {
-#if DCHECK_IS_ON()
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(initialized_);
-#endif
-  const std::string schema_version_key = SchemaVersionKey::Encode();
-  std::string value_buffer;
-  EncodeInt(2, &value_buffer);
-  leveldb::Status s = db_->Put(schema_version_key, &value_buffer);
-  if (!s.ok())
-    INTERNAL_WRITE_ERROR(REVERT_SCHEMA_TO_V2);
-  return s;
-}
-
-V2SchemaCorruptionStatus IndexedDBBackingStore::HasV2SchemaCorruption() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#if DCHECK_IS_ON()
-  DCHECK(initialized_);
-#endif
-  const std::string schema_version_key = SchemaVersionKey::Encode();
-
-  int64_t db_schema_version = 0;
-  bool found = false;
-  Status s = GetInt(db_.get(), schema_version_key, &db_schema_version, &found);
-  if (!s.ok())
-    return V2SchemaCorruptionStatus::kUnknown;
-  if (db_schema_version != 2)
-    return V2SchemaCorruptionStatus::kNo;
-
-  bool has_blobs = false;
-  s = AnyDatabaseContainsBlobs(&has_blobs);
-  if (!s.ok())
-    return V2SchemaCorruptionStatus::kUnknown;
-  if (!has_blobs)
-    return V2SchemaCorruptionStatus::kNo;
-  return V2SchemaCorruptionStatus::kYes;
-}
-
 std::unique_ptr<IndexedDBBackingStore::Transaction>
 IndexedDBBackingStore::CreateTransaction(
     blink::mojom::IDBTransactionDurability durability,
@@ -3859,93 +3813,6 @@
   }
 }
 
-Status IndexedDBBackingStore::MigrateToV1(LevelDBWriteBatch* write_batch) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  const int64_t db_schema_version = 1;
-  const std::string schema_version_key = SchemaVersionKey::Encode();
-  const std::string data_version_key = DataVersionKey::Encode();
-  Status s;
-
-  std::ignore = PutInt(write_batch, schema_version_key, db_schema_version);
-  const std::string start_key =
-      DatabaseNameKey::EncodeMinKeyForOrigin(origin_identifier_);
-  const std::string stop_key =
-      DatabaseNameKey::EncodeStopKeyForOrigin(origin_identifier_);
-  std::unique_ptr<TransactionalLevelDBIterator> it =
-      db_->CreateIterator(db_->DefaultReadOptions());
-  for (s = it->Seek(start_key);
-       s.ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0;
-       s = it->Next()) {
-    int64_t database_id = 0;
-    bool found = false;
-    s = GetInt(db_.get(), it->Key(), &database_id, &found);
-    if (!s.ok()) {
-      INTERNAL_READ_ERROR(SET_UP_METADATA);
-      return s;
-    }
-    if (!found) {
-      INTERNAL_CONSISTENCY_ERROR(SET_UP_METADATA);
-      return InternalInconsistencyStatus();
-    }
-    std::string version_key = DatabaseMetaDataKey::Encode(
-        database_id, DatabaseMetaDataKey::USER_VERSION);
-    std::ignore = PutVarInt(write_batch, version_key,
-                            IndexedDBDatabaseMetadata::DEFAULT_VERSION);
-  }
-
-  return s;
-}
-
-Status IndexedDBBackingStore::MigrateToV2(LevelDBWriteBatch* write_batch) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  const int64_t db_schema_version = 2;
-  const std::string schema_version_key = SchemaVersionKey::Encode();
-  const std::string data_version_key = DataVersionKey::Encode();
-  Status s;
-
-  std::ignore = PutInt(write_batch, schema_version_key, db_schema_version);
-  std::ignore = PutInt(write_batch, data_version_key,
-                       IndexedDBDataFormatVersion::GetCurrent().Encode());
-  return s;
-}
-
-Status IndexedDBBackingStore::MigrateToV3(LevelDBWriteBatch* write_batch) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  const int64_t db_schema_version = 3;
-  const std::string schema_version_key = SchemaVersionKey::Encode();
-  const std::string data_version_key = DataVersionKey::Encode();
-  Status s;
-
-  // Up until http://crrev.com/3c0d175b, this migration path did not write
-  // the updated schema version to disk. In consequence, any database that
-  // started out as schema version <= 2 will remain at schema version 2
-  // indefinitely. Furthermore, this migration path used to call
-  // "base::DeletePathRecursively(blob_path_)", so databases stuck at
-  // version 2 would lose their stored Blobs on every open call.
-  //
-  // In order to prevent corrupt databases, when upgrading from 2 to 3 this
-  // will consider any v2 databases with BlobEntryKey entries as corrupt.
-  // https://crbug.com/756447, https://crbug.com/829125,
-  // https://crbug.com/829141
-  bool has_blobs = false;
-  s = AnyDatabaseContainsBlobs(&has_blobs);
-  if (!s.ok()) {
-    INTERNAL_CONSISTENCY_ERROR(SET_UP_METADATA);
-    return InternalInconsistencyStatus();
-  }
-  if (has_blobs) {
-    INTERNAL_CONSISTENCY_ERROR(UPGRADING_SCHEMA_CORRUPTED_BLOBS);
-    return InternalInconsistencyStatus();
-  } else {
-    std::ignore = PutInt(write_batch, schema_version_key, db_schema_version);
-  }
-
-  return s;
-}
-
 Status IndexedDBBackingStore::MigrateToV4(LevelDBWriteBatch* write_batch) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
diff --git a/content/browser/indexed_db/indexed_db_backing_store.h b/content/browser/indexed_db/indexed_db_backing_store.h
index 69c27f3..419dbb36 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.h
+++ b/content/browser/indexed_db/indexed_db_backing_store.h
@@ -64,12 +64,6 @@
 FORWARD_DECLARE_TEST(IndexedDBBackingStoreTest, ReadCorruptionInfo);
 }  // namespace indexed_db_backing_store_unittest
 
-enum class V2SchemaCorruptionStatus {
-  kUnknown = 0,  // Due to other unknown/critical errors.
-  kNo = 1,
-  kYes = 2,
-};
-
 // This class is not thread-safe.
 // All accessses to one instance must occur on the same sequence. Currently,
 // this must be the IndexedDB task runner's sequence.
@@ -628,15 +622,6 @@
   // Stops the journal_cleaning_timer_ and runs its pending task.
   void ForceRunBlobCleanup();
 
-  // HasV2SchemaCorruption() returns whether the backing store is v2 and
-  // has blob references.
-  V2SchemaCorruptionStatus HasV2SchemaCorruption();
-
-  // RevertSchemaToV2() updates a backing store state on disk to override its
-  // metadata version to 2.  This allows triggering https://crbug.com/829141 on
-  // an otherwise healthy backing store.
-  leveldb::Status RevertSchemaToV2();
-
   bool in_memory() const { return backing_store_mode_ == Mode::kInMemory; }
 
   virtual std::unique_ptr<Transaction> CreateTransaction(
@@ -696,9 +681,6 @@
 
   friend class AutoDidCommitTransaction;
 
-  leveldb::Status MigrateToV1(LevelDBWriteBatch* write_batch);
-  leveldb::Status MigrateToV2(LevelDBWriteBatch* write_batch);
-  leveldb::Status MigrateToV3(LevelDBWriteBatch* write_batch);
   leveldb::Status MigrateToV4(LevelDBWriteBatch* write_batch);
   leveldb::Status MigrateToV5(LevelDBWriteBatch* write_batch);
 
diff --git a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
index 0fd6375..f49a584 100644
--- a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
@@ -1608,200 +1608,6 @@
   EXPECT_EQ("foo", message);
 }
 
-// There was a wrong migration from schema 2 to 3, which always delete IDB
-// blobs and doesn't actually write the new schema version. This tests the
-// upgrade path where the database doesn't have blob entries, so it' safe to
-// keep the database.
-// https://crbug.com/756447, https://crbug.com/829125, https://crbug.com/829141
-TEST_F(IndexedDBBackingStoreTest, SchemaUpgradeWithoutBlobsSurvives) {
-  int64_t database_id;
-  const int64_t object_store_id = 99;
-
-  // The database metadata needs to be written so we can verify the blob entry
-  // keys are not detected.
-  const std::u16string database_name(u"db1");
-  const int64_t version = 9;
-
-  const std::u16string object_store_name(u"object_store1");
-  const bool auto_increment = true;
-  const IndexedDBKeyPath object_store_key_path(u"object_store_key");
-
-  {
-    IndexedDBDatabaseMetadata database;
-    database.name = database_name;
-    database.version = version;
-    leveldb::Status s = backing_store()->CreateDatabase(database);
-    EXPECT_TRUE(s.ok());
-    EXPECT_GT(database.id, 0);
-    database_id = database.id;
-
-    IndexedDBBackingStore::Transaction transaction(
-        backing_store()->AsWeakPtr(),
-        blink::mojom::IDBTransactionDurability::Relaxed,
-        blink::mojom::IDBTransactionMode::ReadWrite);
-    transaction.Begin(CreateDummyLock());
-
-    IndexedDBObjectStoreMetadata object_store;
-    s = backing_store()->CreateObjectStore(
-        &transaction, database.id, object_store_id, object_store_name,
-        object_store_key_path, auto_increment, &object_store);
-    EXPECT_TRUE(s.ok());
-
-    bool succeeded = false;
-    EXPECT_TRUE(
-        transaction.CommitPhaseOne(CreateBlobWriteCallback(&succeeded)).ok());
-    EXPECT_TRUE(succeeded);
-    EXPECT_TRUE(transaction.CommitPhaseTwo().ok());
-  }
-  task_environment_.RunUntilIdle();
-
-  // Save a value.
-  IndexedDBBackingStore::Transaction transaction1(
-      backing_store()->AsWeakPtr(),
-      blink::mojom::IDBTransactionDurability::Relaxed,
-      blink::mojom::IDBTransactionMode::ReadWrite);
-  transaction1.Begin(CreateDummyLock());
-  IndexedDBBackingStore::RecordIdentifier record;
-  leveldb::Status s = backing_store()->PutRecord(
-      &transaction1, database_id, object_store_id, key1_, &value1_, &record);
-  EXPECT_TRUE(s.ok());
-  bool succeeded = false;
-  EXPECT_TRUE(
-      transaction1.CommitPhaseOne(CreateBlobWriteCallback(&succeeded)).ok());
-  EXPECT_TRUE(succeeded);
-  EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
-
-  // Set the schema to 2, which was before blob support.
-  std::unique_ptr<LevelDBWriteBatch> write_batch = LevelDBWriteBatch::Create();
-  const std::string schema_version_key = SchemaVersionKey::Encode();
-  std::ignore = indexed_db::PutInt(write_batch.get(), schema_version_key, 2);
-  ASSERT_TRUE(backing_store()->db()->Write(write_batch.get()).ok());
-  task_environment_.RunUntilIdle();
-
-  DestroyFactoryAndBackingStore();
-  CreateFactoryAndBackingStore();
-
-  IndexedDBBackingStore::Transaction transaction2(
-      backing_store()->AsWeakPtr(),
-      blink::mojom::IDBTransactionDurability::Relaxed,
-      blink::mojom::IDBTransactionMode::ReadWrite);
-  transaction2.Begin(CreateDummyLock());
-  IndexedDBValue result_value;
-  EXPECT_TRUE(backing_store()
-                  ->GetRecord(&transaction2, database_id, object_store_id,
-                              key1_, &result_value)
-                  .ok());
-  succeeded = false;
-  EXPECT_TRUE(
-      transaction2.CommitPhaseOne(CreateBlobWriteCallback(&succeeded)).ok());
-  EXPECT_TRUE(succeeded);
-  EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
-  EXPECT_EQ(value1_.bits, result_value.bits);
-
-  // Test that we upgraded.
-  int64_t found_int = 0;
-  bool found = false;
-  bool success = indexed_db::GetInt(backing_store()->db(), schema_version_key,
-                                    &found_int, &found)
-                     .ok();
-  ASSERT_TRUE(success);
-
-  EXPECT_TRUE(found);
-  EXPECT_EQ(indexed_db::kLatestKnownSchemaVersion, found_int);
-  task_environment_.RunUntilIdle();
-}
-
-// Our v2->v3 schema migration code forgot to bump the on-disk version number.
-// This test covers migrating a v3 database mislabeled as v2 to a properly
-// labeled v3 database. When the mislabeled database has blob entries, we must
-// treat it as corrupt and delete it.
-// https://crbug.com/756447, https://crbug.com/829125, https://crbug.com/829141
-TEST_F(IndexedDBBackingStoreTestWithBlobs, SchemaUpgradeWithBlobsCorrupt) {
-  int64_t database_id;
-  const int64_t object_store_id = 99;
-
-  // The database metadata needs to be written so the blob entry keys can
-  // be detected.
-  const std::u16string database_name(u"db1");
-  const int64_t version = 9;
-
-  const std::u16string object_store_name(u"object_store1");
-  const bool auto_increment = true;
-  const IndexedDBKeyPath object_store_key_path(u"object_store_key");
-
-  {
-    IndexedDBDatabaseMetadata database;
-    database.name = database_name;
-    database.version = version;
-    leveldb::Status s = backing_store()->CreateDatabase(database);
-    EXPECT_TRUE(s.ok());
-    EXPECT_GT(database.id, 0);
-    database_id = database.id;
-
-    IndexedDBBackingStore::Transaction transaction(
-        backing_store()->AsWeakPtr(),
-        blink::mojom::IDBTransactionDurability::Relaxed,
-        blink::mojom::IDBTransactionMode::ReadWrite);
-    transaction.Begin(CreateDummyLock());
-
-    IndexedDBObjectStoreMetadata object_store;
-    s = backing_store()->CreateObjectStore(
-        &transaction, database.id, object_store_id, object_store_name,
-        object_store_key_path, auto_increment, &object_store);
-    EXPECT_TRUE(s.ok());
-
-    bool succeeded = false;
-    EXPECT_TRUE(
-        transaction.CommitPhaseOne(CreateBlobWriteCallback(&succeeded)).ok());
-    EXPECT_TRUE(succeeded);
-    EXPECT_TRUE(transaction.CommitPhaseTwo().ok());
-  }
-  task_environment_.RunUntilIdle();
-
-  base::RunLoop write_blobs_loop;
-  // Initiate transaction1 - writing blobs.
-  std::unique_ptr<IndexedDBBackingStore::Transaction> transaction1 =
-      std::make_unique<IndexedDBBackingStore::Transaction>(
-          backing_store()->AsWeakPtr(),
-          blink::mojom::IDBTransactionDurability::Relaxed,
-          blink::mojom::IDBTransactionMode::ReadWrite);
-  transaction1->Begin(CreateDummyLock());
-  IndexedDBBackingStore::RecordIdentifier record;
-  EXPECT_TRUE(backing_store()
-                  ->PutRecord(transaction1.get(), database_id, object_store_id,
-                              key3_, &value3_, &record)
-                  .ok());
-  bool succeeded = false;
-  EXPECT_TRUE(transaction1
-                  ->CommitPhaseOne(CreateBlobWriteCallback(
-                      &succeeded, write_blobs_loop.QuitClosure()))
-                  .ok());
-  task_environment_.RunUntilIdle();
-  write_blobs_loop.Run();
-
-  // Finish up transaction1, verifying blob writes.
-  EXPECT_TRUE(succeeded);
-  EXPECT_TRUE(CheckBlobWrites());
-  EXPECT_TRUE(transaction1->CommitPhaseTwo().ok());
-
-  // Set the schema to 2, which was before blob support.
-  std::unique_ptr<LevelDBWriteBatch> write_batch = LevelDBWriteBatch::Create();
-  const std::string schema_version_key = SchemaVersionKey::Encode();
-  std::ignore = indexed_db::PutInt(write_batch.get(), schema_version_key, 2);
-  ASSERT_TRUE(backing_store()->db()->Write(write_batch.get()).ok());
-
-  // Clean up on the IDB sequence.
-  transaction1.reset();
-  task_environment_.RunUntilIdle();
-
-  DestroyFactoryAndBackingStore();
-  CreateFactoryAndBackingStore();
-
-  // The factory returns a null backing store pointer when there is a corrupt
-  // database.
-  EXPECT_TRUE(data_loss_info_.status == blink::mojom::IDBDataLoss::Total);
-}
-
 namespace {
 
 // v3 Blob Data is encoded as a series of:
diff --git a/content/browser/indexed_db/indexed_db_browsertest.cc b/content/browser/indexed_db/indexed_db_browsertest.cc
index dd033c2..a518f096 100644
--- a/content/browser/indexed_db/indexed_db_browsertest.cc
+++ b/content/browser/indexed_db/indexed_db_browsertest.cc
@@ -245,35 +245,6 @@
     return future.Take();
   }
 
-  bool RequestSchemaDowngrade(const storage::BucketLocator& bucket_locator) {
-    base::RunLoop loop;
-    bool downgraded;
-    auto control_test = GetControlTest();
-    control_test->ForceSchemaDowngradeForTesting(
-        bucket_locator, base::BindLambdaForTesting([&](bool was_downgraded) {
-          downgraded = was_downgraded;
-          loop.Quit();
-        }));
-    loop.Run();
-    return downgraded;
-  }
-
-  storage::mojom::V2SchemaCorruptionStatus RequestHasV2SchemaCorruption(
-      const storage::BucketLocator& bucket_locator) {
-    base::RunLoop loop;
-    storage::mojom::V2SchemaCorruptionStatus ret;
-    auto control_test = GetControlTest();
-    control_test->HasV2SchemaCorruptionForTesting(
-        bucket_locator,
-        base::BindLambdaForTesting(
-            [&](storage::mojom::V2SchemaCorruptionStatus status) {
-              ret = status;
-              loop.Quit();
-            }));
-    loop.Run();
-    return ret;
-  }
-
   // Synchronously writes to the IndexedDB database at the given storage_key.
   void WriteToIndexedDB(const storage::BucketLocator& bucket_locator,
                         std::string key,
@@ -633,15 +604,6 @@
   }
 };
 
-class IndexedDBBrowserTestWithVersion0Schema : public
-    IndexedDBBrowserTestWithPreexistingLevelDB {
-  std::string EnclosingLevelDBDir() override { return "migration_from_0"; }
-};
-
-IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion0Schema, MigrationTest) {
-  SimpleTest(GetTestUrl("indexeddb", "migration_test.html"));
-}
-
 class IndexedDBBrowserTestWithVersion3Schema
     : public IndexedDBBrowserTestWithPreexistingLevelDB {
   std::string EnclosingLevelDBDir() override { return "v3_migration_test"; }
@@ -1229,62 +1191,6 @@
   EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
 }
 
-// The V2 schema corruption test runs in a separate class to avoid corrupting
-// an IDB store that other tests use.
-class IndexedDBBrowserTestV2SchemaCorruption : public IndexedDBBrowserTest {};
-
-// Verify the V2 schema corruption lifecycle:
-// - create a current version backing store (v3 or later)
-// - add an object store, some data, and an object that contains a blob
-// - verify the object+blob are stored in the object store
-// - verify the backing store doesn't have v2 schema corruption
-// - force the schema to downgrade to v2
-// - verify the backing store has v2 schema corruption
-// - verify the object+blob can be fetched
-IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestV2SchemaCorruption, LifecycleTest) {
-  ASSERT_TRUE(embedded_test_server()->Started() ||
-              embedded_test_server()->InitializeAndListen());
-  embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
-      &StaticFileRequestHandler, s_indexeddb_test_prefix, this));
-  embedded_test_server()->StartAcceptingConnections();
-
-  // Set up the IndexedDB instance so it contains our reference data.
-  std::string test_file =
-      std::string(s_indexeddb_test_prefix) + "v2schemacorrupt_setup.html";
-  SimpleTest(embedded_test_server()->GetURL(test_file));
-
-  // Find the bucket that was created.
-  ASSERT_OK_AND_ASSIGN(
-      const auto bucket_info,
-      GetOrCreateBucket(storage::BucketInitParams::ForDefaultBucket(
-          blink::StorageKey::CreateFirstParty(
-              url::Origin::Create(embedded_test_server()->base_url())))));
-  const auto bucket_locator = bucket_info.ToBucketLocator();
-
-  // Verify the backing store does not have corruption.
-  storage::mojom::V2SchemaCorruptionStatus has_corruption =
-      RequestHasV2SchemaCorruption(bucket_locator);
-  ASSERT_EQ(has_corruption,
-            storage::mojom::V2SchemaCorruptionStatus::CORRUPTION_NO);
-
-  // Revert schema to v2.  This closes the targeted backing store.
-  bool schema_downgrade = RequestSchemaDowngrade(bucket_locator);
-  ASSERT_EQ(schema_downgrade, true);
-
-  // Re-open the backing store and verify it has corruption.
-  test_file =
-      std::string(s_indexeddb_test_prefix) + "v2schemacorrupt_reopen.html";
-  SimpleTest(embedded_test_server()->GetURL(test_file));
-  has_corruption = RequestHasV2SchemaCorruption(bucket_locator);
-  ASSERT_EQ(has_corruption,
-            storage::mojom::V2SchemaCorruptionStatus::CORRUPTION_YES);
-
-  // Verify that the saved blob is get-able with a v2 backing store.
-  test_file =
-      std::string(s_indexeddb_test_prefix) + "v2schemacorrupt_verify.html";
-  SimpleTest(embedded_test_server()->GetURL(test_file));
-}
-
 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ShutdownWithRequests) {
   SimpleTest(GetTestUrl("indexeddb", "shutdown_with_requests.html"));
 }
diff --git a/content/browser/indexed_db/indexed_db_bucket_context.cc b/content/browser/indexed_db/indexed_db_bucket_context.cc
index 7d53f6bc..6eaf51af 100644
--- a/content/browser/indexed_db/indexed_db_bucket_context.cc
+++ b/content/browser/indexed_db/indexed_db_bucket_context.cc
@@ -185,7 +185,8 @@
     return {false, leveldb::Status::Corruption(
                        "Invalid IndexedDB database schema version.")};
   }
-  if (db_schema_version > indexed_db::kLatestKnownSchemaVersion) {
+  if (db_schema_version > indexed_db::kLatestKnownSchemaVersion ||
+      db_schema_version < indexed_db::kEarliestSupportedSchemaVersion) {
     return {false, s};
   }
 
diff --git a/content/browser/indexed_db/indexed_db_context_impl.cc b/content/browser/indexed_db/indexed_db_context_impl.cc
index 6b36beca..62abb6ff 100644
--- a/content/browser/indexed_db/indexed_db_context_impl.cc
+++ b/content/browser/indexed_db/indexed_db_context_impl.cc
@@ -511,49 +511,6 @@
   std::move(callback).Run();
 }
 
-void IndexedDBContextImpl::ForceSchemaDowngradeForTesting(
-    const storage::BucketLocator& bucket_locator,
-    ForceSchemaDowngradeForTestingCallback callback) {
-  DCHECK(IDBTaskRunner()->RunsTasksInCurrentSequence());
-
-  if (is_incognito() || !LookUpBucket(bucket_locator.id)) {
-    std::move(callback).Run(false);
-    return;
-  }
-
-  if (indexeddb_factory_.get()) {
-    indexeddb_factory_->ForceSchemaDowngrade(bucket_locator);
-    std::move(callback).Run(true);
-    return;
-  }
-  ForceClose(
-      bucket_locator.id,
-      storage::mojom::ForceCloseReason::FORCE_SCHEMA_DOWNGRADE_INTERNALS_PAGE,
-      base::DoNothing());
-  std::move(callback).Run(false);
-}
-
-void IndexedDBContextImpl::HasV2SchemaCorruptionForTesting(
-    const storage::BucketLocator& bucket_locator,
-    HasV2SchemaCorruptionForTestingCallback callback) {
-  DCHECK(IDBTaskRunner()->RunsTasksInCurrentSequence());
-
-  if (is_incognito() || !LookUpBucket(bucket_locator.id)) {
-    std::move(callback).Run(
-        storage::mojom::V2SchemaCorruptionStatus::CORRUPTION_UNKNOWN);
-    return;
-  }
-
-  if (indexeddb_factory_.get()) {
-    std::move(callback).Run(
-        static_cast<storage::mojom::V2SchemaCorruptionStatus>(
-            indexeddb_factory_->HasV2SchemaCorruption(bucket_locator)));
-    return;
-  }
-  return std::move(callback).Run(
-      storage::mojom::V2SchemaCorruptionStatus::CORRUPTION_UNKNOWN);
-}
-
 void IndexedDBContextImpl::WriteToIndexedDBForTesting(
     const storage::BucketLocator& bucket_locator,
     const std::string& key,
diff --git a/content/browser/indexed_db/indexed_db_context_impl.h b/content/browser/indexed_db/indexed_db_context_impl.h
index e22452d0..f8fe89c 100644
--- a/content/browser/indexed_db/indexed_db_context_impl.h
+++ b/content/browser/indexed_db/indexed_db_context_impl.h
@@ -109,12 +109,6 @@
   void GetFilePathForTesting(const storage::BucketLocator& bucket_locator,
                              GetFilePathForTestingCallback callback) override;
   void ResetCachesForTesting(base::OnceClosure callback) override;
-  void ForceSchemaDowngradeForTesting(
-      const storage::BucketLocator& bucket_locator,
-      ForceSchemaDowngradeForTestingCallback callback) override;
-  void HasV2SchemaCorruptionForTesting(
-      const storage::BucketLocator& bucket_locator,
-      HasV2SchemaCorruptionForTestingCallback callback) override;
   void WriteToIndexedDBForTesting(const storage::BucketLocator& bucket_locator,
                                   const std::string& key,
                                   const std::string& value,
diff --git a/content/browser/indexed_db/indexed_db_factory.cc b/content/browser/indexed_db/indexed_db_factory.cc
index 31f07d12..fab8553 100644
--- a/content/browser/indexed_db/indexed_db_factory.cc
+++ b/content/browser/indexed_db/indexed_db_factory.cc
@@ -206,31 +206,6 @@
   it->second->ForceClose(/*doom=*/will_be_deleted);
 }
 
-void IndexedDBFactory::ForceSchemaDowngrade(
-    const storage::BucketLocator& bucket_locator) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  auto it = bucket_contexts_.find(bucket_locator.id);
-  if (it == bucket_contexts_.end()) {
-    return;
-  }
-
-  IndexedDBBackingStore* backing_store = it->second->backing_store();
-  leveldb::Status s = backing_store->RevertSchemaToV2();
-  DLOG_IF(ERROR, !s.ok()) << "Unable to force downgrade: " << s.ToString();
-}
-
-V2SchemaCorruptionStatus IndexedDBFactory::HasV2SchemaCorruption(
-    const storage::BucketLocator& bucket_locator) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  auto it = bucket_contexts_.find(bucket_locator.id);
-  if (it == bucket_contexts_.end()) {
-    return V2SchemaCorruptionStatus::kUnknown;
-  }
-
-  IndexedDBBackingStore* backing_store = it->second->backing_store();
-  return backing_store->HasV2SchemaCorruption();
-}
-
 void IndexedDBFactory::ContextDestroyed() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Set `context_` to nullptr first to ensure no re-entry into the `context_`
diff --git a/content/browser/indexed_db/indexed_db_factory.h b/content/browser/indexed_db/indexed_db_factory.h
index cf0f141..a9d5ef82 100644
--- a/content/browser/indexed_db/indexed_db_factory.h
+++ b/content/browser/indexed_db/indexed_db_factory.h
@@ -93,10 +93,6 @@
   // multithreading.
   void ForceClose(storage::BucketId bucket_id, bool will_be_deleted);
 
-  void ForceSchemaDowngrade(const storage::BucketLocator& bucket_locator);
-  V2SchemaCorruptionStatus HasV2SchemaCorruption(
-      const storage::BucketLocator& bucket_locator);
-
   // Called by the IndexedDBContext destructor so the factory can do cleanup.
   void ContextDestroyed();
 
diff --git a/content/browser/indexed_db/indexed_db_leveldb_coding.h b/content/browser/indexed_db/indexed_db_leveldb_coding.h
index 7dd617d..7e8f7a48 100644
--- a/content/browser/indexed_db/indexed_db_leveldb_coding.h
+++ b/content/browser/indexed_db/indexed_db_leveldb_coding.h
@@ -29,6 +29,10 @@
 // 4 - Adds size & last_modified to 'file' blob_info encodings.
 // 5 - One time verification that blob files exist on disk.
 const constexpr int64_t kLatestKnownSchemaVersion = 5;
+// Migration from version 2 to 3 occurred in 2014, and migration to version 4
+// began in early 2020, so we currently continue to support schema that are as
+// old as 2014.
+const constexpr int64_t kEarliestSupportedSchemaVersion = 3;
 }  // namespace indexed_db
 
 CONTENT_EXPORT extern const unsigned char kMinimumIndexId;
diff --git a/content/browser/indexed_db/indexed_db_reporting.h b/content/browser/indexed_db/indexed_db_reporting.h
index 0ca3628..6409cc3a 100644
--- a/content/browser/indexed_db/indexed_db_reporting.h
+++ b/content/browser/indexed_db/indexed_db_reporting.h
@@ -51,7 +51,7 @@
   GET_BLOB_KEY_GENERATOR_CURRENT_NUMBER = 28,
   GET_BLOB_INFO_FOR_RECORD = 29,
   UPGRADING_SCHEMA_CORRUPTED_BLOBS = 30,
-  REVERT_SCHEMA_TO_V2 = 31,
+  // REVERT_SCHEMA_TO_V2 = 31,
   CREATE_ITERATOR = 32,
   INTERNAL_ERROR_MAX,
 };
diff --git a/content/browser/preloading/prerender/README.md b/content/browser/preloading/prerender/README.md
index d882c48..16f5204 100644
--- a/content/browser/preloading/prerender/README.md
+++ b/content/browser/preloading/prerender/README.md
@@ -118,11 +118,8 @@
 ### Force-disable all prerender triggers
 
 - The simplest and most aggressive way is disabling preloading on chrome://settings/preloading.
-- If you only want to disable Prerender2, run chromium with the command of
-  `--enable-features=Prerender2MemoryControls:memory_threshold_in_mb/10000000`.
-  This command makes prerender2 only run on devices with more than 10,000,000 MB
-  memory, and it should be able to stop prerender2 from triggering on (almost)
-  all devices (Change `10000000` to a bigger value if needed).
+- If you only want to disable Prerender2, you can use
+  chrome://flags/#prerender2, or `--disable-features=Prerender2`.
 
 ### Force-disable specific prerender triggers
 
diff --git a/content/browser/preloading/prerender/prerender_host_registry.cc b/content/browser/preloading/prerender/prerender_host_registry.cc
index fbab6ed..5766f64 100644
--- a/content/browser/preloading/prerender/prerender_host_registry.cc
+++ b/content/browser/preloading/prerender/prerender_host_registry.cc
@@ -554,6 +554,13 @@
       return RenderFrameHost::kNoFrameTreeNodeId;
     }
 
+    // Check the about://flags toggle.
+    if (!base::FeatureList::IsEnabled(blink::features::kPrerender2)) {
+      builder.RejectAsNotEligible(attributes,
+                                  PrerenderFinalStatus::kPreloadingDisabled);
+      return RenderFrameHost::kNoFrameTreeNodeId;
+    }
+
     // Check whether preloading is enabled. If it is not enabled, report the
     // reason.
     switch (initiator_web_contents.GetDelegate()->IsPrerender2Supported(
diff --git a/content/browser/renderer_host/agent_scheduling_group_host.cc b/content/browser/renderer_host/agent_scheduling_group_host.cc
index c2fb50f..6350ef6 100644
--- a/content/browser/renderer_host/agent_scheduling_group_host.cc
+++ b/content/browser/renderer_host/agent_scheduling_group_host.cc
@@ -175,15 +175,20 @@
   // interface are reinitialized.
   ResetIPC();
 
-  // RenderProcessHostImpl will attempt to call this method later if it has not
-  // already been called. We call it now since `SetUpIPC()` relies on it being
-  // called, thus setting up the IPC channel and mojom::Renderer interface.
-  process_->EnableSendQueue();
+  // We don't want to reinitialize the RenderProcessHost's IPC channel when
+  // we are going to immediately get a call to RenderProcessHostDestroyed.
+  if (!process_->IsDeletingSoon()) {
+    // RenderProcessHostImpl will attempt to call this method later if it has
+    // not already been called. We call it now since `SetUpIPC()` relies on it
+    // being called, thus setting up the IPC channel and mojom::Renderer
+    // interface.
+    process_->EnableSendQueue();
 
-  // We call this so that we can immediately queue IPC and mojo messages on the
-  // new channel/interfaces that are bound for the next renderer process, should
-  // one eventually be spun up.
-  SetUpIPC();
+    // We call this so that we can immediately queue IPC and mojo messages on
+    // the new channel/interfaces that are bound for the next renderer process,
+    // should one eventually be spun up.
+    SetUpIPC();
+  }
 }
 
 void AgentSchedulingGroupHost::RenderProcessHostDestroyed(
@@ -194,7 +199,8 @@
       RenderProcessExited(host, ChildProcessTerminationInfo());
     }
   }
-  DCHECK_EQ(state_, LifecycleState::kBound);
+  DCHECK(state_ == LifecycleState::kBound ||
+         state_ == LifecycleState::kRenderProcessExited);
 
   DCHECK_EQ(host, &*process_);
   process_->RemoveObserver(this);
@@ -471,12 +477,13 @@
           {LifecycleState::kNewborn, {LifecycleState::kBound}},
           {LifecycleState::kBound,
            {LifecycleState::kRenderProcessExited,
-            // Note: kRenderProcessHostDestroyed is only reached through kBound
-            //       state. Upon kRenderProcessExited, we immediately setup a
-            //       unclaimed mojo endpoint to be consumed by the next
-            //       renderer process.
+            // Note: If a renderer process is never spawned to claim the
+            //       mojo endpoint created at initialization, then we will
+            //       skip straight to the destroyed state.
             LifecycleState::kRenderProcessHostDestroyed}},
-          {LifecycleState::kRenderProcessExited, {LifecycleState::kBound}},
+          {LifecycleState::kRenderProcessExited,
+           {LifecycleState::kBound,
+            LifecycleState::kRenderProcessHostDestroyed}},
       }));
 
   DCHECK_STATE_TRANSITION(transitions, state_, state);
diff --git a/content/browser/renderer_host/code_cache_host_impl.cc b/content/browser/renderer_host/code_cache_host_impl.cc
index b083cd8..985dc00 100644
--- a/content/browser/renderer_host/code_cache_host_impl.cc
+++ b/content/browser/renderer_host/code_cache_host_impl.cc
@@ -26,7 +26,6 @@
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "net/base/io_buffer.h"
 #include "third_party/blink/public/common/cache_storage/cache_storage_utils.h"
-#include "third_party/blink/public/common/scheme_registry.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
@@ -69,8 +68,7 @@
     return process_lock.matches_scheme(content::kChromeUIScheme) ||
            process_lock.matches_scheme(content::kChromeUIUntrustedScheme);
   }
-  if (resource_url.SchemeIsHTTPOrHTTPS() ||
-      blink::CommonSchemeRegistry::IsExtensionScheme(resource_url.scheme())) {
+  if (resource_url.SchemeIsHTTPOrHTTPS()) {
     if (process_lock.matches_scheme(content::kChromeUIScheme) ||
         process_lock.matches_scheme(content::kChromeUIUntrustedScheme)) {
       // It is possible for WebUI pages to include open-web content, but such
@@ -424,9 +422,7 @@
   if (process_lock.matches_scheme(url::kHttpScheme) ||
       process_lock.matches_scheme(url::kHttpsScheme) ||
       process_lock.matches_scheme(content::kChromeUIScheme) ||
-      process_lock.matches_scheme(content::kChromeUIUntrustedScheme) ||
-      blink::CommonSchemeRegistry::IsExtensionScheme(
-          process_lock.lock_url().scheme())) {
+      process_lock.matches_scheme(content::kChromeUIUntrustedScheme)) {
     return process_lock.lock_url();
   }
 
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index 8bcb2eb..7517bdd 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -7,6 +7,7 @@
 #include <errno.h>
 
 #include "content/browser/renderer_host/render_widget_helper.h"
+#include "content/common/features.h"
 #include "content/public/browser/browser_thread.h"
 #include "third_party/blink/public/common/tokens/tokens.h"
 
@@ -16,9 +17,11 @@
     int render_process_id,
     RenderWidgetHelper* render_widget_helper)
     : render_widget_helper_(render_widget_helper),
-      render_process_id_(render_process_id) {
-  if (render_widget_helper)
+      render_process_id_(render_process_id),
+      cache_response_size_(features::kFrameRoutingCacheResponseSize.Get()) {
+  if (render_widget_helper) {
     render_widget_helper_->Init(render_process_id_);
+  }
 }
 
 RenderMessageFilter::~RenderMessageFilter() {
@@ -26,16 +29,28 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 }
 
-void RenderMessageFilter::GenerateFrameRoutingID(
-    GenerateFrameRoutingIDCallback callback) {
-  int32_t routing_id = render_widget_helper_->GetNextRoutingID();
-  auto frame_token = blink::LocalFrameToken();
-  auto devtools_frame_token = base::UnguessableToken::Create();
-  auto document_token = blink::DocumentToken();
+mojom::FrameRoutingInfoPtr RenderMessageFilter::AllocateNewRoutingInfo() {
+  auto result = mojom::FrameRoutingInfo::New();
+  result->routing_id = render_widget_helper_->GetNextRoutingID();
+  result->devtools_frame_token = base::UnguessableToken::Create();
   render_widget_helper_->StoreNextFrameRoutingID(
-      routing_id, frame_token, devtools_frame_token, document_token);
-  std::move(callback).Run(routing_id, frame_token, devtools_frame_token,
-                          document_token);
+      result->routing_id, result->frame_token, result->devtools_frame_token,
+      result->document_token);
+  return result;
+}
+
+void RenderMessageFilter::GenerateSingleFrameRoutingInfo(
+    GenerateSingleFrameRoutingInfoCallback callback) {
+  std::move(callback).Run(AllocateNewRoutingInfo());
+}
+
+void RenderMessageFilter::GenerateFrameRoutingInfos(
+    GenerateFrameRoutingInfosCallback callback) {
+  std::vector<mojom::FrameRoutingInfoPtr> result;
+  for (int i = 0; i < cache_response_size_; ++i) {
+    result.push_back(AllocateNewRoutingInfo());
+  }
+  std::move(callback).Run(std::move(result));
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index a01566d..ce1481d 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -26,12 +26,18 @@
   RenderMessageFilter& operator=(const RenderMessageFilter&) = delete;
 
  private:
+  mojom::FrameRoutingInfoPtr AllocateNewRoutingInfo();
+
   // mojom::RenderMessageFilter:
-  void GenerateFrameRoutingID(GenerateFrameRoutingIDCallback callback) override;
+  void GenerateSingleFrameRoutingInfo(
+      GenerateSingleFrameRoutingInfoCallback callback) override;
+  void GenerateFrameRoutingInfos(
+      GenerateFrameRoutingInfosCallback callback) override;
 
   scoped_refptr<RenderWidgetHelper> render_widget_helper_;
 
   const int render_process_id_;
+  const int cache_response_size_;
 };
 
 }  // namespace content
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 161ae31..bcdcd1d7 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -3862,6 +3862,10 @@
   return is_initialized_ && !is_dead_;
 }
 
+bool RenderProcessHostImpl::IsDeletingSoon() {
+  return deleting_soon_;
+}
+
 void RenderProcessHostImpl::SetBlocked(bool blocked) {
   if (blocked == is_blocked_)
     return;
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 4c63a41b..7612d98 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -244,6 +244,7 @@
   int GetID() const override;
   base::SafeRef<RenderProcessHost> GetSafeRef() const override;
   bool IsInitializedAndNotDead() override;
+  bool IsDeletingSoon() override;
   void SetBlocked(bool blocked) override;
   bool IsBlocked() override;
   base::CallbackListSubscription RegisterBlockStateChangedCallback(
@@ -362,8 +363,8 @@
 
   // Return the set of previously stored data for a `frame_token`.
   // The routing ID and frame tokens were stored on the IO thread via the
-  // RenderMessageFilter::GenerateFrameRoutingID mojo call. Returns false if
-  // `frame_token` was not found in the token table.
+  // RenderMessageFilter::GenerateSingleFrameRoutingInfo mojo call. Returns
+  // false if `frame_token` was not found in the token table.
   bool TakeStoredDataForFrameToken(const blink::LocalFrameToken& frame_token,
                                    int32_t& new_routing_id,
                                    base::UnguessableToken& devtools_frame_token,
diff --git a/content/browser/resources/service_worker/serviceworker_internals.html b/content/browser/resources/service_worker/serviceworker_internals.html
index 52542cd..0d19bb3 100644
--- a/content/browser/resources/service_worker/serviceworker_internals.html
+++ b/content/browser/resources/service_worker/serviceworker_internals.html
@@ -82,13 +82,11 @@
         jsdisplay="$this.third_party_storage_partitioning_enabled">
         Storage key:
         <div class="serviceworker-storage-key">
-          <div class="serviceworker-origin"
-            jsdisplay="$this.ancestor_chain_bit == 'CrossSite'">
-            <span>origin:</span>
+          <div class="serviceworker-origin">
+            <span>Origin:</span>
             <span jscontent="$this.origin"></span>
           </div>
-          <div class="serviceworker-top-level-site"
-            jsdisplay="$this.ancestor_chain_bit == 'CrossSite'">
+          <div class="serviceworker-top-level-site">
             <span>Top level site:</span>
             <span jscontent="$this.top_level_site"></span>
           </div>
@@ -97,8 +95,8 @@
             <span jscontent="$this.ancestor_chain_bit"></span>
           </div>
           <div class="serviceworker-nonce"
-            jsdisplay="$this.ancestor_chain_bit == 'CrossSite'">
-            <span>nonce:</span>
+            jsdisplay="$this.nonce !== '<null>'">
+            <span>Nonce:</span>
             <span jscontent="$this.nonce"></span>
           </div>
         </div>
diff --git a/content/browser/service_worker/service_worker_internals_ui_browsertest.cc b/content/browser/service_worker/service_worker_internals_ui_browsertest.cc
index aa26011..b9a8f44 100644
--- a/content/browser/service_worker/service_worker_internals_ui_browsertest.cc
+++ b/content/browser/service_worker/service_worker_internals_ui_browsertest.cc
@@ -568,6 +568,9 @@
 
   EXPECT_EQ(kTitle, title_watcher.WaitAndGetTitle());
 
+  GURL top_level_page(embedded_test_server()->GetURL(kServiceWorkerUrl));
+  GURL scope(embedded_test_server()->GetURL(kServiceWorkerScope));
+
   // Assert populated service worker info.
   SetActiveWindow(sw_internal_ui_window);
   ASSERT_EQ(base::NumberToString(version_id),
@@ -581,6 +584,15 @@
       GetServiceWorkerInfoFromInternalUI(registration_id, "running_status"));
   ASSERT_EQ(GetServiceWorkerInfo(PROCESS_ID),
             GetServiceWorkerInfoFromInternalUI(registration_id, "process_id"));
+  ASSERT_EQ(url::Origin::Create(scope).GetDebugString(),
+            GetServiceWorkerInfoFromInternalUI(registration_id, "origin"));
+  ASSERT_EQ(
+      net::SchemefulSite(url::Origin::Create(top_level_page)).Serialize(),
+      GetServiceWorkerInfoFromInternalUI(registration_id, "top_level_site"));
+  ASSERT_EQ("SameSite", GetServiceWorkerInfoFromInternalUI(
+                            registration_id, "ancestor_chain_bit"));
+  ASSERT_EQ("missed",
+            GetServiceWorkerInfoFromInternalUI(registration_id, "nonce"));
 
   // Leave a clean state.
   UnRegisterServiceWorker();
@@ -784,7 +796,7 @@
       GetServiceWorkerInfoFromInternalUI(registration_id, "top_level_site"));
   ASSERT_EQ("CrossSite", GetServiceWorkerInfoFromInternalUI(
                              registration_id, "ancestor_chain_bit"));
-  ASSERT_EQ("<null>",
+  ASSERT_EQ("missed",
             GetServiceWorkerInfoFromInternalUI(registration_id, "nonce"));
 }
 
diff --git a/content/browser/tracing/tracing_end_to_end_browsertest.cc b/content/browser/tracing/tracing_end_to_end_browsertest.cc
index 808411ba..04f4c41 100644
--- a/content/browser/tracing/tracing_end_to_end_browsertest.cc
+++ b/content/browser/tracing/tracing_end_to_end_browsertest.cc
@@ -572,8 +572,7 @@
   // connecting to the service), but it doesn't matter. We just want to make
   // sure that at least one of them is there.
   std::vector<char> trace;
-  size_t i = 0;
-  for (; i < 300; i++) {
+  for (size_t i = 0; i < 100; i++) {
     EXPECT_TRUE(ExecJs(tab, "performance.mark('mark1');"));
 
     base::RunLoop flush;
@@ -589,7 +588,6 @@
       break;
     }
   }
-  ASSERT_LT(i, 300U);
 
   base::test::TestTraceProcessorImpl ttp;
   absl::Status status = ttp.ParseTrace(trace);
diff --git a/content/browser/webui/web_ui_browsertest.cc b/content/browser/webui/web_ui_browsertest.cc
index 5306d509..6ea238d8 100644
--- a/content/browser/webui/web_ui_browsertest.cc
+++ b/content/browser/webui/web_ui_browsertest.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
 #include <utility>
 
 #include "base/command_line.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/functional/callback_helpers.h"
-#include "base/memory/ptr_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/weak_ptr.h"
@@ -99,7 +99,7 @@
                             base::Unretained(this)));
     web_ui()->RegisterMessageCallback(
         "sendMessage",
-        base::BindRepeating(&TestWebUIMessageHandler::OnSendMessase,
+        base::BindRepeating(&TestWebUIMessageHandler::OnSendMessage,
                             base::Unretained(this)));
   }
 
@@ -125,7 +125,7 @@
       finish_closure_.Run();
   }
 
-  void OnSendMessase(const base::Value::List& args) {
+  void OnSendMessage(const base::Value::List& args) {
     // This message will be invoked when WebContents changes the main RFH
     // and the old main RFH is still alive during navigating from WebUI page
     // to cross-site. WebUI message should be handled with old main RFH.
@@ -161,9 +161,9 @@
 
   void SetUpOnMainThread() override {
     ASSERT_TRUE(NavigateToURL(web_contents(), GetWebUIURL(kChromeUIGpuHost)));
-    test_handler_ = new TestWebUIMessageHandler();
-    web_contents()->GetWebUI()->AddMessageHandler(
-        base::WrapUnique(test_handler_.get()));
+    auto test_handler = std::make_unique<TestWebUIMessageHandler>();
+    test_handler_ = test_handler.get();
+    web_contents()->GetWebUI()->AddMessageHandler(std::move(test_handler));
   }
   void TearDownOnMainThread() override { test_handler_ = nullptr; }
 
@@ -710,8 +710,9 @@
   auto* web_contents = shell()->web_contents();
   ASSERT_TRUE(NavigateToURL(web_contents, GetWebUIURL(kChromeUIHistogramHost)));
 
-  WebUIMessageHandler* test_handler = new TestWebUIMessageHandler;
-  web_contents->GetWebUI()->AddMessageHandler(base::WrapUnique(test_handler));
+  auto owned_test_handler = std::make_unique<TestWebUIMessageHandler>();
+  auto* test_handler = owned_test_handler.get();
+  web_contents->GetWebUI()->AddMessageHandler(std::move(owned_test_handler));
   test_handler->AllowJavascriptForTesting();
 
   // Push onto window.history. Back should now be an in-page navigation.
@@ -735,9 +736,9 @@
     // `TestWebUIMessageHandler` will point to a stale WebUI and we can't check
     // the `IsJavascriptAllowed()` value there. So use a new handler here and
     // check the value on the new handler instead.
-    WebUIMessageHandler* test_handler2 = new TestWebUIMessageHandler;
-    web_contents->GetWebUI()->AddMessageHandler(
-        base::WrapUnique(test_handler2));
+    auto owned_test_handler2 = std::make_unique<TestWebUIMessageHandler>();
+    auto* test_handler2 = owned_test_handler2.get();
+    web_contents->GetWebUI()->AddMessageHandler(std::move(owned_test_handler2));
     EXPECT_FALSE(test_handler2->IsJavascriptAllowed());
   }
 }
@@ -829,8 +830,9 @@
   auto* web_contents = shell()->web_contents();
   ASSERT_TRUE(NavigateToURL(web_contents, GetWebUIURL(kChromeUIGpuHost)));
 
-  auto* test_handler = new TestWebUIMessageHandler;
-  web_contents->GetWebUI()->AddMessageHandler(base::WrapUnique(test_handler));
+  auto owned_test_handler = std::make_unique<TestWebUIMessageHandler>();
+  auto* test_handler = owned_test_handler.get();
+  web_contents->GetWebUI()->AddMessageHandler(std::move(owned_test_handler));
 
   auto* webui = static_cast<WebUIImpl*>(web_contents->GetWebUI());
   EXPECT_EQ(web_contents->GetPrimaryMainFrame(), webui->GetRenderFrameHost());
diff --git a/content/common/features.cc b/content/common/features.cc
index d577af2..a55c479 100644
--- a/content/common/features.cc
+++ b/content/common/features.cc
@@ -234,6 +234,14 @@
              base::FEATURE_ENABLED_BY_DEFAULT);
 #endif
 
+// Whether to use the Frame Routing Cache to avoid synchronous IPCs from the
+// renderer side for iframe creation.
+BASE_FEATURE(kFrameRoutingCache,
+             "FrameRoutingCache",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+const base::FeatureParam<int> kFrameRoutingCacheResponseSize{
+    &kFrameRoutingCache, "responseSize", 4};
+
 // Adds "/prefetch:8" (which is the "other" category of process - i.e. not
 // browser, gpu, crashpad, etc.) to the info collection GPU process' command
 // line, in order to keep from polluting the GPU prefetch history.
diff --git a/content/common/features.h b/content/common/features.h
index 6400663..2b5af37 100644
--- a/content/common/features.h
+++ b/content/common/features.h
@@ -54,6 +54,9 @@
 #if !BUILDFLAG(IS_ANDROID)
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kForwardMemoryPressureEventsToGpuProcess);
 #endif
+CONTENT_EXPORT BASE_DECLARE_FEATURE(kFrameRoutingCache);
+CONTENT_EXPORT extern const base::FeatureParam<int>
+    kFrameRoutingCacheResponseSize;
 #if BUILDFLAG(IS_WIN)
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kGpuInfoCollectionSeparatePrefetch);
 #endif
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
index 3051e35e..9381a20 100644
--- a/content/common/frame.mojom
+++ b/content/common/frame.mojom
@@ -700,9 +700,10 @@
       => (CreateNewWindowStatus status, CreateNewWindowReply? reply);
 
   // Asynchronously creates a child frame. A blink.mojom.LocalFrameToken must
-  // be allocated first by calling RenderMessageFilter::GenerateFrameRoutingID()
-  // Each of these messages will have a corresponding mojom::FrameHost::Detach
-  // API sent when the frame is detached from the DOM.
+  // be allocated first by calling
+  // `RenderMessageFilter::GenerateSingleFrameRoutingInfo`. Each of these
+  // messages will have a corresponding mojom::FrameHost::Detach API sent when
+  // the frame is detached from the DOM.
   CreateChildFrame(blink.mojom.LocalFrameToken child_frame_token,
                    pending_associated_remote<content.mojom.Frame> frame,
                    pending_receiver<blink.mojom.BrowserInterfaceBroker>
diff --git a/content/common/render_message_filter.mojom b/content/common/render_message_filter.mojom
index 4e24679e..ff3857da 100644
--- a/content/common/render_message_filter.mojom
+++ b/content/common/render_message_filter.mojom
@@ -7,12 +7,24 @@
 import "mojo/public/mojom/base/unguessable_token.mojom";
 import "third_party/blink/public/mojom/tokens/tokens.mojom";
 
+// Struct representing the routing information needed for a child iframe
+// created from the renderer.
+struct FrameRoutingInfo {
+  int32 routing_id;
+  blink.mojom.LocalFrameToken frame_token;
+  mojo_base.mojom.UnguessableToken devtools_frame_token;
+  blink.mojom.DocumentToken document_token;
+};
+
+// A interface to the browser process that is handled on the IO thread.
+// This interface contains synchronous calls the renderer needs to
+// block on and should be serviced quickly.
 interface RenderMessageFilter {
-  // Similar to GenerateRoutingID but also generates a `frame token`,
-  // `devtools_frame_token`, and `document_token`. A subsequent call to
+  // Generates a FrameRoutingInfo object. A subsequent call to
   // `FrameHost::CreateChildFrame` is expected after this call.
-  [Sync] GenerateFrameRoutingID() => (int32 routing_id,
-                   blink.mojom.LocalFrameToken frame_token,
-                   mojo_base.mojom.UnguessableToken devtools_frame_token,
-                   blink.mojom.DocumentToken document_token);
+  [Sync] GenerateSingleFrameRoutingInfo() => (FrameRoutingInfo info);
+
+  // Similar to `GenerateSingleFrameRoutingInfo` but returns multiple
+  // FrameRoutingInfo objects that can be later used.
+  [Sync] GenerateFrameRoutingInfos() => (array<FrameRoutingInfo> info_array);
 };
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index 2554ec6..888d3dc 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -305,6 +305,12 @@
   // still return an invalid process with a null handle.
   virtual bool IsInitializedAndNotDead() = 0;
 
+  /// Returns true iff the decision has been made to delete `this`.
+  ///
+  /// If this returns true, then no new child processes will be associated
+  /// with `this`.
+  virtual bool IsDeletingSoon() = 0;
+
   // Returns the renderer channel.
   virtual IPC::ChannelProxy* GetChannel() = 0;
 
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index e06cada..8013e2d5 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -257,12 +257,6 @@
     // and GetLastActiveTime() will return the WebContents' creation time.
     base::TimeTicks last_active_time;
 
-    // Normal WebContents initialization is split between construction and the
-    // first time it is shown. Some WebContents are never shown though.
-    // Setting this to true will invoke the WebContents delayed initialization
-    // that doesn't require visibility.
-    bool is_never_visible = false;
-
     // Code location responsible for creating the CreateParams.  This is used
     // mostly for debugging (e.g. to help attribute specific scenarios or
     // invariant violations to a particular flavor of WebContents).
diff --git a/content/public/test/browser_task_environment.h b/content/public/test/browser_task_environment.h
index 64d92c74..b58a38be 100644
--- a/content/public/test/browser_task_environment.h
+++ b/content/public/test/browser_task_environment.h
@@ -42,7 +42,7 @@
 // To synchronously run tasks from the shared message loop:
 //
 // ... until there are no undelayed tasks in the shared message loop:
-//    base::RunLoop::RunUntilIdle();
+//    base::RunLoop().RunUntilIdle();
 //
 // ... until there are no undelayed tasks in the shared message loop, in
 // ThreadPool (excluding tasks not posted from the shared message loop's thread
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc
index ffcd134..11a3c636 100644
--- a/content/public/test/mock_render_process_host.cc
+++ b/content/public/test/mock_render_process_host.cc
@@ -274,6 +274,10 @@
   return has_connection_;
 }
 
+bool MockRenderProcessHost::IsDeletingSoon() {
+  return deletion_callback_called_;
+}
+
 void MockRenderProcessHost::SetBlocked(bool blocked) {}
 
 bool MockRenderProcessHost::IsBlocked() {
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h
index f71b1fe..c183a64 100644
--- a/content/public/test/mock_render_process_host.h
+++ b/content/public/test/mock_render_process_host.h
@@ -116,6 +116,7 @@
   int GetID() const override;
   base::SafeRef<RenderProcessHost> GetSafeRef() const override;
   bool IsInitializedAndNotDead() override;
+  bool IsDeletingSoon() override;
   void SetBlocked(bool blocked) override;
   bool IsBlocked() override;
   base::CallbackListSubscription RegisterBlockStateChangedCallback(
diff --git a/content/renderer/accessibility/render_accessibility_impl.cc b/content/renderer/accessibility/render_accessibility_impl.cc
index 8970837..44ca6ba09 100644
--- a/content/renderer/accessibility/render_accessibility_impl.cc
+++ b/content/renderer/accessibility/render_accessibility_impl.cc
@@ -771,8 +771,9 @@
 void RenderAccessibilityImpl::AddImageAnnotations(
     const WebDocument& document,
     std::vector<ui::AXNodeData*>& nodes) {
-  if (accessibility_mode_.has_mode(ui::AXMode::kPDF))
+  if (accessibility_mode_.has_mode(ui::AXMode::kPDFPrinting)) {
     return;
+  }
   for (auto* node : nodes) {
     WebAXObject src = WebAXObject::FromWebDocumentByID(document, node->id);
 
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 659ec40..fef1829e 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -639,6 +639,12 @@
 
   UpdateForegroundCrashKey(
       /*foreground=*/!blink::kLaunchingProcessIsBackgrounded);
+
+  use_cached_routing_table_ =
+      base::FeatureList::IsEnabled(features::kFrameRoutingCache);
+  if (use_cached_routing_table_) {
+    RequestNewItemsForFrameRoutingCache();
+  }
 }
 
 RenderThreadImpl::~RenderThreadImpl() {
@@ -739,8 +745,56 @@
     blink::LocalFrameToken& frame_token,
     base::UnguessableToken& devtools_frame_token,
     blink::DocumentToken& document_token) {
-  return render_message_filter()->GenerateFrameRoutingID(
-      &routing_id, &frame_token, &devtools_frame_token, &document_token);
+  if (!use_cached_routing_table_) {
+    mojom::FrameRoutingInfoPtr info;
+    if (!render_message_filter()->GenerateSingleFrameRoutingInfo(&info)) {
+      return false;
+    }
+    routing_id = info->routing_id;
+    frame_token = info->frame_token;
+    devtools_frame_token = info->devtools_frame_token;
+    document_token = info->document_token;
+    return true;
+  }
+
+  // If table is empty force a synchronous fetch.
+  if (cached_frame_routing_.empty()) {
+    std::vector<mojom::FrameRoutingInfoPtr> infos;
+    if (!render_message_filter()->GenerateFrameRoutingInfos(&infos)) {
+      return false;
+    }
+    for (auto& info : infos) {
+      cached_frame_routing_.push_back(std::move(info));
+    }
+  }
+
+  auto& front = cached_frame_routing_.front();
+  routing_id = front->routing_id;
+  frame_token = front->frame_token;
+  devtools_frame_token = front->devtools_frame_token;
+  document_token = front->document_token;
+  cached_frame_routing_.pop_front();
+
+  // If the table drops to 2 or less, request an asynchronous populate.
+  if (!cached_items_requested_ && cached_frame_routing_.size() <= 2) {
+    RequestNewItemsForFrameRoutingCache();
+  }
+  return true;
+}
+
+void RenderThreadImpl::RequestNewItemsForFrameRoutingCache() {
+  cached_items_requested_ = true;
+  render_message_filter()->GenerateFrameRoutingInfos(
+      base::BindOnce(&RenderThreadImpl::PopulateFrameRoutingCacheWithItems,
+                     base::Unretained(this)));
+}
+
+void RenderThreadImpl::PopulateFrameRoutingCacheWithItems(
+    std::vector<mojom::FrameRoutingInfoPtr> infos) {
+  cached_items_requested_ = false;
+  for (auto& info : infos) {
+    cached_frame_routing_.push_back(std::move(info));
+  }
 }
 
 void RenderThreadImpl::AddObserver(RenderThreadObserver* observer) {
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 5d8937a69..e28ef63 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <deque>
 #include <map>
 #include <memory>
 #include <optional>
@@ -461,6 +462,9 @@
       bool enable_video_encode_accelerator);
 
   mojom::RenderMessageFilter* render_message_filter();
+  void RequestNewItemsForFrameRoutingCache();
+  void PopulateFrameRoutingCacheWithItems(
+      std::vector<mojom::FrameRoutingInfoPtr> infos);
 
   scoped_refptr<discardable_memory::ClientDiscardableSharedMemoryManager>
       discardable_memory_allocator_;
@@ -575,6 +579,17 @@
   // Tracks the time the run loop started for this thread.
   base::TimeTicks run_loop_start_time_;
 
+  // A small cache of pending frame routing IDs/tokens so we do not need to make
+  // a synchronous IPC call to retrieve one most of the time. If the cache is
+  // empty a synchronous IPC call will be made. Once the cache only has two
+  // items an asynchronous request to populate it will also be made.
+  std::deque<mojom::FrameRoutingInfoPtr> cached_frame_routing_;
+
+  // Keep track of it we have requested items or not as we do not want to fire
+  // off only one asynchronous request.
+  bool cached_items_requested_ = false;
+  bool use_cached_routing_table_ = false;
+
   base::WeakPtrFactory<RenderThreadImpl> weak_factory_{this};
 };
 
diff --git a/content/test/content_test_bundle_data.filelist b/content/test/content_test_bundle_data.filelist
index 33e2f4f8..6c17658 100644
--- a/content/test/content_test_bundle_data.filelist
+++ b/content/test/content_test_bundle_data.filelist
@@ -6521,12 +6521,6 @@
 data/indexeddb/key_types_test.html
 data/indexeddb/key_types_test.js
 data/indexeddb/migration_database_generator.html
-data/indexeddb/migration_from_0/file__0.indexeddb.leveldb/000003.log
-data/indexeddb/migration_from_0/file__0.indexeddb.leveldb/CURRENT
-data/indexeddb/migration_from_0/file__0.indexeddb.leveldb/LOCK
-data/indexeddb/migration_from_0/file__0.indexeddb.leveldb/MANIFEST-000002
-data/indexeddb/migration_test.html
-data/indexeddb/migration_test.js
 data/indexeddb/missing_sst/file__0.indexeddb.leveldb/000008.sst
 data/indexeddb/missing_sst/file__0.indexeddb.leveldb/000009.log
 data/indexeddb/missing_sst/file__0.indexeddb.leveldb/CURRENT
@@ -6568,9 +6562,6 @@
 data/indexeddb/transaction_run_forever.js
 data/indexeddb/transaction_test.html
 data/indexeddb/transaction_test.js
-data/indexeddb/v2schemacorrupt_reopen.html
-data/indexeddb/v2schemacorrupt_setup.html
-data/indexeddb/v2schemacorrupt_verify.html
 data/indexeddb/v3_migration_test.html
 data/indexeddb/v3_migration_test/file__0.indexeddb.blob/1/00/2
 data/indexeddb/v3_migration_test/file__0.indexeddb.blob/1/00/3
diff --git a/content/test/data/indexeddb/migration_from_0/file__0.indexeddb.leveldb/000003.log b/content/test/data/indexeddb/migration_from_0/file__0.indexeddb.leveldb/000003.log
deleted file mode 100644
index 1b04bf84..0000000
--- a/content/test/data/indexeddb/migration_from_0/file__0.indexeddb.leveldb/000003.log
+++ /dev/null
Binary files differ
diff --git a/content/test/data/indexeddb/migration_from_0/file__0.indexeddb.leveldb/CURRENT b/content/test/data/indexeddb/migration_from_0/file__0.indexeddb.leveldb/CURRENT
deleted file mode 100644
index 1a84852..0000000
--- a/content/test/data/indexeddb/migration_from_0/file__0.indexeddb.leveldb/CURRENT
+++ /dev/null
@@ -1 +0,0 @@
-MANIFEST-000002
diff --git a/content/test/data/indexeddb/migration_from_0/file__0.indexeddb.leveldb/LOCK b/content/test/data/indexeddb/migration_from_0/file__0.indexeddb.leveldb/LOCK
deleted file mode 100644
index e69de29..0000000
--- a/content/test/data/indexeddb/migration_from_0/file__0.indexeddb.leveldb/LOCK
+++ /dev/null
diff --git a/content/test/data/indexeddb/migration_from_0/file__0.indexeddb.leveldb/MANIFEST-000002 b/content/test/data/indexeddb/migration_from_0/file__0.indexeddb.leveldb/MANIFEST-000002
deleted file mode 100644
index 741e1a2..0000000
--- a/content/test/data/indexeddb/migration_from_0/file__0.indexeddb.leveldb/MANIFEST-000002
+++ /dev/null
Binary files differ
diff --git a/content/test/data/indexeddb/migration_test.html b/content/test/data/indexeddb/migration_test.html
deleted file mode 100644
index 5fbd4834..0000000
--- a/content/test/data/indexeddb/migration_test.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<html>
-  <head>
-    <title>IndexedDB migration test</title>
-    <script type="text/javascript" src="common.js"></script>
-    <script type="text/javascript" src="migration_test.js"></script>
-  </head>
-  <body onLoad="test()">
-    <div id="status">Starting...</div>
-  </body>
-</html>
diff --git a/content/test/data/indexeddb/migration_test.js b/content/test/data/indexeddb/migration_test.js
deleted file mode 100644
index e9853afb..0000000
--- a/content/test/data/indexeddb/migration_test.js
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2012 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-function test() {
-  request = indexedDB.open('open-close-version-test1');
-  request.onsuccess = openTest2;
-  request.onupgradeneeded = onupgrade;
-  request.onerror = unexpectedErrorCallback;
-  request.onblocked = unexpectedBlockedCallback;
-}
-
-var saw_upgradeneeded_event = false;
-function onupgrade(event) {
-  saw_upgradeneeded_event = true;
-  db = event.target.result;
-  debug("Ensure that the existing leveldb files are used. If they are not, " +
-        "this script will create a new database that has no object stores");
-  shouldBe("event.oldVersion", "0");
-  shouldBe("event.newVersion", "1");
-  // A pre-existing store in a database that was version 0 can only
-  // happen with databases creating with the old setVersion(string)
-  // API that was removed from Chrome circa 2012, and was never
-  // supported in other browsers.
-  shouldBe("db.objectStoreNames.length", "1");
-  shouldBeEqualToString("typeof db.version", "number");
-  shouldBe("db.version", "1");
-}
-
-function openTest2(event) {
-  shouldBeTrue("saw_upgradeneeded_event");
-  db = event.target.result;
-  shouldBe("db.objectStoreNames.length", "1");
-  shouldBeEqualToString("typeof db.version", "number");
-  shouldBe("db.version", "1");
-  request = indexedDB.open('open-close-version-test2');
-  request.onsuccess = done;
-  request.onerror = unexpectedErrorCallback;
-  request.onblocked = unexpectedBlockedCallback;
-}
diff --git a/content/test/data/indexeddb/v2schemacorrupt_reopen.html b/content/test/data/indexeddb/v2schemacorrupt_reopen.html
deleted file mode 100644
index 40d68bd..0000000
--- a/content/test/data/indexeddb/v2schemacorrupt_reopen.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<html>
-<!--
-Copyright 2018 The Chromium Authors
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-<head>
-<!-- Reopen a database so its backing store is available to the invoking
-     backing store. -->
-<title>IDB test for v2schema corruption - reopen</title>
-<script type="text/javascript" src="common.js"></script>
-<script>
-
-function test() {
-  const dbname = "v2schemacorrupt_setup.html";
-  const request = indexedDB.open(dbname);
-  request.onsuccess = () => { done(); };
-  request.onerror = unexpectedErrorCallback;
-  request.onblocked = unexpectedBlockedCallback;
-}
-
-</script>
-</head>
-<body onLoad="test()">
-<div id="status">Starting...</div>
-</body>
-</html>
diff --git a/content/test/data/indexeddb/v2schemacorrupt_setup.html b/content/test/data/indexeddb/v2schemacorrupt_setup.html
deleted file mode 100644
index 192ff36..0000000
--- a/content/test/data/indexeddb/v2schemacorrupt_setup.html
+++ /dev/null
@@ -1,64 +0,0 @@
-<!DOCTYPE html>
-<html>
-<!--
-Copyright 2018 The Chromium Authors
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-<head>
-<!-- Create a schema with a blob.  This will be downgraded to V2 by the
-     invoking browsertest. -->
-<title>IDB test for v2schema corruption - setup</title>
-<script type="text/javascript" src="common.js"></script>
-<script>
-
-function test() {
-  // TODO(cmp): Switch this and the other corruption browser test to a promise-
-  //            based call flow.
-  indexedDBTest(upgradeCallback, openCallback);
-}
-
-let db;
-
-function upgradeCallback() {
-  db = event.target.result;
-  deleteAllObjectStores(db);
-  objectStore = db.createObjectStore('storeName', { autoIncrement : true });
-}
-
-function openCallback() {
-  const transaction = db.transaction('storeName', 'readwrite');
-  transaction.onabort = unexpectedAbortCallback;
-  transaction.onerror = unexpectedErrorCallback;
-  transaction.oncomplete = getBlob;
-  const objectStore = transaction.objectStore('storeName');
-  const request = objectStore.put({blob: new Blob(['abc'])}, 'key-0');
-  request.onerror = unexpectedErrorCallback;
-}
-
-function getBlob() {
-  const transaction = db.transaction('storeName', 'readwrite');
-  transaction.onabort = unexpectedAbortCallback;
-  transaction.onerror = unexpectedErrorCallback;
-  const objectStore = transaction.objectStore('storeName');
-  const request = objectStore.get('key-0');
-  request.onerror = unexpectedErrorCallback;
-  request.onsuccess = () => {
-    const reader = new FileReader();
-    reader.addEventListener("loadend", () => {
-      if (reader.result !== "abc") {
-        fail(`expected blob to contain 'abc', got '${reader.result}'`);
-        return;
-      }
-      done();
-    });
-    reader.readAsText(request.result.blob);
-  }
-}
-
-</script>
-</head>
-<body onLoad="test()">
-<div id="status">Starting...</div>
-</body>
-</html>
diff --git a/content/test/data/indexeddb/v2schemacorrupt_verify.html b/content/test/data/indexeddb/v2schemacorrupt_verify.html
deleted file mode 100644
index 75206fbd..0000000
--- a/content/test/data/indexeddb/v2schemacorrupt_verify.html
+++ /dev/null
@@ -1,49 +0,0 @@
-<!DOCTYPE html>
-<html>
-<!--
-Copyright 2018 The Chromium Authors
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-<head>
-<!-- Verify the storeName / key-0 blob key is present
-     and blob value matches what was written during setup. -->
-<title>IDB test for v2schema corruption - verify</title>
-<script type="text/javascript" src="common.js"></script>
-<script>
-
-function test() {
-  const dbname = "v2schemacorrupt_setup.html";
-  const request = indexedDB.open(dbname);
-  request.onsuccess = onSuccess;
-  request.onerror = unexpectedErrorCallback;
-  request.onblocked = unexpectedBlockedCallback;
-}
-
-function onSuccess(event) {
-  db = event.target.result;
-  debug("Verify object store exists");
-  shouldBe("db.objectStoreNames.length", "1");
-  const transaction = db.transaction("storeName", "readonly");
-  const objectStore = transaction.objectStore("storeName");
-  const request = objectStore.get("key-0");
-  request.onsuccess = (requestSuccessEvent) => {
-    const reader = new FileReader();
-    reader.addEventListener("loadend", () => {
-      if (reader.result !== "abc") {
-        fail(`expected blob to contain 'abc', got '${reader.result}'`);
-        return;
-      }
-      done();
-    });
-    reader.readAsText(request.result.blob);
-  };
-  request.onerror = () => { fail("onerror called"); };
-}
-
-</script>
-</head>
-<body onLoad="test()">
-<div id="status">Starting...</div>
-</body>
-</html>
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index 24d9696..2e4a3cff 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -514,6 +514,7 @@
 crbug.com/1523401 [ win11 qualcomm-0x41333430 angle-d3d11 ] deqp/functional/gles3/shaderindexing/tmp.html [ Failure ]
 crbug.com/1523401 [ win11 qualcomm-0x41333430 angle-d3d11 ] deqp/functional/gles3/shaderindexing/varying.html [ Failure ]
 crbug.com/1523401 [ win11 qualcomm-0x41333430 angle-d3d11 ] deqp/functional/gles3/shadertexturefunction/texelfetchoffset.html [ Failure ]
+crbug.com/323824490 [ win11 qualcomm-0x41333430 angle-d3d11 ] conformance/ogles/GL/ceil/ceil_001_to_006.html [ RetryOnFailure ]
 
 ######################
 # Mac Metal failures #
diff --git a/docs/updater/functional_spec.md b/docs/updater/functional_spec.md
index f168351..6909c1a 100644
--- a/docs/updater/functional_spec.md
+++ b/docs/updater/functional_spec.md
@@ -41,7 +41,8 @@
 
 ##### Brand code
 The brand code is a string of up to 4 characters long. The brand code is
-persisted during the install, over-installs, and updates.
+persisted during the first install of the app. Over-installs and updates do not
+modify the brand code.
 
 On macOS, the brand code (as well as AP parameter and the app version) can be
 specified using a path to a plist file and a key within that plist file. When
diff --git a/docs/website b/docs/website
index e85b75e..ab6fa72 160000
--- a/docs/website
+++ b/docs/website
@@ -1 +1 @@
-Subproject commit e85b75e5b3355dc1c848bf89a884b33b44693375
+Subproject commit ab6fa722cd68f58581086289b93bac51775b453e
diff --git a/internal b/internal
index 01d0125..267ce4f 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit 01d0125dd7c53d19a5983726d14b842676311905
+Subproject commit 267ce4f58248ec59895483e5ef12b065db32717c
diff --git a/ios/chrome/browser/contextual_panel/model/BUILD.gn b/ios/chrome/browser/contextual_panel/model/BUILD.gn
index c9c0c66..38a681c 100644
--- a/ios/chrome/browser/contextual_panel/model/BUILD.gn
+++ b/ios/chrome/browser/contextual_panel/model/BUILD.gn
@@ -4,11 +4,16 @@
 
 source_set("model") {
   sources = [
+    "contextual_panel_browser_agent.h",
+    "contextual_panel_browser_agent.mm",
     "contextual_panel_tab_helper.h",
     "contextual_panel_tab_helper.mm",
   ]
   deps = [
     "//base",
+    "//ios/chrome/browser/shared/model/browser",
+    "//ios/chrome/browser/shared/model/browser_state",
+    "//ios/chrome/browser/shared/model/web_state_list",
     "//ios/web/public",
   ]
 }
diff --git a/ios/chrome/browser/contextual_panel/model/contextual_panel_browser_agent.h b/ios/chrome/browser/contextual_panel/model/contextual_panel_browser_agent.h
new file mode 100644
index 0000000..8b119f0
--- /dev/null
+++ b/ios/chrome/browser/contextual_panel/model/contextual_panel_browser_agent.h
@@ -0,0 +1,46 @@
+// 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.
+
+#ifndef IOS_CHROME_BROWSER_CONTEXTUAL_PANEL_MODEL_CONTEXTUAL_PANEL_BROWSER_AGENT_H_
+#define IOS_CHROME_BROWSER_CONTEXTUAL_PANEL_MODEL_CONTEXTUAL_PANEL_BROWSER_AGENT_H_
+
+#import "base/scoped_observation.h"
+#import "ios/chrome/browser/shared/model/browser/browser_user_data.h"
+#import "ios/chrome/browser/shared/model/web_state_list/web_state_list_observer.h"
+
+class Browser;
+class WebStateList;
+
+// Browser agent that is responsible for observing the WebStateList to listen to
+// the current contextual panel model for updates, and updating the entrypoint
+// UI accordingly.
+class ContextualPanelBrowserAgent
+    : public WebStateListObserver,
+      public BrowserUserData<ContextualPanelBrowserAgent> {
+ public:
+  ContextualPanelBrowserAgent(const ContextualPanelBrowserAgent&) = delete;
+  ContextualPanelBrowserAgent& operator=(const ContextualPanelBrowserAgent&) =
+      delete;
+
+  ~ContextualPanelBrowserAgent() override;
+
+ private:
+  friend class BrowserUserData<ContextualPanelBrowserAgent>;
+  BROWSER_USER_DATA_KEY_DECL();
+
+  explicit ContextualPanelBrowserAgent(Browser* browser);
+
+  // WebStateListObserver methods.
+  void WebStateListDidChange(WebStateList* web_state_list,
+                             const WebStateListChange& change,
+                             const WebStateListStatus& status) override;
+
+  void WebStateListDestroyed(WebStateList* web_state_list) override;
+
+  // ScopedObservation for WebStateList.
+  base::ScopedObservation<WebStateList, WebStateListObserver>
+      web_state_list_observation_{this};
+};
+
+#endif  // IOS_CHROME_BROWSER_CONTEXTUAL_PANEL_MODEL_CONTEXTUAL_PANEL_BROWSER_AGENT_H_
diff --git a/ios/chrome/browser/contextual_panel/model/contextual_panel_browser_agent.mm b/ios/chrome/browser/contextual_panel/model/contextual_panel_browser_agent.mm
new file mode 100644
index 0000000..98d37909
--- /dev/null
+++ b/ios/chrome/browser/contextual_panel/model/contextual_panel_browser_agent.mm
@@ -0,0 +1,33 @@
+// 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/browser/contextual_panel/model/contextual_panel_browser_agent.h"
+
+#import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h"
+#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
+
+BROWSER_USER_DATA_KEY_IMPL(ContextualPanelBrowserAgent)
+
+ContextualPanelBrowserAgent::ContextualPanelBrowserAgent(Browser* browser) {
+  DCHECK(browser);
+  web_state_list_observation_.Observe(browser->GetWebStateList());
+}
+
+ContextualPanelBrowserAgent::~ContextualPanelBrowserAgent() {
+  web_state_list_observation_.Reset();
+}
+
+#pragma mark - WebStateListObserver
+
+void ContextualPanelBrowserAgent::WebStateListDidChange(
+    WebStateList* web_state_list,
+    const WebStateListChange& change,
+    const WebStateListStatus& status) {
+  // Update the entrypoint's badge status.
+}
+
+void ContextualPanelBrowserAgent::WebStateListDestroyed(
+    WebStateList* web_state_list) {
+  web_state_list_observation_.Reset();
+}
diff --git a/ios/chrome/browser/main/model/BUILD.gn b/ios/chrome/browser/main/model/BUILD.gn
index c06fa5f4..3280126d 100644
--- a/ios/chrome/browser/main/model/BUILD.gn
+++ b/ios/chrome/browser/main/model/BUILD.gn
@@ -20,6 +20,7 @@
     "//base",
     "//components/breadcrumbs/core:status",
     "//ios/chrome/browser/app_launcher/model",
+    "//ios/chrome/browser/contextual_panel/model",
     "//ios/chrome/browser/crash_report/model/breadcrumbs",
     "//ios/chrome/browser/device_sharing/model",
     "//ios/chrome/browser/favicon/model",
diff --git a/ios/chrome/browser/main/model/DEPS b/ios/chrome/browser/main/model/DEPS
index 04acf736d..1a09d00 100644
--- a/ios/chrome/browser/main/model/DEPS
+++ b/ios/chrome/browser/main/model/DEPS
@@ -10,6 +10,7 @@
   "^browser_agent_util.mm": [
     "+ios/chrome/browser/ui/start_surface/start_surface_recent_tab_browser_agent.h",
     "+ios/chrome/browser/app_launcher/model/app_launcher_browser_agent.h",
+    "+ios/chrome/browser/contextual_panel/model/contextual_panel_browser_agent.h",
     "+ios/chrome/browser/crash_report/model/breadcrumbs/breadcrumb_manager_browser_agent.h",
     "+ios/chrome/browser/device_sharing/model/device_sharing_browser_agent.h",
     "+ios/chrome/browser/follow/model/follow_browser_agent.h",
diff --git a/ios/chrome/browser/main/model/browser_agent_util.mm b/ios/chrome/browser/main/model/browser_agent_util.mm
index 42711d7..876f839 100644
--- a/ios/chrome/browser/main/model/browser_agent_util.mm
+++ b/ios/chrome/browser/main/model/browser_agent_util.mm
@@ -7,6 +7,7 @@
 #import "base/feature_list.h"
 #import "components/breadcrumbs/core/breadcrumbs_status.h"
 #import "ios/chrome/browser/app_launcher/model/app_launcher_browser_agent.h"
+#import "ios/chrome/browser/contextual_panel/model/contextual_panel_browser_agent.h"
 #import "ios/chrome/browser/crash_report/model/breadcrumbs/breadcrumb_manager_browser_agent.h"
 #import "ios/chrome/browser/device_sharing/model/device_sharing_browser_agent.h"
 #import "ios/chrome/browser/favicon/model/favicon_browser_agent.h"
@@ -137,6 +138,10 @@
     TabBasedIPHBrowserAgent::CreateForBrowser(browser);
   }
 
+  if (IsContextualPanelEnabled()) {
+    ContextualPanelBrowserAgent::CreateForBrowser(browser);
+  }
+
   // This needs to be called last in case any downstream browser agents need to
   // access upstream agents created earlier in this function.
   ios::provider::AttachBrowserAgents(browser);
diff --git a/ios/chrome/browser/push_notification/model/push_notification_client.h b/ios/chrome/browser/push_notification/model/push_notification_client.h
index 6c2390f..cb5217f 100644
--- a/ios/chrome/browser/push_notification/model/push_notification_client.h
+++ b/ios/chrome/browser/push_notification/model/push_notification_client.h
@@ -77,6 +77,10 @@
 
   ChromeBrowserState* GetLastUsedBrowserState();
 
+  // Returns the first active browser found with scene level
+  // SceneActivationLevelForegroundActive.
+  Browser* GetSceneLevelForegroundActiveBrowser();
+
  private:
   friend class ::CommercePushNotificationClientTest;
   std::vector<GURL> urls_delayed_for_loading_;
@@ -85,10 +89,6 @@
   // GetLastUsedBrowserState().
   raw_ptr<ChromeBrowserState> last_used_browser_state_for_testing_ = nullptr;
 
-  // Returns the first active browser found with scene level
-  // SceneActivationLevelForegroundActive.
-  Browser* GetSceneLevelForegroundActiveBrowser();
-
   // Loads a url in a new tab for a given browser.
   void loadUrlInNewTab(const GURL& url, Browser* browser);
 };
diff --git a/ios/chrome/browser/push_notification/model/push_notification_client.mm b/ios/chrome/browser/push_notification/model/push_notification_client.mm
index 598780a7..f0124d53 100644
--- a/ios/chrome/browser/push_notification/model/push_notification_client.mm
+++ b/ios/chrome/browser/push_notification/model/push_notification_client.mm
@@ -33,6 +33,9 @@
   urls_delayed_for_loading_.clear();
 }
 
+// TODO(crbug.com/1524081): Make functionality that relies on this multi-profile
+// and multi-window safe. That might mean removing this method and finding a
+// different way to determine which window should be used to present UI.
 Browser* PushNotificationClient::GetSceneLevelForegroundActiveBrowser() {
   BrowserList* browser_list =
       BrowserListFactory::GetForBrowserState(GetLastUsedBrowserState());
diff --git a/ios/chrome/browser/tips_notifications/model/BUILD.gn b/ios/chrome/browser/tips_notifications/model/BUILD.gn
index 90fe357..f3a978d 100644
--- a/ios/chrome/browser/tips_notifications/model/BUILD.gn
+++ b/ios/chrome/browser/tips_notifications/model/BUILD.gn
@@ -10,7 +10,9 @@
   deps = [
     ":utils",
     "//base",
+    "//components/feature_engagement/public",
     "//ios/chrome/browser/default_browser/model:utils",
+    "//ios/chrome/browser/feature_engagement/model",
     "//ios/chrome/browser/push_notification/model:push_notification_client",
     "//ios/chrome/browser/shared/coordinator/scene:scene_state_header",
     "//ios/chrome/browser/shared/model/application_context",
@@ -18,6 +20,8 @@
     "//ios/chrome/browser/shared/model/browser_state",
     "//ios/chrome/browser/shared/model/utils",
     "//ios/chrome/browser/shared/public/commands",
+    "//ios/chrome/browser/signin/model",
+    "//ios/chrome/browser/ui/authentication:signin_presenter",
   ]
 }
 
diff --git a/ios/chrome/browser/tips_notifications/model/DEPS b/ios/chrome/browser/tips_notifications/model/DEPS
index 1fc6889..3629d88 100644
--- a/ios/chrome/browser/tips_notifications/model/DEPS
+++ b/ios/chrome/browser/tips_notifications/model/DEPS
@@ -1,4 +1,7 @@
 include_rules = [
   "+ios/chrome/browser/default_browser/model",
+  "+ios/chrome/browser/feature_engagement/model",
   "+ios/chrome/browser/push_notification/model",
+  "+ios/chrome/browser/signin/model",
+  "+ios/chrome/browser/ui/authentication",
 ]
diff --git a/ios/chrome/browser/tips_notifications/model/tips_notification_client.h b/ios/chrome/browser/tips_notifications/model/tips_notification_client.h
index 26829170..23d3ee3f 100644
--- a/ios/chrome/browser/tips_notifications/model/tips_notification_client.h
+++ b/ios/chrome/browser/tips_notifications/model/tips_notification_client.h
@@ -11,7 +11,6 @@
 
 #import "ios/chrome/browser/push_notification/model/push_notification_client.h"
 
-class Browser;
 enum class TipsNotificationType;
 class PrefRegistrySimple;
 
@@ -64,8 +63,11 @@
   // Returns true if a notification of the given `type` should be sent.
   bool ShouldSendNotification(TipsNotificationType type);
 
-  // Returns the first "foreground active" browser, if any.
-  Browser* GetSceneLevelForegroundActiveBrowser();
+  // Returns true if a Signin notification should be sent.
+  bool ShouldSendSignin();
+
+  // Returns true if a WhatsNew notification should be sent.
+  bool ShouldSendWhatsNew();
 
   // Returns `true` if there is foreground active browser.
   bool IsSceneLevelForegroundActive();
@@ -73,6 +75,7 @@
   // Helpers to handle notification interactions.
   void ShowDefaultBrowserPromo();
   void ShowWhatsNew();
+  void ShowSignin();
 
   // Helpers to store state in local state prefs.
   void MarkNotificationTypeSent(TipsNotificationType type);
diff --git a/ios/chrome/browser/tips_notifications/model/tips_notification_client.mm b/ios/chrome/browser/tips_notifications/model/tips_notification_client.mm
index c8a0aec7..8177392 100644
--- a/ios/chrome/browser/tips_notifications/model/tips_notification_client.mm
+++ b/ios/chrome/browser/tips_notifications/model/tips_notification_client.mm
@@ -6,9 +6,12 @@
 
 #import "base/task/bind_post_task.h"
 #import "base/time/time.h"
+#import "components/feature_engagement/public/tracker.h"
 #import "components/prefs/pref_registry_simple.h"
 #import "components/prefs/pref_service.h"
+#import "components/sync/base/features.h"
 #import "ios/chrome/browser/default_browser/model/utils.h"
+#import "ios/chrome/browser/feature_engagement/model/tracker_factory.h"
 #import "ios/chrome/browser/shared/coordinator/scene/scene_state.h"
 #import "ios/chrome/browser/shared/model/application_context/application_context.h"
 #import "ios/chrome/browser/shared/model/browser/browser.h"
@@ -19,7 +22,13 @@
 #import "ios/chrome/browser/shared/public/commands/browser_coordinator_commands.h"
 #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
 #import "ios/chrome/browser/shared/public/commands/promos_manager_commands.h"
+#import "ios/chrome/browser/shared/public/commands/show_signin_command.h"
+#import "ios/chrome/browser/signin/model/authentication_service.h"
+#import "ios/chrome/browser/signin/model/authentication_service_factory.h"
+#import "ios/chrome/browser/signin/model/chrome_account_manager_service.h"
+#import "ios/chrome/browser/signin/model/chrome_account_manager_service_factory.h"
 #import "ios/chrome/browser/tips_notifications/model/utils.h"
+#import "ios/chrome/browser/ui/authentication/signin_presenter.h"
 
 namespace {
 
@@ -36,6 +45,19 @@
   return nil;
 }
 
+// Returns true if signin is allowed / enabled.
+bool IsSigninEnabled(AuthenticationService* auth_service) {
+  switch (auth_service->GetServiceStatus()) {
+    case AuthenticationService::ServiceStatus::SigninForcedByPolicy:
+    case AuthenticationService::ServiceStatus::SigninAllowed:
+      return true;
+    case AuthenticationService::ServiceStatus::SigninDisabledByUser:
+    case AuthenticationService::ServiceStatus::SigninDisabledByPolicy:
+    case AuthenticationService::ServiceStatus::SigninDisabledByInternal:
+      return false;
+  }
+}
+
 }  // namespace
 
 TipsNotificationClient::TipsNotificationClient()
@@ -73,7 +95,7 @@
       ShowWhatsNew();
       break;
     case TipsNotificationType::kSignin:
-      // TODO(crbug.com/1517912) implement Signin interaction.
+      ShowSignin();
       break;
   }
 }
@@ -199,27 +221,29 @@
     case TipsNotificationType::kDefaultBrowser:
       return !IsChromeLikelyDefaultBrowser();
     case TipsNotificationType::kWhatsNew:
-      return true;
+      return ShouldSendWhatsNew();
     case TipsNotificationType::kSignin:
-      return true;
+      return ShouldSendSignin();
   }
 }
 
-Browser* TipsNotificationClient::GetSceneLevelForegroundActiveBrowser() {
-  ChromeBrowserState* browser_state = GetApplicationContext()
-                                          ->GetChromeBrowserStateManager()
-                                          ->GetLastUsedBrowserState();
-  BrowserList* browser_list =
-      BrowserListFactory::GetForBrowserState(browser_state);
-  for (Browser* browser : browser_list->AllRegularBrowsers()) {
-    if (!browser->IsInactive()) {
-      if (browser->GetSceneState().activationLevel ==
-          SceneActivationLevelForegroundActive) {
-        return browser;
-      }
-    }
-  }
-  return nullptr;
+bool TipsNotificationClient::ShouldSendWhatsNew() {
+  Browser* browser = GetSceneLevelForegroundActiveBrowser();
+  feature_engagement::Tracker* tracker =
+      feature_engagement::TrackerFactory::GetForBrowserState(
+          browser->GetBrowserState());
+  return !tracker->HasEverTriggered(
+      feature_engagement::kIPHWhatsNewUpdatedFeature, true);
+}
+
+bool TipsNotificationClient::ShouldSendSignin() {
+  Browser* browser = GetSceneLevelForegroundActiveBrowser();
+  ChromeBrowserState* browser_state = browser->GetBrowserState();
+  AuthenticationService* auth_service =
+      AuthenticationServiceFactory::GetForBrowserState(browser_state);
+
+  return IsSigninEnabled(auth_service) &&
+         !auth_service->HasPrimaryIdentity(signin::ConsentLevel::kSignin);
 }
 
 bool TipsNotificationClient::IsSceneLevelForegroundActive() {
@@ -227,7 +251,7 @@
 }
 
 void TipsNotificationClient::ShowDefaultBrowserPromo() {
-  raw_ptr<Browser> browser = GetSceneLevelForegroundActiveBrowser();
+  Browser* browser = GetSceneLevelForegroundActiveBrowser();
   [HandlerForProtocol(browser->GetCommandDispatcher(), PromosManagerCommands)
       maybeDisplayDefaultBrowserPromo];
 }
@@ -238,6 +262,32 @@
                       BrowserCoordinatorCommands) showWhatsNew];
 }
 
+void TipsNotificationClient::ShowSignin() {
+  Browser* browser = GetSceneLevelForegroundActiveBrowser();
+  AuthenticationOperation operation = AuthenticationOperation::kSigninAndSync;
+  if (base::FeatureList::IsEnabled(
+          syncer::kReplaceSyncPromosWithSignInPromos)) {
+    // If there are identities, kInstantSignin requires less taps.
+    ChromeBrowserState* browser_state = browser->GetBrowserState();
+    operation =
+        ChromeAccountManagerServiceFactory::GetForBrowserState(browser_state)
+                ->HasIdentities()
+            ? AuthenticationOperation::kSigninOnly
+            : AuthenticationOperation::kInstantSignin;
+  }
+  ShowSigninCommand* command = [[ShowSigninCommand alloc]
+      initWithOperation:operation
+               identity:nil
+            accessPoint:signin_metrics::AccessPoint::
+                            ACCESS_POINT_TIPS_NOTIFICATION
+            promoAction:signin_metrics::PromoAction::
+                            PROMO_ACTION_NO_SIGNIN_PROMO
+               callback:nil];
+
+  [HandlerForProtocol(browser->GetCommandDispatcher(), SigninPresenter)
+      showSignin:command];
+}
+
 void TipsNotificationClient::MarkNotificationTypeSent(
     TipsNotificationType type) {
   PrefService* local_state = GetApplicationContext()->GetLocalState();
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.mm b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.mm
index ad4b50f..48b0729e 100644
--- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.mm
+++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.mm
@@ -144,6 +144,7 @@
     case signin_metrics::AccessPoint::
         ACCESS_POINT_RESTORE_PRIMARY_ACCOUNT_ON_PROFILE_LOAD:
     case signin_metrics::AccessPoint::ACCESS_POINT_TAB_ORGANIZATION:
+    case signin_metrics::AccessPoint::ACCESS_POINT_TIPS_NOTIFICATION:
       // Nothing prevents instantiating ConsistencyDefaultAccountViewController
       // with an arbitrary entry point, API-wise. In doubt, no label is a good,
       // generic default that fits all entry points.
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
index dad3052..d7e2475 100644
--- a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
+++ b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
@@ -117,6 +117,7 @@
     case signin_metrics::AccessPoint::
         ACCESS_POINT_RESTORE_PRIMARY_ACCOUNT_ON_PROFILE_LOAD:
     case signin_metrics::AccessPoint::ACCESS_POINT_TAB_ORGANIZATION:
+    case signin_metrics::AccessPoint::ACCESS_POINT_TIPS_NOTIFICATION:
     case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
       return false;
   }
@@ -200,6 +201,7 @@
     case signin_metrics::AccessPoint::
         ACCESS_POINT_RESTORE_PRIMARY_ACCOUNT_ON_PROFILE_LOAD:
     case signin_metrics::AccessPoint::ACCESS_POINT_TAB_ORGANIZATION:
+    case signin_metrics::AccessPoint::ACCESS_POINT_TIPS_NOTIFICATION:
     case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
       NOTREACHED() << "Unexpected value for access point "
                    << static_cast<int>(access_point);
@@ -285,6 +287,7 @@
     case signin_metrics::AccessPoint::
         ACCESS_POINT_RESTORE_PRIMARY_ACCOUNT_ON_PROFILE_LOAD:
     case signin_metrics::AccessPoint::ACCESS_POINT_TAB_ORGANIZATION:
+    case signin_metrics::AccessPoint::ACCESS_POINT_TIPS_NOTIFICATION:
     case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
       NOTREACHED() << "Unexpected value for access point "
                    << static_cast<int>(access_point);
@@ -370,6 +373,7 @@
     case signin_metrics::AccessPoint::
         ACCESS_POINT_RESTORE_PRIMARY_ACCOUNT_ON_PROFILE_LOAD:
     case signin_metrics::AccessPoint::ACCESS_POINT_TAB_ORGANIZATION:
+    case signin_metrics::AccessPoint::ACCESS_POINT_TIPS_NOTIFICATION:
     case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
       NOTREACHED() << "Unexpected value for access point "
                    << static_cast<int>(access_point);
@@ -444,6 +448,7 @@
     case signin_metrics::AccessPoint::
         ACCESS_POINT_RESTORE_PRIMARY_ACCOUNT_ON_PROFILE_LOAD:
     case signin_metrics::AccessPoint::ACCESS_POINT_TAB_ORGANIZATION:
+    case signin_metrics::AccessPoint::ACCESS_POINT_TIPS_NOTIFICATION:
     case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
       return nullptr;
   }
@@ -516,6 +521,7 @@
     case signin_metrics::AccessPoint::
         ACCESS_POINT_RESTORE_PRIMARY_ACCOUNT_ON_PROFILE_LOAD:
     case signin_metrics::AccessPoint::ACCESS_POINT_TAB_ORGANIZATION:
+    case signin_metrics::AccessPoint::ACCESS_POINT_TIPS_NOTIFICATION:
     case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
       return nullptr;
   }
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.h b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.h
index c56283a..3c2c2971 100644
--- a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.h
+++ b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.h
@@ -316,8 +316,6 @@
 extern const char kFollowCountAfterFollow[];
 // After unfollowing a channel.
 extern const char kFollowCountAfterUnfollow[];
-// After engaging with the Following feed.
-extern const char kFollowCountWhenEngaged[];
 
 // Histogram name for last visible card when switching from Discover to
 // Following feed.
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.mm b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.mm
index 808564b..52c672b 100644
--- a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.mm
+++ b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_constants.mm
@@ -88,8 +88,6 @@
     "ContentSuggestions.Feed.WebFeed.FollowCount.AfterFollow";
 const char kFollowCountAfterUnfollow[] =
     "ContentSuggestions.Feed.WebFeed.FollowCount.AfterUnfollow";
-const char kFollowCountWhenEngaged[] =
-    "ContentSuggestions.Feed.WebFeed.FollowCount.Engaged";
 const char kDiscoverIndexWhenSwitchingFeed[] =
     "ContentSuggestions.Feed.CardIndexOnSwitch";
 const char kFollowingIndexWhenSwitchingFeed[] =
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm
index 408ba8e..05b8456f 100644
--- a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm
+++ b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm
@@ -617,7 +617,7 @@
       base::UmaHistogramSparse(kFollowCountAfterUnfollow, followCount);
       break;
     case FollowCountLogReasonEngaged:
-      base::UmaHistogramSparse(kFollowCountWhenEngaged, followCount);
+      // TODO(b/323593501): Report on-feed-engagement follow count.
       break;
   }
 }
diff --git a/ios_internal b/ios_internal
index e0f7bfa..a2e9e8c 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit e0f7bfa6413ecdadaf5626cfe53f3ef58d23c102
+Subproject commit a2e9e8cfd9bd77d59fc632ddb10190e30514189d
diff --git a/media/gpu/sandbox/hardware_video_decoding_sandbox_hook_linux.cc b/media/gpu/sandbox/hardware_video_decoding_sandbox_hook_linux.cc
index 31336072..c28cf6fa 100644
--- a/media/gpu/sandbox/hardware_video_decoding_sandbox_hook_linux.cc
+++ b/media/gpu/sandbox/hardware_video_decoding_sandbox_hook_linux.cc
@@ -7,6 +7,7 @@
 #include <dlfcn.h>
 #include <sys/stat.h>
 
+#include "base/process/process_metrics.h"
 #include "base/strings/stringprintf.h"
 #include "media/gpu/buildflags.h"
 #include "sandbox/policy/linux/bpf_hardware_video_decoding_policy_linux.h"
@@ -185,6 +186,15 @@
   using PolicyType =
       sandbox::policy::HardwareVideoDecodingProcessPolicy::PolicyType;
 
+  // When decoding many video streams at once, the video utility process can hit
+  // FD limits. Increase the limit of maximum FDs allowed to (at least) 8192.
+  // IncreaseFdLimitTo() will only increase the FD limit to a value in:
+  // [max(soft limit, requested value), min(hard limit, requested value)], never
+  // decrease it. See https://man7.org/linux/man-pages/man2/getrlimit.2.html for
+  // context on resource limits.
+  constexpr unsigned int kAttemptedFdSoftLimit = 1u << 13;
+  base::IncreaseFdLimitTo(kAttemptedFdSoftLimit);
+
   const PolicyType policy_type =
       HardwareVideoDecodingProcessPolicy::ComputePolicyType(
           options.use_amd_specific_policies);
diff --git a/pdf/pdfium/pdfium_engine_unittest.cc b/pdf/pdfium/pdfium_engine_unittest.cc
index 95c0191..b880d92 100644
--- a/pdf/pdfium/pdfium_engine_unittest.cc
+++ b/pdf/pdfium/pdfium_engine_unittest.cc
@@ -377,7 +377,7 @@
     // The whole attachment content is too long to do string comparison.
     // Instead, we only verify the checksum value here.
     base::MD5Digest hash;
-    base::MD5Sum(content.data(), content.size(), &hash);
+    base::MD5Sum(content, &hash);
     EXPECT_EQ(kCheckSum, base::MD5DigestToBase16(hash));
   }
 
diff --git a/remoting/host/installer/linux/debian/rules b/remoting/host/installer/linux/debian/rules
index 43b765ba..5caa8d6 100755
--- a/remoting/host/installer/linux/debian/rules
+++ b/remoting/host/installer/linux/debian/rules
@@ -11,3 +11,8 @@
 # virtual desktops, possibly losing unsaved work.
 override_dh_installinit:
 	dh_installinit -r
+
+# Use the older "xz" compression format so the package installs on Debian 11
+# or similar systems - see b/322991199.
+override_dh_builddeb:
+	dh_builddeb -- -Zxz
diff --git a/services/audio/COMMON_METADATA b/services/audio/COMMON_METADATA
index 4a9994d..fc97103d 100644
--- a/services/audio/COMMON_METADATA
+++ b/services/audio/COMMON_METADATA
@@ -1,3 +1,6 @@
-monorail {
+monorail: {
   component: "Internals>Media>Audio"
-}
\ No newline at end of file
+}
+buganizer_public: {
+  component_id: 1456755
+}
diff --git a/services/content/DIR_METADATA b/services/content/DIR_METADATA
index 445f6239..e19d178 100644
--- a/services/content/DIR_METADATA
+++ b/services/content/DIR_METADATA
@@ -1,11 +1,6 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
+monorail: {
   component: "Internals>Services>Content"
-}
\ No newline at end of file
+}
+buganizer_public: {
+  component_id: 1456865
+}
diff --git a/services/data_decoder/DIR_METADATA b/services/data_decoder/DIR_METADATA
index f229b7b..47d3a0e 100644
--- a/services/data_decoder/DIR_METADATA
+++ b/services/data_decoder/DIR_METADATA
@@ -1,12 +1,7 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
+monorail: {
   component: "Internals>Mojo>Bindings"
 }
-team_email: "chrome-security@google.com"
\ No newline at end of file
+team_email: "chrome-security@google.com"
+buganizer_public: {
+  component_id: 1456986
+}
diff --git a/services/device/compute_pressure/cpu_probe_manager.cc b/services/device/compute_pressure/cpu_probe_manager.cc
index 4800bc8..5ce7f567 100644
--- a/services/device/compute_pressure/cpu_probe_manager.cc
+++ b/services/device/compute_pressure/cpu_probe_manager.cc
@@ -19,7 +19,7 @@
 namespace {
 
 using system_cpu::CpuProbe;
-using system_cpu::PressureSample;
+using system_cpu::CpuSample;
 
 // Delta for the state decision hysteresis.
 constexpr double kThresholdDelta = 0.03;
@@ -74,12 +74,11 @@
   // base::Unretained usage is safe here because the callback is only run
   // while `system_cpu_probe_` is alive, and `system_cpu_probe_` is owned by
   // this instance.
-  timer_.Start(
-      FROM_HERE, sampling_interval_,
-      base::BindRepeating(
-          &CpuProbe::RequestSample, system_cpu_probe_->GetWeakPtr(),
-          base::BindRepeating(&CpuProbeManager::OnPressureSampleAvailable,
-                              base::Unretained(this))));
+  timer_.Start(FROM_HERE, sampling_interval_,
+               base::BindRepeating(
+                   &CpuProbe::RequestSample, system_cpu_probe_->GetWeakPtr(),
+                   base::BindRepeating(&CpuProbeManager::OnCpuSampleAvailable,
+                                       base::Unretained(this))));
 
   if (base::FeatureList::IsEnabled(
           features::kComputePressureBreakCalibrationMitigation)) {
@@ -125,8 +124,7 @@
   got_probe_baseline_ = true;
 }
 
-void CpuProbeManager::OnPressureSampleAvailable(
-    std::optional<PressureSample> sample) {
+void CpuProbeManager::OnCpuSampleAvailable(std::optional<CpuSample> sample) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Stop sending data when Stop() was already called.
@@ -140,11 +138,11 @@
 }
 
 mojom::PressureState CpuProbeManager::CalculateState(
-    std::optional<PressureSample> maybe_sample) {
-  const PressureSample sample = maybe_sample.value_or(kUnsupportedValue);
+    std::optional<CpuSample> maybe_sample) {
+  const CpuSample sample = maybe_sample.value_or(kUnsupportedValue);
 
   // TODO(crbug.com/1342528): A more advanced algorithm that calculates
-  // PressureState using PressureSample needs to be determined.
+  // PressureState using CpuSample needs to be determined.
   // At this moment the algorithm is the simplest possible
   // with thresholds defining the state.
   const auto& kStateThresholds = state_randomization_requested_
diff --git a/services/device/compute_pressure/cpu_probe_manager.h b/services/device/compute_pressure/cpu_probe_manager.h
index 15f833c1..7fc3218 100644
--- a/services/device/compute_pressure/cpu_probe_manager.h
+++ b/services/device/compute_pressure/cpu_probe_manager.h
@@ -11,7 +11,7 @@
 #include "base/sequence_checker.h"
 #include "base/thread_annotations.h"
 #include "base/timer/timer.h"
-#include "components/system_cpu/pressure_sample.h"
+#include "components/system_cpu/cpu_sample.h"
 #include "services/device/public/mojom/pressure_update.mojom-shared.h"
 
 namespace system_cpu {
@@ -33,8 +33,8 @@
 class CpuProbeManager {
  public:
   // Return this value when the implementation fails to get a result.
-  static constexpr system_cpu::PressureSample kUnsupportedValue = {
-      .cpu_utilization = 0.0};
+  static constexpr system_cpu::CpuSample kUnsupportedValue = {.cpu_utilization =
+                                                                  0.0};
 
   CpuProbeManager(base::TimeDelta,
                   base::RepeatingCallback<void(mojom::PressureState)>);
@@ -73,11 +73,10 @@
   void OnSamplingStarted();
 
   // Called periodically while the CpuProbe is running.
-  void OnPressureSampleAvailable(std::optional<system_cpu::PressureSample>);
+  void OnCpuSampleAvailable(std::optional<system_cpu::CpuSample>);
 
-  // Calculate PressureState based on optional PressureSample.
-  mojom::PressureState CalculateState(
-      std::optional<system_cpu::PressureSample>);
+  // Calculate PressureState based on optional CpuSample.
+  mojom::PressureState CalculateState(std::optional<system_cpu::CpuSample>);
 
   SEQUENCE_CHECKER(sequence_checker_);
 
@@ -108,9 +107,9 @@
 
   // True if the CpuProbe state will be reported after the next update.
   //
-  // The PressureSample reported by many CpuProbe implementations relies
+  // The CpuSample reported by many CpuProbe implementations relies
   // on the differences observed between two Update() calls. For this reason,
-  // the PressureSample reported after a first Update() call is not
+  // the CpuSample reported after a first Update() call is not
   // reported via `sampling_callback_`.
   bool got_probe_baseline_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
 };
diff --git a/services/device/compute_pressure/cpu_probe_manager_unittest.cc b/services/device/compute_pressure/cpu_probe_manager_unittest.cc
index aa555e9..d6e0dc95 100644
--- a/services/device/compute_pressure/cpu_probe_manager_unittest.cc
+++ b/services/device/compute_pressure/cpu_probe_manager_unittest.cc
@@ -24,8 +24,8 @@
 
 namespace device {
 
+using system_cpu::CpuSample;
 using system_cpu::FakeCpuProbe;
-using system_cpu::PressureSample;
 using system_cpu::StreamingCpuProbe;
 
 class CpuProbeManagerTest : public testing::Test {
@@ -100,7 +100,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   static_cast<FakeCpuProbe*>(cpu_probe_manager_->GetCpuProbeForTesting())
-      ->SetLastSample(absl::make_optional(PressureSample{0.9}));
+      ->SetLastSample(absl::make_optional(CpuSample{0.9}));
   cpu_probe_manager_->EnsureStarted();
   WaitForUpdate();
 
@@ -111,13 +111,13 @@
 TEST_F(CpuProbeManagerTest, EnsureStartedSkipsFirstSample) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  std::vector<PressureSample> samples = {
+  std::vector<CpuSample> samples = {
       // Value right after construction.
-      PressureSample{0.6},
+      CpuSample{0.6},
       // Value after first Update(), should be discarded.
-      PressureSample{0.9},
+      CpuSample{0.9},
       // Value after second Update(), should be reported.
-      PressureSample{0.4},
+      CpuSample{0.4},
   };
 
   base::RunLoop run_loop;
@@ -133,9 +133,8 @@
 TEST_F(CpuProbeManagerTest, CalculateStateValueTooLarge) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  EXPECT_DCHECK_DEATH_WITH(
-      cpu_probe_manager_->CalculateState(PressureSample{1.1}),
-      "unexpected value: 1.1");
+  EXPECT_DCHECK_DEATH_WITH(cpu_probe_manager_->CalculateState(CpuSample{1.1}),
+                           "unexpected value: 1.1");
 }
 
 TEST_F(CpuProbeManagerWithMockTimeTest,
@@ -153,7 +152,7 @@
   cpu_probe_manager_->SetCpuProbeForTesting(std::make_unique<FakeCpuProbe>());
 
   static_cast<FakeCpuProbe*>(cpu_probe_manager_->GetCpuProbeForTesting())
-      ->SetLastSample(PressureSample{0.86});
+      ->SetLastSample(CpuSample{0.86});
   cpu_probe_manager_->EnsureStarted();
   WaitForUpdate();
   EXPECT_THAT(samples_.back(),
@@ -163,7 +162,7 @@
   samples_.clear();
 
   static_cast<FakeCpuProbe*>(cpu_probe_manager_->GetCpuProbeForTesting())
-      ->SetLastSample(PressureSample{0.86});
+      ->SetLastSample(CpuSample{0.86});
   cpu_probe_manager_->EnsureStarted();
   WaitForUpdate();
   // First toggling.
@@ -181,19 +180,19 @@
 TEST_F(CpuProbeManagerTest, EnsureStartedCheckCalculateStateHysteresisUp) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  std::vector<PressureSample> samples = {
+  std::vector<CpuSample> samples = {
       // Value right after construction.
-      PressureSample{0.6},
+      CpuSample{0.6},
       // Value after first Update(), should be discarded.
-      PressureSample{0.9},
+      CpuSample{0.9},
       // kNominal value after should be reported.
-      PressureSample{0.3},
+      CpuSample{0.3},
       // kFair value should be reported.
-      PressureSample{0.6},
+      CpuSample{0.6},
       // kSerious value should be reported.
-      PressureSample{0.9},
+      CpuSample{0.9},
       // kCritical value should be reported.
-      PressureSample{1.0},
+      CpuSample{1.0},
   };
 
   base::RunLoop run_loop;
@@ -213,19 +212,19 @@
 TEST_F(CpuProbeManagerTest, EnsureStartedCheckCalculateStateHysteresisDown) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  std::vector<PressureSample> samples = {
+  std::vector<CpuSample> samples = {
       // Value right after construction.
-      PressureSample{1.0},
+      CpuSample{1.0},
       // Value after first Update(), should be discarded.
-      PressureSample{0.85},
+      CpuSample{0.85},
       // kCritical value after should be reported.
-      PressureSample{1.0},
+      CpuSample{1.0},
       // kSerious value should be reported.
-      PressureSample{0.85},
+      CpuSample{0.85},
       // kFair value should be reported.
-      PressureSample{0.55},
+      CpuSample{0.55},
       // kNominal value should be reported.
-      PressureSample{0.25},
+      CpuSample{0.25},
   };
 
   base::RunLoop run_loop;
@@ -246,19 +245,19 @@
        EnsureStartedCheckCalculateStateHysteresisDownByDelta) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  std::vector<PressureSample> samples = {
+  std::vector<CpuSample> samples = {
       // Value right after construction.
-      PressureSample{1.0},
+      CpuSample{1.0},
       // Value after first Update(), should be discarded.
-      PressureSample{1.0},
+      CpuSample{1.0},
       // kCritical value after should be reported.
-      PressureSample{0.95},
+      CpuSample{0.95},
       // kCritical value should be reported due to hysteresis.
-      PressureSample{0.88},
+      CpuSample{0.88},
       // kFair value should be reported.
-      PressureSample{0.58},
+      CpuSample{0.58},
       // kNominal value should be reported.
-      PressureSample{0.26},
+      CpuSample{0.26},
   };
 
   base::RunLoop run_loop;
@@ -279,17 +278,17 @@
        EnsureStartedCheckCalculateStateHysteresisDownByDeltaTwoState) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  std::vector<PressureSample> samples = {
+  std::vector<CpuSample> samples = {
       // Value right after construction.
-      PressureSample{1.0},
+      CpuSample{1.0},
       // Value after first Update(), should be discarded.
-      PressureSample{1.0},
+      CpuSample{1.0},
       // kCritical value after should be reported.
-      PressureSample{0.95},
+      CpuSample{0.95},
       // kFair value should be reported.
-      PressureSample{0.58},
+      CpuSample{0.58},
       // kFair value should be reported due to hysteresis.
-      PressureSample{0.28},
+      CpuSample{0.28},
   };
 
   base::RunLoop run_loop;
@@ -309,19 +308,19 @@
        EnsureStartedCheckCalculateStateHysteresisUpByDelta) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  std::vector<PressureSample> samples = {
+  std::vector<CpuSample> samples = {
       // Value right after construction.
-      PressureSample{1.0},
+      CpuSample{1.0},
       // Value after first Update(), should be discarded.
-      PressureSample{1.0},
+      CpuSample{1.0},
       // kNominal value after should be reported.
-      PressureSample{0.3},
+      CpuSample{0.3},
       // kFair value should be reported due to hysteresis.
-      PressureSample{0.32},
+      CpuSample{0.32},
       // kSerious value should be reported.
-      PressureSample{0.62},
+      CpuSample{0.62},
       // kCritical value should be reported.
-      PressureSample{0.91},
+      CpuSample{0.91},
   };
 
   base::RunLoop run_loop;
@@ -347,7 +346,7 @@
 
   samples_.clear();
   static_cast<FakeCpuProbe*>(cpu_probe_manager_->GetCpuProbeForTesting())
-      ->SetLastSample(PressureSample{0.9});
+      ->SetLastSample(CpuSample{0.9});
 
   cpu_probe_manager_->EnsureStarted();
   WaitForUpdate();
@@ -363,7 +362,7 @@
   cpu_probe_manager_->Stop();
   samples_.clear();
   static_cast<FakeCpuProbe*>(cpu_probe_manager_->GetCpuProbeForTesting())
-      ->SetLastSample(PressureSample{0.9});
+      ->SetLastSample(CpuSample{0.9});
   // 10ms should be long enough to ensure that all the sampling tasks are done.
   base::PlatformThread::Sleep(base::Milliseconds(10));
 
@@ -381,7 +380,7 @@
 
   samples_.clear();
   static_cast<FakeCpuProbe*>(cpu_probe_manager_->GetCpuProbeForTesting())
-      ->SetLastSample(PressureSample{0.9});
+      ->SetLastSample(CpuSample{0.9});
 
   cpu_probe_manager_->EnsureStarted();
   WaitForUpdate();
@@ -397,7 +396,7 @@
 
   samples_.clear();
   static_cast<FakeCpuProbe*>(cpu_probe_manager_->GetCpuProbeForTesting())
-      ->SetLastSample(PressureSample{0.9});
+      ->SetLastSample(CpuSample{0.9});
   // 10ms should be long enough to ensure that all the sampling tasks are done.
   base::PlatformThread::Sleep(base::Milliseconds(10));
 
diff --git a/services/device/compute_pressure/pressure_manager_impl_unittest.cc b/services/device/compute_pressure/pressure_manager_impl_unittest.cc
index 1c6462b..209979c3 100644
--- a/services/device/compute_pressure/pressure_manager_impl_unittest.cc
+++ b/services/device/compute_pressure/pressure_manager_impl_unittest.cc
@@ -103,7 +103,7 @@
                                 base::Unretained(manager_impl_.get()),
                                 mojom::PressureSource::kCpu));
     auto fake_cpu_probe = std::make_unique<system_cpu::FakeCpuProbe>();
-    fake_cpu_probe->SetLastSample(system_cpu::PressureSample{0.42});
+    fake_cpu_probe->SetLastSample(system_cpu::CpuSample{0.42});
     cpu_probe_manager->SetCpuProbeForTesting(std::move(fake_cpu_probe));
     manager_impl_->SetCpuProbeManagerForTesting(std::move(cpu_probe_manager));
     manager_.reset();
diff --git a/services/preferences/DIR_METADATA b/services/preferences/DIR_METADATA
index 6c50d8e..66623a3 100644
--- a/services/preferences/DIR_METADATA
+++ b/services/preferences/DIR_METADATA
@@ -1,11 +1,6 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
+monorail: {
   component: "Internals>Preferences>Service"
-}
\ No newline at end of file
+}
+buganizer_public: {
+  component_id: 1456864
+}
diff --git a/services/proxy_resolver/DIR_METADATA b/services/proxy_resolver/DIR_METADATA
index 441c330..29ff466 100644
--- a/services/proxy_resolver/DIR_METADATA
+++ b/services/proxy_resolver/DIR_METADATA
@@ -1,11 +1,6 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
+monorail: {
   component: "Internals>Network>Proxy"
-}
\ No newline at end of file
+}
+buganizer_public: {
+  component_id: 1456619
+}
diff --git a/services/resource_coordinator/COMMON_METADATA b/services/resource_coordinator/COMMON_METADATA
index 35eeb9be..1a5eb1d 100644
--- a/services/resource_coordinator/COMMON_METADATA
+++ b/services/resource_coordinator/COMMON_METADATA
@@ -1,4 +1,7 @@
-monorail {
+monorail: {
   component: "Internals>PerformanceManager"
 }
-team_email: "catan-team@chromium.org"
\ No newline at end of file
+team_email: "catan-team@chromium.org"
+buganizer_public: {
+  component_id: 1456682
+}
diff --git a/services/resource_coordinator/memory_instrumentation/COMMON_METADATA b/services/resource_coordinator/memory_instrumentation/COMMON_METADATA
index dd2bdaf6..02385d6 100644
--- a/services/resource_coordinator/memory_instrumentation/COMMON_METADATA
+++ b/services/resource_coordinator/memory_instrumentation/COMMON_METADATA
@@ -1,3 +1,6 @@
-monorail {
+monorail: {
   component: "Internals>Instrumentation>Memory"
-}
\ No newline at end of file
+}
+buganizer_public: {
+  component_id: 1456375
+}
diff --git a/services/shape_detection/DIR_METADATA b/services/shape_detection/DIR_METADATA
index e73c760..45cce42c 100644
--- a/services/shape_detection/DIR_METADATA
+++ b/services/shape_detection/DIR_METADATA
@@ -1,12 +1,7 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
+monorail: {
   component: "Blink>ShapeDetection"
 }
-team_email: "device-dev@chromium.org"
\ No newline at end of file
+team_email: "device-dev@chromium.org"
+buganizer_public: {
+  component_id: 1456183
+}
diff --git a/services/test/data/DIR_METADATA b/services/test/data/DIR_METADATA
index 3974bbe3..7c4af96 100644
--- a/services/test/data/DIR_METADATA
+++ b/services/test/data/DIR_METADATA
@@ -1,11 +1,6 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
+monorail: {
   component: "Test"
-}
\ No newline at end of file
+}
+buganizer_public: {
+  component_id: 1457429
+}
diff --git a/services/tracing/DIR_METADATA b/services/tracing/DIR_METADATA
index 5fac972..73ed78a 100644
--- a/services/tracing/DIR_METADATA
+++ b/services/tracing/DIR_METADATA
@@ -1,11 +1,6 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
+monorail: {
   component: "Speed>Tracing"
-}
\ No newline at end of file
+}
+buganizer_public: {
+  component_id: 1457213
+}
diff --git a/services/video_capture/DIR_METADATA b/services/video_capture/DIR_METADATA
index 085fd4c..8a13538 100644
--- a/services/video_capture/DIR_METADATA
+++ b/services/video_capture/DIR_METADATA
@@ -1,12 +1,7 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
+monorail: {
   component: "Internals>Media>CameraCapture"
 }
 team_email: "media-capture-dev@chromium.org"
+buganizer_public: {
+  component_id: 1456104
+}
diff --git a/services/viz/DIR_METADATA b/services/viz/DIR_METADATA
index 8ff07801..34549ba 100644
--- a/services/viz/DIR_METADATA
+++ b/services/viz/DIR_METADATA
@@ -1,12 +1,7 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
 mixins: "//components/viz/COMMON_METADATA"
-monorail {
+monorail: {
   component: "Internals>Services>Viz"
-}
\ No newline at end of file
+}
+buganizer_public: {
+  component_id: 1457051
+}
diff --git a/testing/buildbot/tryserver.blink.json b/testing/buildbot/tryserver.blink.json
index ad9da04..a305d13 100644
--- a/testing/buildbot/tryserver.blink.json
+++ b/testing/buildbot/tryserver.blink.json
@@ -810,7 +810,7 @@
         "swarming": {
           "dimensions": {
             "cpu": "arm64",
-            "os": "Windows-11-22000"
+            "os": "Windows-11"
           },
           "hard_timeout": 2400,
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -841,7 +841,7 @@
         "swarming": {
           "dimensions": {
             "cpu": "arm64",
-            "os": "Windows-11-22000"
+            "os": "Windows-11"
           },
           "hard_timeout": 2400,
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index d341a4f3..8a0e072 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -6802,11 +6802,13 @@
       },
       'win11-arm64-blink-rel': {
         'mixins': [
-            'win11',
             'arm64'
         ],
         'swarming': {
           'hard_timeout': 900,
+          'dimensions': {
+            'os': 'Windows-11',
+          },
         },
         'test_suites': {
           'isolated_scripts': 'chromium_webkit_isolated_scripts',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 38afe1c..2388e13 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3319,6 +3319,25 @@
             ]
         }
     ],
+    "CastFallbackCRLRevocation": [
+        {
+            "platforms": [
+                "chromeos",
+                "chromeos_lacros",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "EnableCastFallbackCRLRevocation",
+                    "enable_features": [
+                        "CastFallbackCRLRevocation"
+                    ]
+                }
+            ]
+        }
+    ],
     "CastMirroringPlayoutDelayAndBitrate": [
         {
             "platforms": [
@@ -10911,6 +10930,25 @@
             ]
         }
     ],
+    "MaldocaSkipChecks": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "windows",
+                "chromeos_lacros"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "MaldocaSkipChecks"
+                    ]
+                }
+            ]
+        }
+    ],
     "MaxNumDelayableRequestsPerHostPerClient": [
         {
             "platforms": [
diff --git a/third_party/angle b/third_party/angle
index 11eb5eb..e62bd70 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit 11eb5eb7ace91dc15ba341dd864c34a841c9f94b
+Subproject commit e62bd70a6c748559b384f8acb944b602b91869a2
diff --git a/third_party/blink/public/blink_resources.grd b/third_party/blink/public/blink_resources.grd
index fcee227..20e5b49 100644
--- a/third_party/blink/public/blink_resources.grd
+++ b/third_party/blink/public/blink_resources.grd
@@ -56,6 +56,7 @@
         <include name="IDR_LIST_PICKER_JS" file="../renderer/core/html/forms/resources/list_picker.js" type="BINDATA" compress="brotli"/>
       </if>
       <include name="IDR_AUDIO_SPATIALIZATION_COMPOSITE" file="../renderer/platform/audio/resources/Composite.flac" type="BINDATA"/>
+      <include name="IDR_UASTYLE_JSON_DOCUMENT_CSS" file="../renderer/core/css/json-document.css" type="BINDATA" compress="brotli"/>
     </includes>
   </release>
 </grit>
diff --git a/third_party/blink/public/platform/web_theme_engine.h b/third_party/blink/public/platform/web_theme_engine.h
index 833fddd..c9996758 100644
--- a/third_party/blink/public/platform/web_theme_engine.h
+++ b/third_party/blink/public/platform/web_theme_engine.h
@@ -195,6 +195,7 @@
     WebScrollbarOverlayColorTheme scrollbar_theme =
         WebScrollbarOverlayColorTheme::kWebScrollbarOverlayColorThemeDark;
     std::optional<SkColor> thumb_color;
+    bool is_thumb_minimal_mode = false;
   };
 
   struct ScrollbarButtonExtraParams {
diff --git a/third_party/blink/renderer/bindings/core/v8/callback_invoke_helper.cc b/third_party/blink/renderer/bindings/core/v8/callback_invoke_helper.cc
index 0e9d4cca..ddb7f4d 100644
--- a/third_party/blink/renderer/bindings/core/v8/callback_invoke_helper.cc
+++ b/third_party/blink/renderer/bindings/core/v8/callback_invoke_helper.cc
@@ -119,8 +119,7 @@
                         CallbackFunctionWithTaskAttributionBase>::value) {
         parent_task = callback_->GetParentTask();
       }
-      if (parent_task ||
-          !tracker->RunningTask(callback_->CallbackRelevantScriptState())) {
+      if (parent_task || !tracker->RunningTask(isolate)) {
         task_attribution_scope_ = tracker->CreateTaskScope(
             callback_->CallbackRelevantScriptState(), parent_task,
             scheduler::TaskAttributionTracker::TaskScopeType::kCallback);
diff --git a/third_party/blink/renderer/core/css/css_default_style_sheets.cc b/third_party/blink/renderer/core/css/css_default_style_sheets.cc
index dc566b0..77eb320 100644
--- a/third_party/blink/renderer/core/css/css_default_style_sheets.cc
+++ b/third_party/blink/renderer/core/css/css_default_style_sheets.cc
@@ -217,6 +217,17 @@
   return default_view_source_style_.Get();
 }
 
+RuleSet* CSSDefaultStyleSheets::DefaultJSONDocumentStyle() {
+  CHECK(RuntimeEnabledFeatures::PrettyPrintJSONDocumentEnabled());
+  if (!default_json_document_style_) {
+    StyleSheetContents* stylesheet = ParseUASheet(
+        UncompressResourceAsASCIIString(IDR_UASTYLE_JSON_DOCUMENT_CSS));
+    default_json_document_style_ = MakeGarbageCollected<RuleSet>();
+    default_json_document_style_->AddRulesFromSheet(stylesheet, ScreenEval());
+  }
+  return default_json_document_style_.Get();
+}
+
 static void AddTextTrackCSSProperties(StringBuilder* builder,
                                       CSSPropertyID propertyId,
                                       String value) {
@@ -478,6 +489,10 @@
   if (document.IsViewSource() && DefaultViewSourceStyle()) {
     features.Merge(DefaultViewSourceStyle()->Features());
   }
+  if (RuntimeEnabledFeatures::PrettyPrintJSONDocumentEnabled() &&
+      document.IsJSONDocument() && DefaultJSONDocumentStyle()) {
+    features.Merge(DefaultJSONDocumentStyle()->Features());
+  }
 }
 
 void CSSDefaultStyleSheets::Trace(Visitor* visitor) const {
@@ -504,6 +519,7 @@
   visitor->Trace(marker_style_sheet_);
   visitor->Trace(form_controls_not_vertical_style_sheet_);
   visitor->Trace(form_controls_not_vertical_style_text_sheet_);
+  visitor->Trace(default_json_document_style_);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/css_default_style_sheets.h b/third_party/blink/renderer/core/css/css_default_style_sheets.h
index 0f14a635..c4391fd 100644
--- a/third_party/blink/renderer/core/css/css_default_style_sheets.h
+++ b/third_party/blink/renderer/core/css/css_default_style_sheets.h
@@ -67,6 +67,7 @@
   RuleSet* DefaultHtmlQuirksStyle() { return default_html_quirks_style_.Get(); }
   RuleSet* DefaultPrintStyle() { return default_print_style_.Get(); }
   RuleSet* DefaultViewSourceStyle();
+  RuleSet* DefaultJSONDocumentStyle();
   RuleSet* DefaultForcedColorStyle() {
     return default_forced_color_style_.Get();
   }
@@ -147,6 +148,7 @@
   Member<RuleSet> default_pseudo_element_style_;
   Member<RuleSet> default_media_controls_style_;
   Member<RuleSet> default_fullscreen_style_;
+  Member<RuleSet> default_json_document_style_;
   // If new RuleSets are added, make sure to add a new check in
   // VerifyUniversalRuleCount() as universal rule buckets are performance
   // sensitive. At least if the added UA styles are matched against all elements
diff --git a/third_party/blink/renderer/core/css/json-document.css b/third_party/blink/renderer/core/css/json-document.css
new file mode 100644
index 0000000..87f762d
--- /dev/null
+++ b/third_party/blink/renderer/core/css/json-document.css
@@ -0,0 +1,29 @@
+/* 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. */
+
+body > pre {
+  padding-top: 20px;
+  word-wrap: break-word;
+  white-space: pre-wrap;
+}
+.json-formatter-container {
+  position: fixed;
+  top: 0px;
+  width: 100%;
+}
+body {
+  margin: 0;
+}
+.json-formatter-container::-internal-json-formatter-control {
+  width: 100%;
+  font-size: initial;
+  font-family: monospace;
+  user-select: none;
+  background-color: light-dark(rgb(240, 240, 240),rgb(60, 60, 60));
+  border-bottom: 1px solid rgb(187, 187, 187);
+  display: flex;
+  justify-content: flex-start;
+  align-items: center;
+}
+
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
index 2f1c84b6..07b787f 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -920,6 +920,11 @@
     func(default_style_sheets.DefaultForcedColorStyle());
   }
 
+  if (RuntimeEnabledFeatures::PrettyPrintJSONDocumentEnabled() &&
+      GetDocument().IsJSONDocument()) {
+    func(default_style_sheets.DefaultJSONDocumentStyle());
+  }
+
   const auto pseudo_id = GetPseudoId(element, collector);
   if (pseudo_id == kPseudoIdNone) {
     return;
diff --git a/third_party/blink/renderer/core/dom/container_node.cc b/third_party/blink/renderer/core/dom/container_node.cc
index 547a9d6..e79e7cbd 100644
--- a/third_party/blink/renderer/core/dom/container_node.cc
+++ b/third_party/blink/renderer/core/dom/container_node.cc
@@ -1692,16 +1692,16 @@
     return;
   }
 
-  SoftNavigationHeuristics* heuristics =
-      SoftNavigationHeuristics::From(*window);
-  DCHECK(heuristics);
-  // TODO(crbug.com/1521100): This does not filter out updates from isolated
-  // worlds. Should it?
-  if (heuristics->ModifiedDOM()) {
-    if (inserted_node.IsHTMLElement()) {
-      inserted_node.SetIsModifiedBySoftNavigation();
-    } else {
-      SetIsModifiedBySoftNavigation();
+  if (SoftNavigationHeuristics* heuristics =
+          SoftNavigationHeuristics::From(*window)) {
+    // TODO(crbug.com/1521100): This does not filter out updates from isolated
+    // worlds. Should it?
+    if (heuristics->ModifiedDOM()) {
+      if (inserted_node.IsHTMLElement()) {
+        inserted_node.SetIsModifiedBySoftNavigation();
+      } else {
+        SetIsModifiedBySoftNavigation();
+      }
     }
   }
 }
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 251e1fb..ca890ff 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -1942,14 +1942,11 @@
   if (!window) {
     return 0;
   }
-  LocalFrame* frame = window->GetFrame();
-  if (!frame || !frame->IsMainFrame()) {
-    return 0;
+  if (SoftNavigationHeuristics* heuristics =
+          SoftNavigationHeuristics::From(*window)) {
+    return heuristics->SoftNavigationCount();
   }
-  SoftNavigationHeuristics* heuristics =
-      SoftNavigationHeuristics::From(*window);
-  DCHECK(heuristics);
-  return heuristics->SoftNavigationCount();
+  return 0;
 }
 
 bool Document::hidden() const {
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 5fb40f6..3042b35a 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -613,6 +613,8 @@
     is_view_source_ = is_view_source;
   }
 
+  virtual bool IsJSONDocument() const { return false; }
+
   // WebXR DOM Overlay support, cf https://immersive-web.github.io/dom-overlays/
   // True if there's an ongoing "immersive-ar" WebXR session with a DOM Overlay
   // element active. This is needed for applying the :xr-overlay pseudoclass
diff --git a/third_party/blink/renderer/core/dom/events/event_dispatcher.cc b/third_party/blink/renderer/core/dom/events/event_dispatcher.cc
index c69c8d03..b0b809a 100644
--- a/third_party/blink/renderer/core/dom/events/event_dispatcher.cc
+++ b/third_party/blink/renderer/core/dom/events/event_dispatcher.cc
@@ -224,16 +224,19 @@
   std::unique_ptr<SoftNavigationEventScope> soft_navigation_scope;
   if ((is_click || is_unfocused_keyboard_event) && event_->isTrusted() &&
       frame) {
-    if (window && frame->IsMainFrame() &&
+    if (window &&
         base::FeatureList::IsEnabled(features::kSoftNavigationDetection)) {
-      bool is_new_interaction =
-          is_click || (event_->type() == event_type_names::kKeydown);
-      soft_navigation_scope = std::make_unique<SoftNavigationEventScope>(
-          SoftNavigationHeuristics::From(*window),
-          is_unfocused_keyboard_event
-              ? SoftNavigationHeuristics::EventScopeType::kKeyboard
-              : SoftNavigationHeuristics::EventScopeType::kClick,
-          is_new_interaction);
+      if (SoftNavigationHeuristics* heuristics =
+              SoftNavigationHeuristics::From(*window)) {
+        bool is_new_interaction =
+            is_click || (event_->type() == event_type_names::kKeydown);
+        soft_navigation_scope = std::make_unique<SoftNavigationEventScope>(
+            heuristics,
+            is_unfocused_keyboard_event
+                ? SoftNavigationHeuristics::EventScopeType::kKeyboard
+                : SoftNavigationHeuristics::EventScopeType::kClick,
+            is_new_interaction);
+      }
     }
     // A genuine mouse click cannot be triggered by script so we don't expect
     // there are any script in the stack.
diff --git a/third_party/blink/renderer/core/fetch/fetch_manager.cc b/third_party/blink/renderer/core/fetch/fetch_manager.cc
index c7575dc..89ce85470 100644
--- a/third_party/blink/renderer/core/fetch/fetch_manager.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_manager.cc
@@ -30,7 +30,6 @@
 #include "services/network/public/mojom/url_loader_factory.mojom-blink.h"
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/public/common/features.h"
-#include "third_party/blink/public/common/scheme_registry.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
 #include "third_party/blink/public/mojom/loader/code_cache.mojom-blink.h"
 #include "third_party/blink/public/mojom/loader/fetch_later.mojom-blink.h"
@@ -616,9 +615,7 @@
   response_http_status_code_ = response.HttpStatusCode();
 
   if (response.MimeType() == "application/wasm" &&
-      (response.CurrentRequestUrl().ProtocolIsInHTTPFamily() ||
-       CommonSchemeRegistry::IsExtensionScheme(
-           response.CurrentRequestUrl().Protocol().Ascii()))) {
+      response.CurrentRequestUrl().ProtocolIsInHTTPFamily()) {
     // We create a ScriptCachedMetadataHandler for WASM modules.
     cached_metadata_handler_ =
         MakeGarbageCollected<ScriptCachedMetadataHandler>(
diff --git a/third_party/blink/renderer/core/frame/history.cc b/third_party/blink/renderer/core/frame/history.cc
index caac614..730346b 100644
--- a/third_party/blink/renderer/core/frame/history.cc
+++ b/third_party/blink/renderer/core/frame/history.cc
@@ -57,10 +57,11 @@
                      const String& url) {
   DCHECK(window);
   DCHECK(window->GetFrame());
-  if (window->GetFrame()->IsMainFrame() && window->Url() != url) {
-    SoftNavigationHeuristics* heuristics =
-        SoftNavigationHeuristics::From(*window);
-    heuristics->SameDocumentNavigationStarted();
+  if (window->Url() != url) {
+    if (SoftNavigationHeuristics* heuristics =
+            SoftNavigationHeuristics::From(*window)) {
+      heuristics->SameDocumentNavigationStarted();
+    }
   }
 }
 }  // namespace
@@ -229,7 +230,7 @@
     scheduler::TaskAttributionInfo* task = nullptr;
     if (tracker && script_state->World().IsMainWorld() &&
         frame->IsOutermostMainFrame()) {
-      task = tracker->RunningTask(script_state);
+      task = tracker->RunningTask(script_state->GetIsolate());
       tracker->AddSameDocumentNavigationTask(task);
     }
     DCHECK(frame->Client());
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index 8b2ba04..22eb2e6 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -177,7 +177,7 @@
   ScriptState* script_state = callback->CallbackRelevantScriptState();
   auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker();
   if (tracker && script_state->World().IsMainWorld()) {
-    callback->SetParentTask(tracker->RunningTask(script_state));
+    callback->SetParentTask(tracker->RunningTask(script_state->GetIsolate()));
   }
 }
 
@@ -907,9 +907,8 @@
 void LocalDOMWindow::EnqueueHashchangeEvent(const String& old_url,
                                             const String& new_url) {
   DCHECK(GetFrame());
-  if (GetFrame()->IsMainFrame()) {
-    SoftNavigationHeuristics* heuristics =
-        SoftNavigationHeuristics::From(*this);
+  if (SoftNavigationHeuristics* heuristics =
+          SoftNavigationHeuristics::From(*this)) {
     heuristics->SameDocumentNavigationStarted();
   }
   // https://html.spec.whatwg.org/C/#history-traversal
diff --git a/third_party/blink/renderer/core/html/json_document.cc b/third_party/blink/renderer/core/html/json_document.cc
index 481a5b8d..2cb8c92 100644
--- a/third_party/blink/renderer/core/html/json_document.cc
+++ b/third_party/blink/renderer/core/html/json_document.cc
@@ -18,7 +18,6 @@
 #include "third_party/blink/renderer/core/html/html_html_element.h"
 #include "third_party/blink/renderer/core/html/html_meta_element.h"
 #include "third_party/blink/renderer/core/html/html_pre_element.h"
-#include "third_party/blink/renderer/core/html/html_style_element.h"
 #include "third_party/blink/renderer/core/html/parser/html_document_parser.h"
 #include "third_party/blink/renderer/core/input_type_names.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
@@ -28,49 +27,6 @@
 
 namespace blink {
 
-namespace {
-// TODO(crbug.com/1512214): Move Inline CSS to UA stylesheet
-String GetStyleSheetContentForShadowDOM() {
-  return R"CSS(
-    .json-formatter-control {
-      width: 100%;
-      font-size: initial;
-      font-family: monospace;
-      user-select: none;
-      background-color: rgb(240,240,240);
-      border-bottom: 1px solid rgb(187, 187, 187);
-      display: flex;
-      justify-content: flex-start;
-      align-items: center;
-    }
-    @media (prefers-color-scheme: dark) {
-      .json-formatter-control {
-        background-color: rgb(60, 60, 60);
-      }
-    }
-  )CSS";
-}
-
-String GetStyleSheetContentForDocument() {
-  return R"(
-    body > pre {
-      padding-top: 20px;
-      word-wrap: break-word;
-      white-space: pre-wrap;
-    }
-    .json-formatter-container {
-      position: fixed;
-      top: 0px;
-      width: 100%;
-    }
-    body {
-      margin: 0;
-    }
-  )";
-}
-
-}  // namespace
-
 class PrettyPrintJSONListener : public NativeEventListener {
  public:
   PrettyPrintJSONListener(HTMLPreElement* pre, HTMLInputElement* checkbox)
@@ -140,10 +96,6 @@
     head->ParserAppendChild(meta);
     head->ParserAppendChild(meta_charset);
     html->ParserAppendChild(head);
-    auto* documentStyle =
-        MakeGarbageCollected<HTMLStyleElement>(*GetDocument());
-    documentStyle->setTextContent(GetStyleSheetContentForDocument());
-    head->ParserAppendChild(documentStyle);
     auto* body = MakeGarbageCollected<HTMLBodyElement>(*GetDocument());
     html->ParserAppendChild(body);
     pre_ = MakeGarbageCollected<HTMLPreElement>(html_names::kPreTag,
@@ -153,8 +105,7 @@
     label->ParserAppendChild(Text::Create(
         *GetDocument(), WTF::AtomicString(Locale::DefaultLocale().QueryString(
                             IDS_PRETTY_PRINT_JSON))));
-    label->setAttribute(html_names::kClassAttr,
-                        AtomicString("json-formatter-control"));
+    label->SetShadowPseudoId(AtomicString("-internal-json-formatter-control"));
     auto* checkbox = MakeGarbageCollected<HTMLInputElement>(*GetDocument());
     checkbox->setAttribute(html_names::kTypeAttr, input_type_names::kCheckbox);
     checkbox->addEventListener(
@@ -171,9 +122,6 @@
     auto* form = MakeGarbageCollected<HTMLFormElement>(*GetDocument());
     form->setAttribute(html_names::kAutocompleteAttr, AtomicString("off"));
     form->ParserAppendChild(label);
-    HTMLStyleElement* style =
-        MakeGarbageCollected<HTMLStyleElement>(*GetDocument());
-    style->setTextContent(GetStyleSheetContentForShadowDOM());
     // See crbug.com/1485052: the div is fixed-positioned to maintain the
     // DOM tree structure and avoid compatibility problems with extensions.
     auto* div = MakeGarbageCollected<HTMLDivElement>(*GetDocument());
@@ -181,7 +129,6 @@
                       AtomicString("json-formatter-container"));
 
     ShadowRoot& shadow_root = div->EnsureUserAgentShadowRoot();
-    shadow_root.ParserAppendChild(style);
     shadow_root.ParserAppendChild(form);
     body->ParserAppendChild(pre_);
     body->ParserAppendChild(div);
diff --git a/third_party/blink/renderer/core/html/json_document.h b/third_party/blink/renderer/core/html/json_document.h
index bde2f27f..7a8454c 100644
--- a/third_party/blink/renderer/core/html/json_document.h
+++ b/third_party/blink/renderer/core/html/json_document.h
@@ -12,6 +12,7 @@
 class JSONDocument : public HTMLDocument {
  public:
   JSONDocument(const DocumentInit&);
+  bool IsJSONDocument() const override { return true; }
 
  private:
   DocumentParser* CreateParser() override;
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index 417b0bc7..73b9c881 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -1003,7 +1003,7 @@
       base::FeatureList::IsEnabled(features::kSoftNavigationDetection)) {
     CHECK(frame_->DomWindow());
     heuristics = SoftNavigationHeuristics::From(*frame_->DomWindow());
-    if (is_browser_initiated) {
+    if (is_browser_initiated && heuristics) {
       // For browser-initiated navigations, we never started the soft
       // navigation (as this is the first we hear of it in the renderer). We
       // need to do that now.
diff --git a/third_party/blink/renderer/core/messaging/message_port.cc b/third_party/blink/renderer/core/messaging/message_port.cc
index 2fa03e0..9a12b88 100644
--- a/third_party/blink/renderer/core/messaging/message_port.cc
+++ b/third_party/blink/renderer/core/messaging/message_port.cc
@@ -140,7 +140,8 @@
   if (auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker();
       initially_entangled_port_ && tracker &&
       script_state->World().IsMainWorld()) {
-    scheduler::TaskAttributionInfo* task = tracker->RunningTask(script_state);
+    scheduler::TaskAttributionInfo* task =
+        tracker->RunningTask(script_state->GetIsolate());
     if (task) {
       // Since `initially_entangled_port_` is not nullptr, neither should be
       // `post_message_task_container_`.
diff --git a/third_party/blink/renderer/core/navigation_api/navigation_api.cc b/third_party/blink/renderer/core/navigation_api/navigation_api.cc
index 23f24be9..c556418 100644
--- a/third_party/blink/renderer/core/navigation_api/navigation_api.cc
+++ b/third_party/blink/renderer/core/navigation_api/navigation_api.cc
@@ -613,14 +613,14 @@
   LocalFrame* frame = window_->GetFrame();
   scheduler::TaskAttributionInfo* task = nullptr;
   if (frame->IsOutermostMainFrame()) {
-    SoftNavigationHeuristics* heuristics =
-        SoftNavigationHeuristics::From(*window_);
-
-    heuristics->SameDocumentNavigationStarted();
-    auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker();
-    if (tracker && script_state->World().IsMainWorld()) {
-      task = tracker->RunningTask(script_state->GetIsolate());
-      tracker->AddSameDocumentNavigationTask(task);
+    if (SoftNavigationHeuristics* heuristics =
+            SoftNavigationHeuristics::From(*window_)) {
+      heuristics->SameDocumentNavigationStarted();
+      auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker();
+      if (tracker && script_state->World().IsMainWorld()) {
+        task = tracker->RunningTask(script_state->GetIsolate());
+        tracker->AddSameDocumentNavigationTask(task);
+      }
     }
   }
   frame->GetLocalFrameHostRemote().NavigateToNavigationApiKey(
@@ -834,16 +834,16 @@
   // SoftNavigationEventScope until the event handler runs.
   std::unique_ptr<SoftNavigationEventScope> soft_navigation_scope;
   if (base::FeatureList::IsEnabled(features::kSoftNavigationDetection)) {
-    auto* soft_navigation_heuristics = SoftNavigationHeuristics::From(*window_);
-    if (soft_navigation_heuristics && init->userInitiated() &&
-        !init->downloadRequest() && init->canIntercept()) {
-      // If these conditions are met, create a SoftNavigationEventScope to
-      // consider this a "user initiated click", and the dispatched event
-      // handlers as potential soft navigation tasks.
-      soft_navigation_scope = std::make_unique<SoftNavigationEventScope>(
-          soft_navigation_heuristics,
-          SoftNavigationHeuristics::EventScopeType::kNavigate,
-          /*is_new_interaction=*/true);
+    if (auto* heuristics = SoftNavigationHeuristics::From(*window_)) {
+      if (init->userInitiated() && !init->downloadRequest() &&
+          init->canIntercept()) {
+        // If these conditions are met, create a SoftNavigationEventScope to
+        // consider this a "user initiated click", and the dispatched event
+        // handlers as potential soft navigation tasks.
+        soft_navigation_scope = std::make_unique<SoftNavigationEventScope>(
+            heuristics, SoftNavigationHeuristics::EventScopeType::kNavigate,
+            /*is_new_interaction=*/true);
+      }
     }
   }
   auto* navigate_event = NavigateEvent::Create(
diff --git a/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.cc b/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.cc
index d36f700..50c9486 100644
--- a/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.cc
+++ b/third_party/blink/renderer/core/paint/timing/image_paint_timing_detector.cc
@@ -63,10 +63,10 @@
                                         Node* node) {
   LocalFrame& frame = frame_view->GetFrame();
   if (LocalDOMWindow* window = frame.DomWindow()) {
-    if (SoftNavigationHeuristics* soft_navigation =
+    if (SoftNavigationHeuristics* heuristics =
             SoftNavigationHeuristics::From(*window)) {
-      soft_navigation->RecordPaint(&frame, rect.size().GetArea(),
-                                   node->IsModifiedBySoftNavigation());
+      heuristics->RecordPaint(&frame, rect.size().GetArea(),
+                              node->IsModifiedBySoftNavigation());
     }
   }
 }
diff --git a/third_party/blink/renderer/core/paint/timing/text_paint_timing_detector.cc b/third_party/blink/renderer/core/paint/timing/text_paint_timing_detector.cc
index 95e5c7e..8007162 100644
--- a/third_party/blink/renderer/core/paint/timing/text_paint_timing_detector.cc
+++ b/third_party/blink/renderer/core/paint/timing/text_paint_timing_detector.cc
@@ -186,9 +186,9 @@
 
   LocalFrame& frame = frame_view_->GetFrame();
   if (LocalDOMWindow* window = frame.DomWindow()) {
-    if (SoftNavigationHeuristics* soft_navigation =
+    if (SoftNavigationHeuristics* heuristics =
             SoftNavigationHeuristics::From(*window)) {
-      soft_navigation->RecordPaint(
+      heuristics->RecordPaint(
           &frame, mapped_visual_rect.size().GetArea(),
           aggregator.GetNode()->IsModifiedBySoftNavigation());
     }
diff --git a/third_party/blink/renderer/core/script/script_loader.cc b/third_party/blink/renderer/core/script/script_loader.cc
index 7dac235..123621d 100644
--- a/third_party/blink/renderer/core/script/script_loader.cc
+++ b/third_party/blink/renderer/core/script/script_loader.cc
@@ -95,7 +95,7 @@
   if (!script_state || !script_state->World().IsMainWorld() || !tracker) {
     return nullptr;
   }
-  return tracker->RunningTask(script_state);
+  return tracker->RunningTask(script_state->GetIsolate());
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/core/scroll/scrollbar.cc b/third_party/blink/renderer/core/scroll/scrollbar.cc
index 1e33d17..86afc46 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar.cc
+++ b/third_party/blink/renderer/core/scroll/scrollbar.cc
@@ -516,6 +516,11 @@
     scrollable_area_->MouseExitedScrollbar(*this);
   SetHoveredPart(kNoPart);
   if (theme_.UsesFluentOverlayScrollbars() && scrollable_area_) {
+    // If the mouse was hovering over the track and leaves the scrollbar, the
+    // call to `SetHoveredPart(kNoPart)` will only invalidate the paint for the
+    // track. Overlay Fluent scrollbars always need to invalidate the thumb to
+    // change between solid/transparent colors.
+    SetNeedsPaintInvalidation(kThumbPart);
     scrollable_area_->GetLayoutBox()
         ->GetFrameView()
         ->SetPaintArtifactCompositorNeedsUpdate();
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme_fluent.cc b/third_party/blink/renderer/core/scroll/scrollbar_theme_fluent.cc
index 3d7dc5d..95734f5 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_theme_fluent.cc
+++ b/third_party/blink/renderer/core/scroll/scrollbar_theme_fluent.cc
@@ -169,15 +169,9 @@
   if (scrollbar.ScrollbarThumbColor().has_value()) {
     scrollbar_thumb.thumb_color =
         scrollbar.ScrollbarThumbColor().value().toSkColor4f().toSkColor();
-  } else if (scrollbar.IsFluentOverlayScrollbarMinimalMode() &&
-             WebThemeEngineHelper::GetNativeThemeEngine()->GetForcedColors() ==
-                 ForcedColors::kNone) {
-    const bool dark_mode =
-        (scrollbar.UsedColorScheme() == mojom::blink::ColorScheme::kDark);
-    // TODO(crbug.com/1518945): Find a better way to define these colors.
-    scrollbar_thumb.thumb_color = dark_mode ? SkColorSetA(SK_ColorWHITE, 0x8B)
-                                            : SkColorSetA(SK_ColorBLACK, 0x72);
   }
+  scrollbar_thumb.is_thumb_minimal_mode =
+      scrollbar.IsFluentOverlayScrollbarMinimalMode();
   return scrollbar_thumb;
 }
 
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc
index 16007223..9ecadd0 100644
--- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc
+++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.cc
@@ -95,13 +95,18 @@
 
 SoftNavigationHeuristics* SoftNavigationHeuristics::From(
     LocalDOMWindow& window) {
-  // TODO(yoav): Ensure all callers don't have spurious IsMainFrame checks.
   if (!window.GetFrame()->IsMainFrame()) {
     return nullptr;
   }
   SoftNavigationHeuristics* heuristics =
       Supplement<LocalDOMWindow>::From<SoftNavigationHeuristics>(window);
   if (!heuristics) {
+    if (Document* document = window.document()) {
+      // Don't measure soft navigations in devtools.
+      if (document->Url().ProtocolIs("devtools")) {
+        return nullptr;
+      }
+    }
     heuristics = MakeGarbageCollected<SoftNavigationHeuristics>(window);
     ProvideTo(window, heuristics);
   }
@@ -340,6 +345,16 @@
     LocalFrame* frame,
     uint64_t painted_area,
     bool is_modified_by_soft_navigation) {
+  if (!initial_interaction_encountered_ && is_modified_by_soft_navigation) {
+    // TODO(crbug.com/41496928): Paints can be reported for Nodes which had
+    // is_modified... flag set but a different instance of a
+    // SoftNavigationHeuristics class.  This happens when Nodes are re-parented
+    // into a new document, e.g. into an open() window.
+    // Instead of just ignoring the worst case of this issue as we do here, we
+    // should support this use case.  Either by clearing the flag on nodes, or,
+    // by staring an interaction/navigation id on Node, rathan than boolean.
+    return;
+  }
   if (!initial_interaction_encountered_) {
     // We haven't seen an interaction yet, so we are still measuring initial
     // paint area.
@@ -538,9 +553,7 @@
 }
 
 void SoftNavigationHeuristics::OnCreateTaskScope(
-    scheduler::TaskAttributionInfo& task,
-    ScriptState* script_state) {
-  CHECK(script_state);
+    scheduler::TaskAttributionInfo& task) {
   ThreadScheduler* scheduler = ThreadScheduler::Current();
   CHECK(scheduler);
   auto* tracker = scheduler->GetTaskAttributionTracker();
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h
index a147eb3..eca80fa 100644
--- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h
+++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics.h
@@ -72,8 +72,7 @@
   uint32_t SoftNavigationCount() { return soft_navigation_count_; }
 
   // TaskAttributionTracker::Observer's implementation.
-  void OnCreateTaskScope(scheduler::TaskAttributionInfo&,
-                         ScriptState*) override;
+  void OnCreateTaskScope(scheduler::TaskAttributionInfo&) override;
   ExecutionContext* GetExecutionContext() override;
 
   void RecordPaint(LocalFrame*,
diff --git a/third_party/blink/renderer/core/timing/soft_navigation_heuristics_test.cc b/third_party/blink/renderer/core/timing/soft_navigation_heuristics_test.cc
index 432da19..348e19b 100644
--- a/third_party/blink/renderer/core/timing/soft_navigation_heuristics_test.cc
+++ b/third_party/blink/renderer/core/timing/soft_navigation_heuristics_test.cc
@@ -141,7 +141,7 @@
         /*is_new_interaction=*/true);
     std::unique_ptr<TaskScope> task_scope = tracker->CreateTaskScope(
         script_state, /*parent_task=*/nullptr, TaskScopeType::kCallback);
-    root_task = tracker->RunningTask(script_state);
+    root_task = tracker->RunningTask(script_state->GetIsolate());
   }
   EXPECT_TRUE(root_task);
   EXPECT_GT(heuristics->GetLastInteractionTaskIdForTest(), 0u);
@@ -151,7 +151,7 @@
   {
     std::unique_ptr<TaskScope> task_scope = tracker->CreateTaskScope(
         script_state, root_task, TaskScopeType::kCallback);
-    descendant_task = tracker->RunningTask(script_state);
+    descendant_task = tracker->RunningTask(script_state->GetIsolate());
   }
   EXPECT_TRUE(descendant_task);
 
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_supplement.cc b/third_party/blink/renderer/core/view_transition/view_transition_supplement.cc
index 5636071..545a0b6 100644
--- a/third_party/blink/renderer/core/view_transition/view_transition_supplement.cc
+++ b/third_party/blink/renderer/core/view_transition/view_transition_supplement.cc
@@ -99,7 +99,7 @@
     // Set the parent task ID if we're not in an extension task (as extensions
     // are not currently supported in TaskAttributionTracker).
     if (tracker && script_state->World().IsMainWorld()) {
-      callback->SetParentTask(tracker->RunningTask(script_state));
+      callback->SetParentTask(tracker->RunningTask(script_state->GetIsolate()));
     }
   }
   return supplement->StartTransition(document, callback, types,
diff --git a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
index e016d884..58d8d1ae 100644
--- a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
+++ b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
@@ -1065,8 +1065,7 @@
     if (world_ && world_->IsMainWorld()) {
       if (auto* tracker =
               ThreadScheduler::Current()->GetTaskAttributionTracker()) {
-        parent_task_ =
-            tracker->RunningTask(ToScriptStateForMainWorld(&execution_context));
+        parent_task_ = tracker->RunningTask(execution_context.GetIsolate());
       }
     }
     async_task_context_.Schedule(&execution_context, "XMLHttpRequest.send");
@@ -2146,7 +2145,7 @@
   //
   // TODO(crbug.com/1439971): Make this safe to do or move the logic into the
   // task attribution implementation.
-  if (tracker->RunningTask(script_state) == parent_task_.Get()) {
+  if (tracker->RunningTask(script_state->GetIsolate()) == parent_task_.Get()) {
     return nullptr;
   }
   return tracker->CreateTaskScope(
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc
index 932a816..6a184c5 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -1350,15 +1350,16 @@
     SerializeColorAttributes(node_data);  // Blends using all nodes' values.
 
   if (accessibility_mode.has_mode(ui::AXMode::kScreenReader) ||
-      accessibility_mode.has_mode(ui::AXMode::kPDF)) {
+      accessibility_mode.has_mode(ui::AXMode::kPDFPrinting)) {
     SerializeLangAttribute(node_data);  // Propagates using all nodes' values.
   }
 
   // Always try to serialize child tree ids.
   SerializeChildTreeID(node_data);
 
-  if (!accessibility_mode.has_mode(ui::AXMode::kPDF))
+  if (!accessibility_mode.has_mode(ui::AXMode::kPDFPrinting)) {
     SerializeBoundingBoxAttributes(*node_data);
+  }
 
   // Return early. The following attributes are unnecessary for ignored nodes.
   // Exception: focusable ignored nodes are fully serialized, so that reasonable
@@ -1383,7 +1384,7 @@
 
   SerializeUnignoredAttributes(node_data, accessibility_mode);
 
-  if (accessibility_mode.has_mode(ui::AXMode::kPDF)) {
+  if (accessibility_mode.has_mode(ui::AXMode::kPDFPrinting)) {
     SerializeNameAndDescriptionAttributes(accessibility_mode, node_data);
     // Return early. None of the following attributes are needed for PDFs.
     return;
@@ -2219,7 +2220,7 @@
   }
 
   if (accessibility_mode.has_mode(ui::AXMode::kScreenReader) ||
-      accessibility_mode.has_mode(ui::AXMode::kPDF)) {
+      accessibility_mode.has_mode(ui::AXMode::kPDFPrinting)) {
     // The DOMNodeID from Blink. Currently only populated when using
     // the accessibility tree for PDF exporting. Warning, this is totally
     // unrelated to the accessibility node ID, or the ID attribute for an
@@ -2240,7 +2241,7 @@
     SerializeTableAttributes(node_data);
   }
 
-  if (accessibility_mode.has_mode(ui::AXMode::kPDF)) {
+  if (accessibility_mode.has_mode(ui::AXMode::kPDFPrinting)) {
     // Return early. None of the following attributes are needed for PDFs.
     return;
   }
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
index 10c0499..03e73ba6 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
@@ -1854,7 +1854,16 @@
   scoped_refptr<Image> image;
   gfx::SizeF default_object_size(Width(), Height());
   SourceImageStatus source_image_status = kInvalidSourceImageStatus;
-  if (!image_source->IsVideoElement()) {
+  if (image_source->IsVideoElement()) {
+    if (!static_cast<HTMLVideoElement*>(image_source)
+             ->HasAvailableVideoFrame()) {
+      return;
+    }
+  } else if (image_source->IsVideoFrame()) {
+    if (!static_cast<VideoFrame*>(image_source)->frame()) {
+      return;
+    }
+  } else {
     image = image_source->GetSourceImageForCanvas(
         FlushReason::kDrawImage, &source_image_status, default_object_size);
     if (source_image_status == kUndecodableSourceImageStatus) {
@@ -1871,9 +1880,6 @@
     }
     if (!image || !image->width() || !image->height())
       return;
-  } else {
-    if (!static_cast<HTMLVideoElement*>(image_source)->HasAvailableVideoFrame())
-      return;
   }
 
   if (!std::isfinite(dx) || !std::isfinite(dy) || !std::isfinite(dw) ||
diff --git a/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.cc b/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.cc
index a7223fcb..c89695c 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.cc
+++ b/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.cc
@@ -905,54 +905,7 @@
       // TODO(https://crbug.com/1416939): make sure the Digital Credentials API
       // works well with the Multiple IdP API.
       !blink::RuntimeEnabledFeatures::FedCmMultipleIdentityProvidersEnabled()) {
-    auto mojo_provider = DigitalCredentialProvider::New();
-    if (provider.holder()->hasParams()) {
-      HashMap<String, String> params;
-      for (const auto& pair : provider.holder()->params()) {
-        params.Set(pair.first, pair.second);
-      }
-      mojo_provider->params = std::move(params);
-    }
-    if (provider.holder()->hasSelector()) {
-      mojo_provider->selector = DigitalCredentialSelector::New();
-      if (provider.holder()->selector()->hasFormat()) {
-        mojo_provider->selector->format =
-            provider.holder()->selector()->format();
-      }
-      if (provider.holder()->selector()->hasDoctype()) {
-        mojo_provider->selector->doctype =
-            provider.holder()->selector()->doctype();
-      }
-      if (provider.holder()->selector()->hasFields()) {
-        WTF::Vector<DigitalCredentialFieldRequirementPtr> fields;
-        for (auto element : provider.holder()->selector()->fields()) {
-          auto requested_element = DigitalCredentialFieldRequirement::New();
-          if (element->IsString()) {
-            requested_element->name = element->GetAsString();
-          } else {
-            requested_element->name =
-                element->GetAsDigitalCredentialFieldRequirement()->name();
-            if (element->GetAsDigitalCredentialFieldRequirement()
-                    ->hasEquals()) {
-              requested_element->equals =
-                  element->GetAsDigitalCredentialFieldRequirement()->equals();
-            }
-          }
-
-          fields.push_back(std::move(requested_element));
-        }
-        mojo_provider->selector->fields = std::move(fields);
-      }
-    }
-    if (provider.holder()->hasProtocol()) {
-      mojo_provider->protocol = provider.holder()->protocol();
-    }
-    if (provider.holder()->hasRequest()) {
-      mojo_provider->request = provider.holder()->request();
-    }
-    if (provider.holder()->hasPublicKey()) {
-      mojo_provider->publicKey = provider.holder()->publicKey();
-    }
+    auto mojo_provider = DigitalCredentialProvider::From(*provider.holder());
     return IdentityProvider::NewHolder(std::move(mojo_provider));
   } else {
     auto config = IdentityProviderRequestOptions::From(provider);
@@ -961,6 +914,58 @@
 }
 
 // static
+DigitalCredentialProviderPtr
+TypeConverter<DigitalCredentialProviderPtr, blink::DigitalCredentialProvider>::
+    Convert(const blink::DigitalCredentialProvider& provider) {
+  auto mojo_provider = DigitalCredentialProvider::New();
+  if (provider.hasParams()) {
+    HashMap<String, String> params;
+    for (const auto& pair : provider.params()) {
+      params.Set(pair.first, pair.second);
+    }
+    mojo_provider->params = std::move(params);
+  }
+  if (provider.hasSelector()) {
+    mojo_provider->selector = DigitalCredentialSelector::New();
+    if (provider.selector()->hasFormat()) {
+      mojo_provider->selector->format = provider.selector()->format();
+    }
+    if (provider.selector()->hasDoctype()) {
+      mojo_provider->selector->doctype = provider.selector()->doctype();
+    }
+    if (provider.selector()->hasFields()) {
+      WTF::Vector<DigitalCredentialFieldRequirementPtr> fields;
+      for (auto element : provider.selector()->fields()) {
+        auto requested_element = DigitalCredentialFieldRequirement::New();
+        if (element->IsString()) {
+          requested_element->name = element->GetAsString();
+        } else {
+          requested_element->name =
+              element->GetAsDigitalCredentialFieldRequirement()->name();
+          if (element->GetAsDigitalCredentialFieldRequirement()->hasEquals()) {
+            requested_element->equals =
+                element->GetAsDigitalCredentialFieldRequirement()->equals();
+          }
+        }
+
+        fields.push_back(std::move(requested_element));
+      }
+      mojo_provider->selector->fields = std::move(fields);
+    }
+  }
+  if (provider.hasProtocol()) {
+    mojo_provider->protocol = provider.protocol();
+  }
+  if (provider.hasRequest()) {
+    mojo_provider->request = provider.request();
+  }
+  if (provider.hasPublicKey()) {
+    mojo_provider->publicKey = provider.publicKey();
+  }
+  return mojo_provider;
+}
+
+// static
 RpContext
 TypeConverter<RpContext, blink::V8IdentityCredentialRequestOptionsContext>::
     Convert(const blink::V8IdentityCredentialRequestOptionsContext& context) {
diff --git a/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.h b/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.h
index 33a21493f..1949a01b 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.h
+++ b/third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.h
@@ -25,6 +25,7 @@
 class AuthenticatorSelectionCriteria;
 class CableAuthenticationData;
 class Credential;
+class DigitalCredentialProvider;
 class IdentityCredentialDisconnectOptions;
 class IdentityProviderConfig;
 class IdentityProviderRequestOptions;
@@ -234,6 +235,13 @@
 };
 
 template <>
+struct TypeConverter<blink::mojom::blink::DigitalCredentialProviderPtr,
+                     blink::DigitalCredentialProvider> {
+  static blink::mojom::blink::DigitalCredentialProviderPtr Convert(
+      const blink::DigitalCredentialProvider&);
+};
+
+template <>
 struct MODULES_EXPORT
     TypeConverter<blink::mojom::blink::RpContext,
                   blink::V8IdentityCredentialRequestOptionsContext> {
diff --git a/third_party/blink/renderer/modules/credentialmanagement/credentials_container.cc b/third_party/blink/renderer/modules/credentialmanagement/credentials_container.cc
index 6ac3906..e341c42 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/credentials_container.cc
+++ b/third_party/blink/renderer/modules/credentialmanagement/credentials_container.cc
@@ -1526,7 +1526,7 @@
   }
 
   if (options->hasIdentity() && options->identity()->hasProviders()) {
-    return GetForIdentity(script_state, resolver, promise, options,
+    return GetForIdentity(script_state, resolver, promise, *options,
                           *options->identity(), exception_state);
   }
 
@@ -1990,9 +1990,31 @@
     ScriptState* script_state,
     ScriptPromiseResolver* resolver,
     const ScriptPromise& promise,
-    const CredentialRequestOptions* options,
+    const CredentialRequestOptions& options,
     const IdentityCredentialRequestOptions& identity_options,
     ExceptionState& exception_state) {
+  // Common errors for FedCM and WebIdentityDigitalCredential.
+  if (identity_options.providers().size() == 0) {
+    exception_state.ThrowTypeError("Need at least one identity provider.");
+    resolver->Detach();
+    return ScriptPromise();
+  }
+
+  auto* signal = options.getSignalOr(nullptr);
+  if (signal && signal->aborted()) {
+    resolver->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kAbortError, "Request has been aborted."));
+    return promise;
+  }
+
+  if (absl::optional<ScriptPromise> digital_credential_promise =
+          GetForDigitalCredential(script_state, resolver, promise, options,
+                                  *identity_options.providers()[0],
+                                  identity_options.providers().size(),
+                                  exception_state)) {
+    return *digital_credential_promise;
+  }
+
   ExecutionContext* context = ExecutionContext::From(script_state);
 
   // TODO(https://crbug.com/1441075): Ideally the logic should be handled in
@@ -2002,11 +2024,6 @@
   ContentSecurityPolicy* policy =
       resolver->GetExecutionContext()
           ->GetContentSecurityPolicyForCurrentWorld();
-  if (identity_options.providers().size() == 0) {
-    exception_state.ThrowTypeError("Need at least one identity provider.");
-    resolver->Detach();
-    return ScriptPromise();
-  }
   if (!RuntimeEnabledFeatures::FedCmMultipleIdentityProvidersEnabled(context) &&
       identity_options.providers().size() > 1) {
     exception_state.ThrowTypeError(
@@ -2040,21 +2057,6 @@
       UseCounter::Count(resolver->GetExecutionContext(),
                         WebFeature::kFedCmDomainHint);
     }
-    if (RuntimeEnabledFeatures::WebIdentityDigitalCredentialsEnabled(
-            resolver->GetExecutionContext()) &&
-        !RuntimeEnabledFeatures::FedCmMultipleIdentityProvidersEnabled()) {
-      // TODO(https://crbug.com/1416939): make sure the Digital Credentials
-      //  API works well with the Multiple IdP API.
-      if (provider->hasHolder()) {
-        UseCounter::Count(resolver->GetExecutionContext(),
-                          WebFeature::kIdentityDigitalCredentials);
-
-        auto identity_provider =
-            blink::mojom::blink::IdentityProvider::From(*provider);
-        identity_provider_ptrs.push_back(std::move(identity_provider));
-        continue;
-      }
-    }
 
     if (blink::RuntimeEnabledFeatures::FedCmIdPRegistrationEnabled() &&
         provider->hasConfigURL() && provider->configURL() == "any") {
@@ -2120,18 +2122,18 @@
   // TODO(crbug.com/1429083): add uma histograms for rp mode.
 
   CredentialMediationRequirement mediation_requirement;
-  if (options->mediation() == "conditional") {
+  if (options.mediation() == "conditional") {
     resolver->Reject(MakeGarbageCollected<DOMException>(
         DOMExceptionCode::kNotSupportedError,
         "Conditional mediation is not supported for this credential type"));
     return promise;
   }
-  if (options->mediation() == "silent") {
+  if (options.mediation() == "silent") {
     mediation_requirement = CredentialMediationRequirement::kSilent;
-  } else if (options->mediation() == "required") {
+  } else if (options.mediation() == "required") {
     mediation_requirement = CredentialMediationRequirement::kRequired;
   } else {
-    DCHECK_EQ("optional", options->mediation());
+    DCHECK_EQ("optional", options.mediation());
     mediation_requirement = CredentialMediationRequirement::kOptional;
   }
 
@@ -2141,12 +2143,8 @@
   }
 
   std::unique_ptr<ScopedAbortState> scoped_abort_state;
-  if (auto* signal = options->getSignalOr(nullptr)) {
-    if (signal->aborted()) {
-      resolver->Reject(MakeGarbageCollected<DOMException>(
-          DOMExceptionCode::kAbortError, "Request has been aborted."));
-      return promise;
-    }
+  if (signal) {
+    // Checked signal->aborted() at the top of the function.
 
     auto callback =
         !RuntimeEnabledFeatures::FedCmMultipleIdentityProvidersEnabled(context)
@@ -2172,7 +2170,7 @@
     auth_request->RequestToken(
         std::move(idp_get_params), mediation_requirement,
         WTF::BindOnce(&OnRequestToken, WrapPersistent(resolver),
-                      std::move(scoped_abort_state), WrapPersistent(options)));
+                      std::move(scoped_abort_state), WrapPersistent(&options)));
 
     // Start recording the duration from when RequestToken is called directly
     // to when RequestToken would be called if invoked through
@@ -2193,4 +2191,62 @@
   return promise;
 }
 
+absl::optional<ScriptPromise> CredentialsContainer::GetForDigitalCredential(
+    ScriptState* script_state,
+    ScriptPromiseResolver* resolver,
+    const ScriptPromise& promise,
+    const CredentialRequestOptions& options,
+    const IdentityProviderRequestOptions& first_identity_provider,
+    size_t num_identity_providers,
+    ExceptionState& exception_state) {
+  // TODO(https://crbug.com/1416939): make sure the Digital Credentials
+  //  API works well with the Multiple IdP API.
+  if (!RuntimeEnabledFeatures::WebIdentityDigitalCredentialsEnabled(
+            resolver->GetExecutionContext()) ||
+      RuntimeEnabledFeatures::FedCmMultipleIdentityProvidersEnabled() ||
+      !first_identity_provider.hasHolder()) {
+    return absl::nullopt;
+  }
+
+  if (num_identity_providers > 1u) {
+    resolver->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kAbortError,
+        "Digital Credentials API currently does not support multiple "
+        "providers."));
+    return promise;
+  }
+
+  UseCounter::Count(resolver->GetExecutionContext(),
+                    WebFeature::kIdentityDigitalCredentials);
+
+  std::unique_ptr<ScopedAbortState> scoped_abort_state;
+  if (auto* signal = options.getSignalOr(nullptr)) {
+    auto callback = WTF::BindOnce(&AbortIdentityCredentialRequest,
+                                  WrapPersistent(script_state));
+
+    auto* handle = signal->AddAlgorithm(std::move(callback));
+    scoped_abort_state = std::make_unique<ScopedAbortState>(signal, handle);
+  }
+
+  Vector<mojom::blink::IdentityProviderPtr> identity_provider_ptrs;
+  identity_provider_ptrs.push_back(
+      blink::mojom::blink::IdentityProvider::From(first_identity_provider));
+
+  mojom::blink::IdentityProviderGetParametersPtr get_params =
+      mojom::blink::IdentityProviderGetParameters::New(
+          std::move(identity_provider_ptrs), mojom::blink::RpContext::kSignIn,
+          mojom::blink::RpMode::kWidget);
+
+  Vector<mojom::blink::IdentityProviderGetParametersPtr> idp_get_params;
+  idp_get_params.push_back(std::move(get_params));
+
+  auto* auth_request =
+      CredentialManagerProxy::From(script_state)->FederatedAuthRequest();
+  auth_request->RequestToken(
+      std::move(idp_get_params), CredentialMediationRequirement::kRequired,
+      WTF::BindOnce(&OnRequestToken, WrapPersistent(resolver),
+                    std::move(scoped_abort_state), WrapPersistent(&options)));
+  return promise;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/credentialmanagement/credentials_container.h b/third_party/blink/renderer/modules/credentialmanagement/credentials_container.h
index 26b0f6b..33d91c01 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/credentials_container.h
+++ b/third_party/blink/renderer/modules/credentialmanagement/credentials_container.h
@@ -53,10 +53,22 @@
   ScriptPromise GetForIdentity(ScriptState*,
                                ScriptPromiseResolver* resolver,
                                const ScriptPromise& promise,
-                               const CredentialRequestOptions*,
+                               const CredentialRequestOptions&,
                                const IdentityCredentialRequestOptions&,
                                ExceptionState&);
 
+  // get() implementation for WebIdentityDigitalCredential.
+  // Returns absl::nullopt if the passed-in CredentialRequestOptions are not for
+  // a WebIdentityDigitalCredential.
+  absl::optional<ScriptPromise> GetForDigitalCredential(
+      ScriptState*,
+      ScriptPromiseResolver*,
+      const ScriptPromise&,
+      const CredentialRequestOptions&,
+      const IdentityProviderRequestOptions& first_identity_provider,
+      size_t num_identity_providers,
+      ExceptionState&);
+
   class OtpRequestAbortAlgorithm;
   class PublicKeyRequestAbortAlgorithm;
 
diff --git a/third_party/blink/renderer/modules/ml/ml_trace_unittest.cc b/third_party/blink/renderer/modules/ml/ml_trace_unittest.cc
index c70c8c2..fb4fc214 100644
--- a/third_party/blink/renderer/modules/ml/ml_trace_unittest.cc
+++ b/third_party/blink/renderer/modules/ml/ml_trace_unittest.cc
@@ -86,10 +86,7 @@
       const std::string* trace_type = dict.FindString("ph");
       CHECK(trace_type);
       // Count both the "BEGIN" and "END" traces.
-      if (*trace_type == "n") {
-        ((event_counts)[*name].first)++;
-        ((event_counts)[*name].second)++;
-      } else if (*trace_type != "E" && *trace_type != "e") {
+      if (*trace_type != "E" && *trace_type != "e") {
         ((event_counts)[*name].first)++;
       } else {
         ((event_counts)[*name].second)++;
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
index 22b1a17..2c16dee 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
@@ -1309,6 +1309,13 @@
                      options, exception_state);
 }
 
+MLOperand* MLGraphBuilder::l2Pool2d(const MLOperand* input,
+                                    const MLPool2dOptions* options,
+                                    ExceptionState& exception_state) {
+  return BuildPool2d(this, MLOperator::OperatorKind::kL2Pool2d, input, options,
+                     exception_state);
+}
+
 MLOperand* MLGraphBuilder::maxPool2d(const MLOperand* input,
                                      const MLPool2dOptions* options,
                                      ExceptionState& exception_state) {
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h
index b2846ecc..f0db527 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h
@@ -241,6 +241,9 @@
   MLOperand* averagePool2d(const MLOperand* input,
                            const MLPool2dOptions* options,
                            ExceptionState& exception_state);
+  MLOperand* l2Pool2d(const MLOperand* input,
+                      const MLPool2dOptions* options,
+                      ExceptionState& exception_state);
   MLOperand* maxPool2d(const MLOperand* input,
                        const MLPool2dOptions* options,
                        ExceptionState& exception_state);
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.idl b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.idl
index e69d0f802..5c972c0 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.idl
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.idl
@@ -248,6 +248,7 @@
 
   // Pooling operations
   [RaisesException] MLOperand averagePool2d(MLOperand input, optional MLPool2dOptions options = {});
+  [RaisesException] MLOperand l2Pool2d(MLOperand input, optional MLPool2dOptions options = {});
   [RaisesException] MLOperand maxPool2d(MLOperand input, optional MLPool2dOptions options = {});
 
   [RaisesException] MLOperand prelu(MLOperand x, MLOperand slope);
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.cc
index 4947e97b..57f69f1 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.cc
@@ -2539,6 +2539,9 @@
       output =
           builder->averagePool2d(input, options, scope.GetExceptionState());
       break;
+    case Pool2dKind::kL2:
+      output = builder->l2Pool2d(input, options, scope.GetExceptionState());
+      break;
     case Pool2dKind::kMax:
       output = builder->maxPool2d(input, options, scope.GetExceptionState());
       break;
@@ -2558,6 +2561,9 @@
     case Pool2dKind::kAverage:
       EXPECT_EQ(pool2d->Kind(), MLOperator::OperatorKind::kAveragePool2d);
       break;
+    case Pool2dKind::kL2:
+      EXPECT_EQ(pool2d->Kind(), MLOperator::OperatorKind::kL2Pool2d);
+      break;
     case Pool2dKind::kMax:
       EXPECT_EQ(pool2d->Kind(), MLOperator::OperatorKind::kMaxPool2d);
       break;
@@ -2571,7 +2577,8 @@
   auto* builder =
       CreateMLGraphBuilder(scope.GetExecutionContext(), scope.GetScriptState(),
                            scope.GetExceptionState());
-  const auto Pool2dKinds = {Pool2dKind::kAverage, Pool2dKind::kMax};
+  const auto Pool2dKinds = {Pool2dKind::kAverage, Pool2dKind::kL2,
+                            Pool2dKind::kMax};
   for (const auto pool2d_kind : Pool2dKinds) {
     {
       // Test pool2d with default options.
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.h
index 18cfe119..5b550df 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.h
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.h
@@ -136,7 +136,7 @@
                     const Vector<uint32_t>& endingPadding,
                     const MLPadOptions* options = MLPadOptions::Create());
 
-enum class Pool2dKind { kAverage, kMax };
+enum class Pool2dKind { kAverage, kL2, kMax };
 
 MLOperand* BuildPool2d(
     V8TestingScope& scope,
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo_test.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo_test.cc
index e1f3d461..6a339ff 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo_test.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo_test.cc
@@ -3594,6 +3594,7 @@
             V8TestingScope& scope,
             MLGraphBuilder* builder) {
     Test(helper, scope, builder, Pool2dKind::kAverage);
+    Test(helper, scope, builder, Pool2dKind::kL2);
     Test(helper, scope, builder, Pool2dKind::kMax);
   }
 
@@ -3641,35 +3642,38 @@
     ASSERT_EQ(graph_info->operations.size(), 1u);
     auto& operation = graph_info->operations[0];
     EXPECT_TRUE(operation->is_pool2d());
-    auto& poo2d_mojo = operation->get_pool2d();
+    auto& pool2d_mojo = operation->get_pool2d();
     switch (kind) {
       case Pool2dKind::kAverage:
-        EXPECT_EQ(poo2d_mojo->kind, blink_mojom::Pool2d::Kind::kAveragePool2d);
+        EXPECT_EQ(pool2d_mojo->kind, blink_mojom::Pool2d::Kind::kAveragePool2d);
+        break;
+      case Pool2dKind::kL2:
+        EXPECT_EQ(pool2d_mojo->kind, blink_mojom::Pool2d::Kind::kL2Pool2d);
         break;
       case Pool2dKind::kMax:
-        EXPECT_EQ(poo2d_mojo->kind, blink_mojom::Pool2d::Kind::kMaxPool2d);
+        EXPECT_EQ(pool2d_mojo->kind, blink_mojom::Pool2d::Kind::kMaxPool2d);
         break;
       default:
         NOTREACHED();
     }
     // Validate window dimensions.
-    EXPECT_EQ(poo2d_mojo->window_dimensions->height,
+    EXPECT_EQ(pool2d_mojo->window_dimensions->height,
               expected_attributes.window_dimensions[0]);
-    EXPECT_EQ(poo2d_mojo->window_dimensions->width,
+    EXPECT_EQ(pool2d_mojo->window_dimensions->width,
               expected_attributes.window_dimensions[1]);
     // Validate explicit padding.
     auto& expected_padding = expected_attributes.padding;
-    EXPECT_EQ(poo2d_mojo->padding->beginning->height, expected_padding[0]);
-    EXPECT_EQ(poo2d_mojo->padding->ending->height, expected_padding[1]);
-    EXPECT_EQ(poo2d_mojo->padding->beginning->width, expected_padding[2]);
-    EXPECT_EQ(poo2d_mojo->padding->ending->width, expected_padding[3]);
+    EXPECT_EQ(pool2d_mojo->padding->beginning->height, expected_padding[0]);
+    EXPECT_EQ(pool2d_mojo->padding->ending->height, expected_padding[1]);
+    EXPECT_EQ(pool2d_mojo->padding->beginning->width, expected_padding[2]);
+    EXPECT_EQ(pool2d_mojo->padding->ending->width, expected_padding[3]);
     // Validate strides
-    EXPECT_EQ(poo2d_mojo->strides->height, expected_attributes.strides[0]);
-    EXPECT_EQ(poo2d_mojo->strides->width, expected_attributes.strides[1]);
+    EXPECT_EQ(pool2d_mojo->strides->height, expected_attributes.strides[0]);
+    EXPECT_EQ(pool2d_mojo->strides->width, expected_attributes.strides[1]);
     // Validate dilations.
-    EXPECT_EQ(poo2d_mojo->dilations->height, expected_attributes.dilations[0]);
-    EXPECT_EQ(poo2d_mojo->dilations->width, expected_attributes.dilations[1]);
-    EXPECT_EQ(poo2d_mojo->layout, expected_attributes.layout);
+    EXPECT_EQ(pool2d_mojo->dilations->height, expected_attributes.dilations[0]);
+    EXPECT_EQ(pool2d_mojo->dilations->width, expected_attributes.dilations[1]);
+    EXPECT_EQ(pool2d_mojo->layout, expected_attributes.layout);
     EXPECT_EQ(graph_info->output_operands.size(), 1u);
     auto output_operand_id = graph_info->output_operands[0];
     auto output_operand_iter =
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc
index 64a6953..53479cf5 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc
@@ -1143,6 +1143,9 @@
     case MLOperator::OperatorKind::kAveragePool2d:
       return CreatePool2dOperation(operand_to_id_map, op,
                                    blink_mojom::Pool2d::Kind::kAveragePool2d);
+    case MLOperator::OperatorKind::kL2Pool2d:
+      return CreatePool2dOperation(operand_to_id_map, op,
+                                   blink_mojom::Pool2d::Kind::kL2Pool2d);
     case MLOperator::OperatorKind::kMaxPool2d:
       return CreatePool2dOperation(operand_to_id_map, op,
                                    blink_mojom::Pool2d::Kind::kMaxPool2d);
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_operator.cc b/third_party/blink/renderer/modules/ml/webnn/ml_operator.cc
index 8e96cac..1862ec4 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_operator.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_operator.cc
@@ -102,6 +102,8 @@
       return "hardSwish";
     case MLOperator::OperatorKind::kAveragePool2d:
       return "averagePool2d";
+    case MLOperator::OperatorKind::kL2Pool2d:
+      return "l2Pool2d";
     case MLOperator::OperatorKind::kMaxPool2d:
       return "maxPool2d";
     case MLOperator::OperatorKind::kMatmul:
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_operator.h b/third_party/blink/renderer/modules/ml/webnn/ml_operator.h
index 656db85..bca3cb8 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_operator.h
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_operator.h
@@ -66,6 +66,7 @@
     kHardSigmoid,
     kHardSwish,
     kAveragePool2d,
+    kL2Pool2d,
     kMatmul,
     kMaxPool2d,
     kPad,
diff --git a/third_party/blink/renderer/modules/nfc/COMMON_METADATA b/third_party/blink/renderer/modules/nfc/COMMON_METADATA
index b0c98883..627969d 100644
--- a/third_party/blink/renderer/modules/nfc/COMMON_METADATA
+++ b/third_party/blink/renderer/modules/nfc/COMMON_METADATA
@@ -1,4 +1,7 @@
-monorail {
+monorail: {
   component: "Blink>NFC"
 }
-team_email: "device-dev@chromium.org"
\ No newline at end of file
+team_email: "device-dev@chromium.org"
+buganizer_public: {
+  component_id: 1456179
+}
diff --git a/third_party/blink/renderer/modules/scheduler/dom_scheduler.cc b/third_party/blink/renderer/modules/scheduler/dom_scheduler.cc
index 2861ae6b..66a49d1 100644
--- a/third_party/blink/renderer/modules/scheduler/dom_scheduler.cc
+++ b/third_party/blink/renderer/modules/scheduler/dom_scheduler.cc
@@ -176,7 +176,8 @@
     return 0;
   }
   scheduler::TaskAttributionInfo* task =
-      scheduler->GetTaskAttributionTracker()->RunningTask(script_state);
+      scheduler->GetTaskAttributionTracker()->RunningTask(
+          script_state->GetIsolate());
   // task cannot be nullptr here, as a task has presumably already ran in order
   // for this API call to be called.
   DCHECK(task);
@@ -194,7 +195,7 @@
     return AtomicString("unknown");
   }
   const scheduler::TaskAttributionInfo* current_task =
-      tracker->RunningTask(script_state);
+      tracker->RunningTask(script_state->GetIsolate());
   return current_task &&
                  tracker->IsAncestor(*current_task,
                                      scheduler::TaskAttributionId(parent_id))
diff --git a/third_party/blink/renderer/modules/scheduler/dom_task.cc b/third_party/blink/renderer/modules/scheduler/dom_task.cc
index b99a9cd..b64af493 100644
--- a/third_party/blink/renderer/modules/scheduler/dom_task.cc
+++ b/third_party/blink/renderer/modules/scheduler/dom_task.cc
@@ -112,7 +112,7 @@
   if (script_state->World().IsMainWorld()) {
     if (auto* tracker =
             ThreadScheduler::Current()->GetTaskAttributionTracker()) {
-      parent_task_ = tracker->RunningTask(script_state);
+      parent_task_ = tracker->RunningTask(script_state->GetIsolate());
     }
   }
 
diff --git a/third_party/blink/renderer/modules/scheduler/scheduled_action.cc b/third_party/blink/renderer/modules/scheduler/scheduled_action.cc
index 777e974..7573bea2 100644
--- a/third_party/blink/renderer/modules/scheduler/scheduled_action.cc
+++ b/third_party/blink/renderer/modules/scheduler/scheduled_action.cc
@@ -64,7 +64,8 @@
     arguments_ = arguments;
     auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker();
     if (tracker && script_state->World().IsMainWorld()) {
-      function_->SetParentTask(tracker->RunningTask(script_state));
+      function_->SetParentTask(
+          tracker->RunningTask(script_state->GetIsolate()));
     }
   } else {
     UseCounter::Count(target, WebFeature::kScheduledActionIgnored);
@@ -83,7 +84,7 @@
     code_ = handler;
     auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker();
     if (tracker && script_state->World().IsMainWorld()) {
-      code_parent_task_ = tracker->RunningTask(script_state);
+      code_parent_task_ = tracker->RunningTask(script_state->GetIsolate());
     }
   } else {
     UseCounter::Count(target, WebFeature::kScheduledActionIgnored);
diff --git a/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.cc b/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.cc
index c83716ba..0ce19e3 100644
--- a/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.cc
+++ b/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.cc
@@ -62,12 +62,6 @@
   return task_state ? task_state->GetTask() : running_task_.Get();
 }
 
-TaskAttributionInfo* TaskAttributionTrackerImpl::RunningTask(
-    ScriptState* script_state) const {
-  CHECK(script_state);
-  return RunningTask(script_state->GetIsolate());
-}
-
 bool TaskAttributionTrackerImpl::IsAncestor(const TaskAttributionInfo& task,
                                             TaskAttributionId ancestor_id) {
   const TaskAttributionInfo* ancestor_task = nullptr;
@@ -126,7 +120,7 @@
   ExecutionContext* execution_context = ExecutionContext::From(script_state);
   for (Observer* observer : observers_) {
     if (observer->GetExecutionContext() == execution_context) {
-      observer->OnCreateTaskScope(*running_task_, script_state);
+      observer->OnCreateTaskScope(*running_task_);
     }
   }
 
diff --git a/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.h b/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.h
index 4147dd4..f089375 100644
--- a/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.h
+++ b/third_party/blink/renderer/modules/scheduler/task_attribution_tracker_impl.h
@@ -40,7 +40,6 @@
   TaskAttributionTrackerImpl();
 
   TaskAttributionInfo* RunningTask(v8::Isolate*) const override;
-  TaskAttributionInfo* RunningTask(ScriptState*) const override;
 
   bool IsAncestor(const TaskAttributionInfo& task,
                   TaskAttributionId ancestor_id) override;
@@ -60,8 +59,6 @@
       AbortSignal* abort_source,
       DOMTaskSignal* priority_source) override;
 
-  void TaskScopeCompleted(ScriptState*, TaskAttributionId);
-
   bool RegisterObserverIfNeeded(
       TaskAttributionTracker::Observer* observer) override {
     bool not_registered = !base::Contains(observers_, observer);
diff --git a/third_party/blink/renderer/modules/scheduler/window_idle_tasks.cc b/third_party/blink/renderer/modules/scheduler/window_idle_tasks.cc
index 7201304..856b9a8 100644
--- a/third_party/blink/renderer/modules/scheduler/window_idle_tasks.cc
+++ b/third_party/blink/renderer/modules/scheduler/window_idle_tasks.cc
@@ -38,7 +38,7 @@
     ScriptState* script_state = callback_->CallbackRelevantScriptState();
     auto* tracker = ThreadScheduler::Current()->GetTaskAttributionTracker();
     if (tracker && script_state->World().IsMainWorld()) {
-      parent_task_ = tracker->RunningTask(script_state);
+      parent_task_ = tracker->RunningTask(script_state->GetIsolate());
     }
   }
 
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 590ff47..0ae7694 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -2613,6 +2613,17 @@
   dict = "//testing/libfuzzer/fuzzers/dicts/web_icon_sizes.dict"
 }
 
+# Fuzzer for blink::AVIFImageDecoder
+fuzzer_test("blink_avif_decoder_fuzzer") {
+  sources = [ "image-decoders/avif/avif_image_decoder_fuzzer.cc" ]
+  deps = [
+    ":blink_fuzzer_test_support",
+    ":platform",
+  ]
+  seed_corpuses = [ "//third_party/blink/web_tests/images/resources/avif" ]
+  libfuzzer_options = [ "rss_limit_mb=8192" ]
+}
+
 fuzzer_test("blink_png_decoder_fuzzer") {
   sources = [ "image-decoders/png/png_image_decoder_fuzzer.cc" ]
   deps = [
diff --git a/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder_fuzzer.cc b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder_fuzzer.cc
new file mode 100644
index 0000000..10be1bb
--- /dev/null
+++ b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder_fuzzer.cc
@@ -0,0 +1,41 @@
+// 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.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+
+#include "third_party/blink/renderer/platform/graphics/color_behavior.h"
+#include "third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h"
+#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
+#include "third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.h"
+
+namespace blink {
+
+std::unique_ptr<ImageDecoder> CreateAVIFDecoder() {
+  // TODO(b/323934468): Initialize decoder settings dynamically using fuzzer
+  // input.
+  return std::make_unique<AVIFImageDecoder>(
+      ImageDecoder::kAlphaPremultiplied, ImageDecoder::kDefaultBitDepth,
+      ColorBehavior::kTransformToSRGB, ImageDecoder::kNoDecodedImageByteLimit,
+      ImageDecoder::AnimationOption::kPreferAnimation);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  static BlinkFuzzerTestSupport test_support;
+  auto buffer = SharedBuffer::Create(data, size);
+  auto decoder = CreateAVIFDecoder();
+  constexpr static bool kAllDataReceived = true;
+  decoder->SetData(buffer.get(), kAllDataReceived);
+  for (wtf_size_t frame = 0; frame < decoder->FrameCount(); ++frame) {
+    decoder->DecodeFrameBufferAtIndex(frame);
+    if (decoder->Failed()) {
+      return 0;
+    }
+  }
+  return 0;
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler.cc
index 508478d0..db165ee4 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler.cc
@@ -116,9 +116,8 @@
     const String& cache_storage_name,
     const uint8_t* data,
     size_t size) {
-  if (!code_cache_host) {
+  if (!code_cache_host)
     return;
-  }
   if (cache_storage_name.IsNull()) {
     code_cache_host->get()->DidGenerateCacheableMetadata(
         code_cache_type, KURL(url), response_time,
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/resource_request_sender.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/resource_request_sender.cc
index 5b2e0bb..29052a7 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/resource_request_sender.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/resource_request_sender.cc
@@ -180,7 +180,8 @@
   // The only case where it's easy to skip a kEmpty request is when a content
   // equality check is required, because only ScriptResource supports that
   // requirement.
-  if (request.destination == network::mojom::RequestDestination::kEmpty) {
+  if (request.destination == network::mojom::RequestDestination::kEmpty &&
+      !should_use_source_hash) {
     return true;
   }
   return false;
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 18212299..90832c44 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -3010,7 +3010,11 @@
       status: "stable",
     },
     {
-      // https://crbug.com/1126305
+      // Used to allow chrome://flags to turn off prerendering. (Without using
+      // the user-facing preloading settings page to turn off other
+      // preloading.) See https://crbug.com/1494471.
+      //
+      // It also has some feature params defined throughout the codebase.
       name: "Prerender2",
       status: "stable",
     },
diff --git a/third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h b/third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h
index 6fecf8e..9db5a97 100644
--- a/third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h
+++ b/third_party/blink/renderer/platform/scheduler/public/task_attribution_tracker.h
@@ -58,7 +58,7 @@
 
   class Observer : public GarbageCollectedMixin {
    public:
-    virtual void OnCreateTaskScope(TaskAttributionInfo&, ScriptState*) = 0;
+    virtual void OnCreateTaskScope(TaskAttributionInfo&) = 0;
     virtual ExecutionContext* GetExecutionContext() = 0;
   };
 
@@ -79,9 +79,6 @@
 
   // Get the `TaskAttributionInfo` for the currently running task.
   virtual TaskAttributionInfo* RunningTask(v8::Isolate*) const = 0;
-  // TODO(crbug.com/1351643): Remove this overload once converting everything to
-  // the Isolate version.
-  virtual TaskAttributionInfo* RunningTask(ScriptState*) const = 0;
 
   // Returns true iff `task` has an ancestor task with `ancestor_id`.
   virtual bool IsAncestor(const TaskAttributionInfo& task,
diff --git a/third_party/blink/renderer/platform/theme/web_theme_engine_default.cc b/third_party/blink/renderer/platform/theme/web_theme_engine_default.cc
index f92d81e..aa8193e 100644
--- a/third_party/blink/renderer/platform/theme/web_theme_engine_default.cc
+++ b/third_party/blink/renderer/platform/theme/web_theme_engine_default.cc
@@ -175,6 +175,8 @@
           NativeThemeScrollbarOverlayColorTheme(
               scrollbar_thumb.scrollbar_theme);
       native_scrollbar_thumb.thumb_color = scrollbar_thumb.thumb_color;
+      native_scrollbar_thumb.is_thumb_minimal_mode =
+          scrollbar_thumb.is_thumb_minimal_mode;
       return ui::NativeTheme::ExtraParams(native_scrollbar_thumb);
     }
     case WebThemeEngine::kPartScrollbarDownArrow:
diff --git a/third_party/blink/tools/blinkpy/common/config/builders.json b/third_party/blink/tools/blinkpy/common/config/builders.json
index e3ed574..159d0b38 100644
--- a/third_party/blink/tools/blinkpy/common/config/builders.json
+++ b/third_party/blink/tools/blinkpy/common/config/builders.json
@@ -177,6 +177,19 @@
         },
         "is_try_builder": true
     },
+    "win11-arm64-blink-rel": {
+        "main": "tryserver.blink",
+        "port_name": "win-win11-arm64",
+        "specifiers": [
+            "Win11-arm64",
+            "Release"
+        ],
+        "steps": {
+            "blink_web_tests (with patch)": {},
+            "blink_wpt_tests (with patch)": {}
+        },
+        "is_try_builder": true
+    },
     "win11-blink-rel": {
         "main": "tryserver.blink",
         "port_name": "win-win11",
diff --git a/third_party/blink/web_tests/external/wpt/webnn/idlharness.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/webnn/idlharness.https.any-expected.txt
index b1834d0..162dc88 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/idlharness.https.any-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webnn/idlharness.https.any-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 39 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 36 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] idl_test setup
   promise_test: Unhandled rejection with value: object "NotSupportedError: The input layout nchw is not supported."
 [FAIL] NavigatorML must be primary interface of navigator
@@ -46,8 +46,6 @@
   assert_own_property: interface prototype object missing non-static operation expected property "lstm" missing
 [FAIL] MLGraphBuilder interface: operation lstmCell(MLOperand, MLOperand, MLOperand, MLOperand, MLOperand, unsigned long, optional MLLstmCellOptions)
   assert_own_property: interface prototype object missing non-static operation expected property "lstmCell" missing
-[FAIL] MLGraphBuilder interface: operation l2Pool2d(MLOperand, optional MLPool2dOptions)
-  assert_own_property: interface prototype object missing non-static operation expected property "l2Pool2d" missing
 [FAIL] MLGraphBuilder interface: operation triangular(MLOperand, optional MLTriangularOptions)
   assert_own_property: interface prototype object missing non-static operation expected property "triangular" missing
 [FAIL] MLGraphBuilder interface: builder must inherit property "not(MLOperand)" with the proper type
@@ -70,10 +68,6 @@
   assert_inherits: property "lstmCell" not found in prototype chain
 [FAIL] MLGraphBuilder interface: calling lstmCell(MLOperand, MLOperand, MLOperand, MLOperand, MLOperand, unsigned long, optional MLLstmCellOptions) on builder with too few arguments must throw TypeError
   assert_inherits: property "lstmCell" not found in prototype chain
-[FAIL] MLGraphBuilder interface: builder must inherit property "l2Pool2d(MLOperand, optional MLPool2dOptions)" with the proper type
-  assert_inherits: property "l2Pool2d" not found in prototype chain
-[FAIL] MLGraphBuilder interface: calling l2Pool2d(MLOperand, optional MLPool2dOptions) on builder with too few arguments must throw TypeError
-  assert_inherits: property "l2Pool2d" not found in prototype chain
 [FAIL] MLGraphBuilder interface: builder must inherit property "triangular(MLOperand, optional MLTriangularOptions)" with the proper type
   assert_inherits: property "triangular" not found in prototype chain
 [FAIL] MLGraphBuilder interface: calling triangular(MLOperand, optional MLTriangularOptions) on builder with too few arguments must throw TypeError
diff --git a/third_party/blink/web_tests/external/wpt/webnn/idlharness.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/webnn/idlharness.https.any.worker-expected.txt
index 2ecd4f6c..b74775ec 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/idlharness.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webnn/idlharness.https.any.worker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 46 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 43 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] idl_test setup
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'buildSync' on 'MLGraphBuilder': The input layout nchw is not supported."
 [FAIL] NavigatorML must be primary interface of navigator
@@ -56,8 +56,6 @@
   assert_own_property: interface prototype object missing non-static operation expected property "lstm" missing
 [FAIL] MLGraphBuilder interface: operation lstmCell(MLOperand, MLOperand, MLOperand, MLOperand, MLOperand, unsigned long, optional MLLstmCellOptions)
   assert_own_property: interface prototype object missing non-static operation expected property "lstmCell" missing
-[FAIL] MLGraphBuilder interface: operation l2Pool2d(MLOperand, optional MLPool2dOptions)
-  assert_own_property: interface prototype object missing non-static operation expected property "l2Pool2d" missing
 [FAIL] MLGraphBuilder interface: operation triangular(MLOperand, optional MLTriangularOptions)
   assert_own_property: interface prototype object missing non-static operation expected property "triangular" missing
 [FAIL] MLGraphBuilder interface: builder must inherit property "build(MLNamedOperands)" with the proper type
@@ -84,10 +82,6 @@
   assert_inherits: property "lstmCell" not found in prototype chain
 [FAIL] MLGraphBuilder interface: calling lstmCell(MLOperand, MLOperand, MLOperand, MLOperand, MLOperand, unsigned long, optional MLLstmCellOptions) on builder with too few arguments must throw TypeError
   assert_inherits: property "lstmCell" not found in prototype chain
-[FAIL] MLGraphBuilder interface: builder must inherit property "l2Pool2d(MLOperand, optional MLPool2dOptions)" with the proper type
-  assert_inherits: property "l2Pool2d" not found in prototype chain
-[FAIL] MLGraphBuilder interface: calling l2Pool2d(MLOperand, optional MLPool2dOptions) on builder with too few arguments must throw TypeError
-  assert_inherits: property "l2Pool2d" not found in prototype chain
 [FAIL] MLGraphBuilder interface: builder must inherit property "triangular(MLOperand, optional MLTriangularOptions)" with the proper type
   assert_inherits: property "triangular" not found in prototype chain
 [FAIL] MLGraphBuilder interface: calling triangular(MLOperand, optional MLTriangularOptions) on builder with too few arguments must throw TypeError
diff --git a/third_party/blink/web_tests/fast/loader/json-document-appearance.html b/third_party/blink/web_tests/fast/loader/json-document-appearance.html
new file mode 100644
index 0000000..939b7ac
--- /dev/null
+++ b/third_party/blink/web_tests/fast/loader/json-document-appearance.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<iframe src="resources/json-document.json" width="800" height="600">
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/loader/resources/json-document.json b/third_party/blink/web_tests/fast/loader/resources/json-document.json
new file mode 100644
index 0000000..df9934a
--- /dev/null
+++ b/third_party/blink/web_tests/fast/loader/resources/json-document.json
@@ -0,0 +1,4 @@
+{
+  "key": "À",
+  "emoji": "✨"
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/platform/linux/fast/loader/json-document-appearance-expected.png b/third_party/blink/web_tests/platform/linux/fast/loader/json-document-appearance-expected.png
new file mode 100644
index 0000000..29ffe32
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/fast/loader/json-document-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac11/fast/loader/json-document-appearance-expected.png b/third_party/blink/web_tests/platform/mac-mac11/fast/loader/json-document-appearance-expected.png
new file mode 100644
index 0000000..af2cb76
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11/fast/loader/json-document-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/loader/json-document-appearance-expected.png b/third_party/blink/web_tests/platform/mac/fast/loader/json-document-appearance-expected.png
new file mode 100644
index 0000000..516e5c4
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/fast/loader/json-document-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/loader/json-document-appearance-expected.png b/third_party/blink/web_tests/platform/win/fast/loader/json-document-appearance-expected.png
new file mode 100644
index 0000000..753926c
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/fast/loader/json-document-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win10/fast/loader/json-document-appearance-expected.png b/third_party/blink/web_tests/platform/win10/fast/loader/json-document-appearance-expected.png
new file mode 100644
index 0000000..f4538f75
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win10/fast/loader/json-document-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/css2.1/t1202-counter-04-b-expected.png b/third_party/blink/web_tests/platform/win11-arm64/css2.1/t1202-counter-04-b-expected.png
index efaafb6..02c33803 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/css2.1/t1202-counter-04-b-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/css2.1/t1202-counter-04-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/css2.1/t1202-counters-04-b-expected.png b/third_party/blink/web_tests/platform/win11-arm64/css2.1/t1202-counters-04-b-expected.png
index 6ad0d67..e85d264 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/css2.1/t1202-counters-04-b-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/css2.1/t1202-counters-04-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/custom-elements/form-validation-bubble-appearance-expected.png b/third_party/blink/web_tests/platform/win11-arm64/custom-elements/form-validation-bubble-appearance-expected.png
index 3cdf8734..7c115520 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/custom-elements/form-validation-bubble-appearance-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/custom-elements/form-validation-bubble-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/soft-navigation-heuristics/interaction-with-paint-before-back.tentative-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/soft-navigation-heuristics/interaction-with-paint-before-back.tentative-expected.txt
new file mode 100644
index 0000000..64ca21b
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/soft-navigation-heuristics/interaction-with-paint-before-back.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Unhandled rejection: element click intercepted error
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any.worker_baseline-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any.worker_baseline-expected.txt
deleted file mode 100644
index 0c4c563..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any.worker_baseline-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] Test that encoding with a specific H264 profile actually produces that profile.
-  assert_unreached: Unexpected encoding error Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any.worker_high-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any.worker_high-expected.txt
deleted file mode 100644
index 0c4c563..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any.worker_high-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] Test that encoding with a specific H264 profile actually produces that profile.
-  assert_unreached: Unexpected encoding error Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any.worker_main-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any.worker_main-expected.txt
deleted file mode 100644
index 0c4c563..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any.worker_main-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] Test that encoding with a specific H264 profile actually produces that profile.
-  assert_unreached: Unexpected encoding error Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any_baseline-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any_baseline-expected.txt
deleted file mode 100644
index 0c4c563..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any_baseline-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] Test that encoding with a specific H264 profile actually produces that profile.
-  assert_unreached: Unexpected encoding error Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any_high-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any_high-expected.txt
deleted file mode 100644
index 0c4c563..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any_high-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] Test that encoding with a specific H264 profile actually produces that profile.
-  assert_unreached: Unexpected encoding error Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any_main-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any_main-expected.txt
deleted file mode 100644
index 0c4c563..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webcodecs/video-encoder-h264.https.any_main-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] Test that encoding with a specific H264 profile actually produces that profile.
-  assert_unreached: Unexpected encoding error Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/arg_min_max.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/arg_min_max.https.any-expected.txt
new file mode 100644
index 0000000..6723efec
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/arg_min_max.https.any-expected.txt
@@ -0,0 +1,87 @@
+This is a testharness.js-based test.
+[FAIL] argMin float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 1D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 2D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 3D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 4D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 5D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 4D tensor options.axes=[2] / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 4D tensor options.axes=[] / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 4D tensor options.keepDimensions=true / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 4D tensor options.keepDimensions=false / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 4D tensor options.selectLastIndex=true / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 4D tensor options.selectLastIndex=false / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 4D tensor options.axes=[0, 2] options.keepDimensions=false / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.keepDimensions=true / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 4D tensor options.axes=[0, 2] options.selectLastIndex=false / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 4D tensor options.axes=[0, 2] options.selectLastIndex=true / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=false / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=true / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 4D tensor all options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 0D scalar options.axes=[] / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMin float32 0D scalar options.axes=[] no effect by both keepDimensions and selectLastIndex being true / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 1D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 2D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 3D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 4D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 5D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 4D tensor options.axes=[2] / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 4D tensor options.axes=[] / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 4D tensor options.keepDimensions=true / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 4D tensor options.keepDimensions=false / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 4D tensor options.selectLastIndex=true / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 4D tensor options.selectLastIndex=false / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 4D tensor options.axes=[0, 2] options.keepDimensions=false / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.keepDimensions=true / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 4D tensor options.axes=[0, 2] options.selectLastIndex=false / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 4D tensor options.axes=[0, 2] options.selectLastIndex=true / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=false / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=true / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 4D tensor all options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 0D scalar options.axes=[] / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] argMax float32 0D scalar options.axes=[] no effect by both keepDimensions and selectLastIndex being true / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/arg_min_max.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/arg_min_max.https.any.worker-expected.txt
new file mode 100644
index 0000000..ed236c5
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/arg_min_max.https.any.worker-expected.txt
@@ -0,0 +1,172 @@
+This is a testharness.js-based test.
+Found 84 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] argMin float32 1D constant tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 1D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 2D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 3D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 4D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 5D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 4D tensor options.axes=[2] / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 4D tensor options.axes=[] / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 4D tensor options.keepDimensions=true / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 4D tensor options.keepDimensions=false / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 4D tensor options.selectLastIndex=true / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 4D tensor options.selectLastIndex=false / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 4D tensor options.axes=[0, 2] options.keepDimensions=false / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.keepDimensions=true / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 4D tensor options.axes=[0, 2] options.selectLastIndex=false / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 4D tensor options.axes=[0, 2] options.selectLastIndex=true / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=false / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=true / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 4D tensor all options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 0D scalar options.axes=[] / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 0D scalar options.axes=[] no effect by both keepDimensions and selectLastIndex being true / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 1D constant tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 1D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 2D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 3D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 4D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 5D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 4D tensor options.axes=[2] / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 4D tensor options.axes=[] / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 4D tensor options.keepDimensions=true / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 4D tensor options.keepDimensions=false / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 4D tensor options.selectLastIndex=true / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 4D tensor options.selectLastIndex=false / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 4D tensor options.axes=[0, 2] options.keepDimensions=false / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.keepDimensions=true / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 4D tensor options.axes=[0, 2] options.selectLastIndex=false / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 4D tensor options.axes=[0, 2] options.selectLastIndex=true / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=false / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=true / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 4D tensor all options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 0D scalar options.axes=[] / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMax float32 0D scalar options.axes=[] no effect by both keepDimensions and selectLastIndex being true / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] argMin float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 1D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 2D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 3D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 4D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 5D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 4D tensor options.axes=[2] / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 4D tensor options.axes=[] / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 4D tensor options.keepDimensions=true / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 4D tensor options.keepDimensions=false / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 4D tensor options.selectLastIndex=true / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 4D tensor options.selectLastIndex=false / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 4D tensor options.axes=[0, 2] options.keepDimensions=false / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.keepDimensions=true / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 4D tensor options.axes=[0, 2] options.selectLastIndex=false / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 4D tensor options.axes=[0, 2] options.selectLastIndex=true / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=false / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=true / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 4D tensor all options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 0D scalar options.axes=[] / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMin float32 0D scalar options.axes=[] no effect by both keepDimensions and selectLastIndex being true / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 1D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 2D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 3D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 4D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 5D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 4D tensor options.axes=[2] / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 4D tensor options.axes=[] / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 4D tensor options.keepDimensions=true / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 4D tensor options.keepDimensions=false / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 4D tensor options.selectLastIndex=true / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 4D tensor options.selectLastIndex=false / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 4D tensor options.axes=[0, 2] options.keepDimensions=false / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.keepDimensions=true / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 4D tensor options.axes=[0, 2] options.selectLastIndex=false / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 4D tensor options.axes=[0, 2] options.selectLastIndex=true / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=false / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=true / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 4D tensor all options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 0D scalar options.axes=[] / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] argMax float32 0D scalar options.axes=[] no effect by both keepDimensions and selectLastIndex being true / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/batch_normalization.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/batch_normalization.https.any-expected.txt
index 2c14411..b6de39f 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/batch_normalization.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/batch_normalization.https.any-expected.txt
@@ -1,6 +1,8 @@
 This is a testharness.js-based test.
 [FAIL] batchNormalization float32 2D tensor (mean and variance are non-constant) default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] batchNormalization float32 2D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] batchNormalization float32 2D tensor default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] batchNormalization float32 3D tensor default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/batch_normalization.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/batch_normalization.https.any.worker-expected.txt
index 8080db69..89ec3d840 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/batch_normalization.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/batch_normalization.https.any.worker-expected.txt
@@ -1,6 +1,8 @@
 This is a testharness.js-based test.
 [FAIL] batchNormalization float32 2D tensor (mean and variance are non-constant) default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] batchNormalization float32 2D constant tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] batchNormalization float32 2D tensor default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] batchNormalization float32 3D tensor default options / sync
@@ -25,6 +27,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] batchNormalization float32 2D tensor (mean and variance are non-constant) default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] batchNormalization float32 2D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] batchNormalization float32 2D tensor default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] batchNormalization float32 3D tensor default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/cast.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/cast.https.any-expected.txt
new file mode 100644
index 0000000..b091b5b
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/cast.https.any-expected.txt
@@ -0,0 +1,95 @@
+This is a testharness.js-based test.
+[FAIL] cast float32 0D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast float32 1D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast float32 2D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast float32 3D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast float32 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast float32 5D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast float32 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast float32 4D tensor to uint32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast float32 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast float32 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast float32 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast float16 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast float16 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast float16 4D tensor to uint32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast float16 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast float16 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast float16 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast int32 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast int32 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast int32 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast int32 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast int32 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast uint32 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast uint32 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast uint32 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast uint32 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast uint32 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast uint32 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast int64 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast int64 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast int64 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast int64 4D tensor to uint32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast int64 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast int64 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast int8 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast int8 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast int8 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast int8 4D tensor to uint32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast int8 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast int8 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast uint8 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast uint8 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast uint8 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast uint8 4D tensor to uint32 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast uint8 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cast uint8 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/cast.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/cast.https.any.worker-expected.txt
new file mode 100644
index 0000000..d585da91
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/cast.https.any.worker-expected.txt
@@ -0,0 +1,188 @@
+This is a testharness.js-based test.
+Found 92 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] cast float32 0D tensor to int32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast float32 1D tensor to int32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast float32 2D tensor to int32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast float32 3D tensor to int32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast float32 4D tensor to int32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast float32 5D tensor to int32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast float32 4D tensor to float16 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast float32 4D tensor to uint32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast float32 4D tensor to int64 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast float32 4D tensor to int8 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast float32 4D tensor to uint8 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast float16 4D tensor to float32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast float16 4D tensor to int32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast float16 4D tensor to uint32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast float16 4D tensor to int64 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast float16 4D tensor to int8 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast float16 4D tensor to uint8 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast int32 4D tensor to float32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast int32 4D tensor to float16 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast int32 4D tensor to int64 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast int32 4D tensor to int8 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast int32 4D tensor to uint8 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast uint32 4D tensor to float32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast uint32 4D tensor to float16 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast uint32 4D tensor to int32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast uint32 4D tensor to int64 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast uint32 4D tensor to int8 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast uint32 4D tensor to uint8 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast int64 4D tensor to float32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast int64 4D tensor to float16 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast int64 4D tensor to int32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast int64 4D tensor to uint32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast int64 4D tensor to int8 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast int64 4D tensor to uint8 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast int8 4D tensor to float32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast int8 4D tensor to float16 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast int8 4D tensor to int32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast int8 4D tensor to uint32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast int8 4D tensor to int64 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast int8 4D tensor to uint8 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast uint8 4D tensor to float32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast uint8 4D tensor to float16 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast uint8 4D tensor to int32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast uint8 4D tensor to uint32 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast uint8 4D tensor to int64 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast uint8 4D tensor to int8 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cast float32 0D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 1D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 2D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 3D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 5D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 4D tensor to uint32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float16 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float16 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float16 4D tensor to uint32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float16 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float16 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float16 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int32 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int32 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int32 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int32 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int32 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint32 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint32 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint32 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint32 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint32 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint32 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int64 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int64 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int64 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int64 4D tensor to uint32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int64 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int64 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int8 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int8 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int8 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int8 4D tensor to uint32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int8 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int8 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint8 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint8 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint8 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint8 4D tensor to uint32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint8 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint8 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/clamp.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/clamp.https.any-expected.txt
index f3c350c..ebbba1e 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/clamp.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/clamp.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] clamp float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] clamp float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] clamp float32 2D tensor default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/clamp.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/clamp.https.any.worker-expected.txt
index b6f014c..10732a98 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/clamp.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/clamp.https.any.worker-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] clamp float32 1D constant tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] clamp float32 1D tensor default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] clamp float32 2D tensor default options / sync
@@ -31,6 +33,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] clamp float32 1D tensor specified both positive options.minValue and options.maxValue / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] clamp float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] clamp float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] clamp float32 2D tensor default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/concat.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/concat.https.any-expected.txt
index 425ed62..82ce5204 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/concat.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/concat.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] concat two float32 1D constant tensors of same shape along axis 0 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] concat two float32 1D tensors of same shape along axis 0 / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] concat two float16 1D tensors of same shape along axis 0 / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/concat.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/concat.https.any.worker-expected.txt
index 0b4c535..3952677 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/concat.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/concat.https.any.worker-expected.txt
@@ -1,5 +1,7 @@
 This is a testharness.js-based test.
-Found 88 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 90 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] concat two float32 1D constant tensors of same shape along axis 0 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] concat two float32 1D tensors of same shape along axis 0 / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] concat two float16 1D tensors of same shape along axis 0 / sync
@@ -88,6 +90,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] concat two float16 5D tensors of same others dimensions except different 5th dimension along axis 4 / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] concat two float32 1D constant tensors of same shape along axis 0 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] concat two float32 1D tensors of same shape along axis 0 / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] concat two float16 1D tensors of same shape along axis 0 / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/conv2d.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/conv2d.https.any-expected.txt
index f12574a..26da89e 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/conv2d.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/conv2d.https.any-expected.txt
@@ -1,6 +1,8 @@
 This is a testharness.js-based test.
 [FAIL] conv2d float32 4D input and filter(non-constant) tensors default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] conv2d float32 4D both input and filter constant tensors default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] conv2d float32 4D input and filter tensors default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] conv2d float32 4D input and filter tensors options.padding / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/conv2d.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/conv2d.https.any.worker-expected.txt
index 273a7fe3..329d559 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/conv2d.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/conv2d.https.any.worker-expected.txt
@@ -1,7 +1,9 @@
 This is a testharness.js-based test.
-Found 52 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 54 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] conv2d float32 4D input and filter(non-constant) tensors default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] conv2d float32 4D both input and filter constant tensors default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] conv2d float32 4D input and filter tensors default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] conv2d float32 4D input and filter tensors options.padding / sync
@@ -54,6 +56,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] conv2d float32 4D input and filter(non-constant) tensors default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] conv2d float32 4D both input and filter constant tensors default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] conv2d float32 4D input and filter tensors default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] conv2d float32 4D input and filter tensors options.padding / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/conv_transpose2d.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/conv_transpose2d.https.any-expected.txt
index 1e69a41..3e99704 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/conv_transpose2d.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/conv_transpose2d.https.any-expected.txt
@@ -1,6 +1,8 @@
 This is a testharness.js-based test.
 [FAIL] convTranspose2d float32 4D input and filter(non-constant) tensors default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] convTranspose2d float32 4D both input and filter constant tensors default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] convTranspose2d float32 4D input and filter tensors default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] convTranspose2d float32 4D input and filter tensors options.groups / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/conv_transpose2d.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/conv_transpose2d.https.any.worker-expected.txt
index d2a244de..7fea6ce 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/conv_transpose2d.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/conv_transpose2d.https.any.worker-expected.txt
@@ -1,7 +1,9 @@
 This is a testharness.js-based test.
-Found 50 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 52 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] convTranspose2d float32 4D input and filter(non-constant) tensors default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] convTranspose2d float32 4D both input and filter constant tensors default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] convTranspose2d float32 4D input and filter tensors default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] convTranspose2d float32 4D input and filter tensors options.groups / sync
@@ -52,6 +54,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] convTranspose2d float32 4D input and filter(non-constant) tensors default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] convTranspose2d float32 4D both input and filter constant tensors default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] convTranspose2d float32 4D input and filter tensors default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] convTranspose2d float32 4D input and filter tensors options.groups / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_binary.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_binary.https.any-expected.txt
index 9712093..850f6db1 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_binary.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_binary.https.any-expected.txt
@@ -1,5 +1,7 @@
 This is a testharness.js-based test.
-Found 63 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 70 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] add float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] add float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] add float32 2D tensors / async
@@ -18,6 +20,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] add float32 broadcast 4D to 4D / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] sub float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] sub float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] sub float32 2D tensors / async
@@ -36,6 +40,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] sub float32 broadcast 4D to 4D / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] mul float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] mul float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] mul float32 2D tensors / async
@@ -54,6 +60,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] mul float32 broadcast 4D to 4D / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] div float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] div float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] div float32 2D tensors / async
@@ -72,6 +80,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] div float32 broadcast 4D to 4D / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] max float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] max float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] max float32 2D tensors / async
@@ -90,6 +100,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] max float32 broadcast 4D to 4D / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] min float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] min float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] min float32 2D tensors / async
@@ -108,6 +120,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] min float32 broadcast 4D to 4D / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] pow float32 constant 1D base tensor and 1D integer exponent tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] pow float32 1D base tensor and 1D integer exponent tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] pow float32 2D base tensor and 2D integer exponent tensor / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_binary.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_binary.https.any.worker-expected.txt
index 6923e2a..681dd6a 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_binary.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_binary.https.any.worker-expected.txt
@@ -1,5 +1,7 @@
 This is a testharness.js-based test.
-Found 126 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 140 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] add float32 1D constant tensors / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] add float32 1D tensors / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] add float32 2D tensors / sync
@@ -18,6 +20,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] add float32 broadcast 4D to 4D / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] sub float32 1D constant tensors / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] sub float32 1D tensors / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] sub float32 2D tensors / sync
@@ -36,6 +40,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] sub float32 broadcast 4D to 4D / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] mul float32 1D constant tensors / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] mul float32 1D tensors / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] mul float32 2D tensors / sync
@@ -54,6 +60,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] mul float32 broadcast 4D to 4D / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] div float32 1D constant tensors / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] div float32 1D tensors / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] div float32 2D tensors / sync
@@ -72,6 +80,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] div float32 broadcast 4D to 4D / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] max float32 1D constant tensors / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] max float32 1D tensors / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] max float32 2D tensors / sync
@@ -90,6 +100,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] max float32 broadcast 4D to 4D / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] min float32 1D constant tensors / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] min float32 1D tensors / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] min float32 2D tensors / sync
@@ -108,6 +120,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] min float32 broadcast 4D to 4D / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] pow float32 constant 1D base tensor and 1D integer exponent tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] pow float32 1D base tensor and 1D integer exponent tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] pow float32 2D base tensor and 2D integer exponent tensor / sync
@@ -126,6 +140,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] pow float32 4D base tensor and broadcastable 3D integer exponent tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] add float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] add float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] add float32 2D tensors / async
@@ -144,6 +160,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] add float32 broadcast 4D to 4D / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] sub float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] sub float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] sub float32 2D tensors / async
@@ -162,6 +180,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] sub float32 broadcast 4D to 4D / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] mul float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] mul float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] mul float32 2D tensors / async
@@ -180,6 +200,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] mul float32 broadcast 4D to 4D / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] div float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] div float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] div float32 2D tensors / async
@@ -198,6 +220,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] div float32 broadcast 4D to 4D / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] max float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] max float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] max float32 2D tensors / async
@@ -216,6 +240,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] max float32 broadcast 4D to 4D / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] min float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] min float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] min float32 2D tensors / async
@@ -234,6 +260,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] min float32 broadcast 4D to 4D / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] pow float32 constant 1D base tensor and 1D integer exponent tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] pow float32 1D base tensor and 1D integer exponent tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] pow float32 2D base tensor and 2D integer exponent tensor / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_logical.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_logical.https.any-expected.txt
index 37a503bc..d33b45f0 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_logical.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_logical.https.any-expected.txt
@@ -1,7 +1,9 @@
 This is a testharness.js-based test.
-Found 61 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 67 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] equal float32 0D scalar / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] equal float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] equal float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] equal float32 2D tensors / async
@@ -24,6 +26,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] greater float32 0D scalar / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] greater float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] greater float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] greater float32 2D tensors / async
@@ -46,6 +50,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] greaterOrEqual float32 0D scalar / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] greaterOrEqual float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] greaterOrEqual float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] greaterOrEqual float32 2D tensors / async
@@ -68,6 +74,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] lesser float32 0D scalar / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] lesser float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] lesser float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] lesser float32 2D tensors / async
@@ -90,6 +98,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] lesserOrEqual float32 0D scalar / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] lesserOrEqual float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] lesserOrEqual float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] lesserOrEqual float32 2D tensors / async
@@ -112,6 +122,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] logicalNot uint8 0D scalar / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] logicalNot uint8 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] logicalNot uint8 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] logicalNot uint8 2D tensor / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_unary.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_unary.https.any-expected.txt
index b771bc82c..268c035 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_unary.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_unary.https.any-expected.txt
@@ -1,5 +1,7 @@
 This is a testharness.js-based test.
-Found 69 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 82 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] abs float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] abs float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] abs float32 2D tensor / async
@@ -10,6 +12,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] abs float32 5D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] ceil float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] ceil float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] ceil float32 2D tensor / async
@@ -20,6 +24,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] ceil float32 5D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] cos float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] cos float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] cos float32 2D tensor / async
@@ -32,6 +38,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] erf float32 0D scalar / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] erf float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] erf float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] erf float32 2D tensor / async
@@ -42,6 +50,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] erf float32 5D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] exp float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] exp float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] exp float32 2D tensor / async
@@ -52,6 +62,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] exp float32 5D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] floor float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] floor float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] floor float32 2D tensor / async
@@ -64,6 +76,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] identity float32 0D scalar / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] identity float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] identity float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] identity float32 2D tensor / async
@@ -74,6 +88,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] identity float32 5D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] log float32 positive 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] log float32 positive 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] log float32 positive 2D tensor / async
@@ -84,6 +100,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] log float32 positive 5D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] neg float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] neg float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] neg float32 2D tensor / async
@@ -96,6 +114,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reciprocal float32 0D scalar / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reciprocal float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reciprocal float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reciprocal float32 2D tensor / async
@@ -106,6 +126,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reciprocal float32 5D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] sin float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] sin float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] sin float32 2D tensor / async
@@ -118,6 +140,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] sqrt float32 0D scalar / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] sqrt float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] sqrt float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] sqrt float32 2D tensor / async
@@ -128,6 +152,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] sqrt float32 5D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] tan float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] tan float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] tan float32 2D tensor / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_unary.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_unary.https.any.worker-expected.txt
index ce35d5c8..5bea302b 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_unary.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elementwise_unary.https.any.worker-expected.txt
@@ -1,5 +1,7 @@
 This is a testharness.js-based test.
-Found 138 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 164 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] abs float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] abs float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] abs float32 2D tensor / sync
@@ -10,6 +12,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] abs float32 5D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] ceil float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] ceil float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] ceil float32 2D tensor / sync
@@ -20,6 +24,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] ceil float32 5D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] cos float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] cos float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] cos float32 2D tensor / sync
@@ -32,6 +38,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] erf float32 0D scalar / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] erf float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] erf float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] erf float32 2D tensor / sync
@@ -42,6 +50,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] erf float32 5D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] exp float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] exp float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] exp float32 2D tensor / sync
@@ -52,6 +62,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] exp float32 5D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] floor float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] floor float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] floor float32 2D tensor / sync
@@ -64,6 +76,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] identity float32 0D scalar / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] identity float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] identity float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] identity float32 2D tensor / sync
@@ -74,6 +88,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] identity float32 5D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] log float32 positive 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] log float32 positive 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] log float32 positive 2D tensor / sync
@@ -84,6 +100,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] log float32 positive 5D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] neg float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] neg float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] neg float32 2D tensor / sync
@@ -96,6 +114,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reciprocal float32 0D scalar / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reciprocal float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reciprocal float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reciprocal float32 2D tensor / sync
@@ -106,6 +126,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reciprocal float32 5D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] sin float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] sin float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] sin float32 2D tensor / sync
@@ -118,6 +140,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] sqrt float32 0D scalar / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] sqrt float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] sqrt float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] sqrt float32 2D tensor / sync
@@ -128,6 +152,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] sqrt float32 5D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] tan float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] tan float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] tan float32 2D tensor / sync
@@ -138,6 +164,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] tan float32 5D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] abs float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] abs float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] abs float32 2D tensor / async
@@ -148,6 +176,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] abs float32 5D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] ceil float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] ceil float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] ceil float32 2D tensor / async
@@ -158,6 +188,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] ceil float32 5D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cos float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] cos float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] cos float32 2D tensor / async
@@ -170,6 +202,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] erf float32 0D scalar / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] erf float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] erf float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] erf float32 2D tensor / async
@@ -180,6 +214,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] erf float32 5D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] exp float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] exp float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] exp float32 2D tensor / async
@@ -190,6 +226,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] exp float32 5D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] floor float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] floor float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] floor float32 2D tensor / async
@@ -202,6 +240,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] identity float32 0D scalar / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] identity float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] identity float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] identity float32 2D tensor / async
@@ -212,6 +252,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] identity float32 5D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] log float32 positive 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] log float32 positive 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] log float32 positive 2D tensor / async
@@ -222,6 +264,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] log float32 positive 5D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] neg float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] neg float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] neg float32 2D tensor / async
@@ -234,6 +278,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reciprocal float32 0D scalar / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reciprocal float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reciprocal float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reciprocal float32 2D tensor / async
@@ -244,6 +290,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reciprocal float32 5D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] sin float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] sin float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] sin float32 2D tensor / async
@@ -256,6 +304,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] sqrt float32 0D scalar / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] sqrt float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] sqrt float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] sqrt float32 2D tensor / async
@@ -266,6 +316,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] sqrt float32 5D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] tan float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] tan float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] tan float32 2D tensor / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elu.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elu.https.any-expected.txt
index 3692083..5963507 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elu.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elu.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] elu float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] elu float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] elu float32 2D tensor default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elu.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elu.https.any.worker-expected.txt
index a680b2ee..6fe4a2b 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elu.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/elu.https.any.worker-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] elu float32 1D constant tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] elu float32 1D tensor default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] elu float32 2D tensor default options / sync
@@ -13,6 +15,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] elu float32 4D tensor negative options.alpha / sync
   Failed to execute 'elu' on 'MLGraphBuilder': The value of alpha must be greater than 0.
+[FAIL] elu float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] elu float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] elu float32 2D tensor default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/expand.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/expand.https.any-expected.txt
new file mode 100644
index 0000000..ef468d4e
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/expand.https.any-expected.txt
@@ -0,0 +1,47 @@
+This is a testharness.js-based test.
+[FAIL] expand float32 0D scalar to 1D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 0D scalar to 2D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 0D scalar to 3D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 0D scalar to 4D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 0D scalar to 5D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 1D constant tensor to 1D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 1D tensor to 1D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 1D tensor to 2D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 1D tensor to 3D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 1D tensor to 4D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 1D tensor to 5D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 2D tensor to 2D (1st dimension) / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 2D tensor to 2D (2nd dimension) / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 2D tensor to 2D (all dimensions) / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 2D tensor to 3D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 2D tensor to 4D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 2D tensor to 5D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 3D tensor to 3D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 3D tensor to 4D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 3D tensor to 5D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 4D tensor to 4D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] expand float32 4D tensor to 5D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/expand.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/expand.https.any.worker-expected.txt
new file mode 100644
index 0000000..df062fa
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/expand.https.any.worker-expected.txt
@@ -0,0 +1,91 @@
+This is a testharness.js-based test.
+[FAIL] expand float32 0D scalar to 1D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 0D scalar to 2D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 0D scalar to 3D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 0D scalar to 4D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 0D scalar to 5D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 1D constant tensor to 1D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 1D tensor to 1D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 1D tensor to 2D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 1D tensor to 3D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 1D tensor to 4D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 1D tensor to 5D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 2D tensor to 2D (1st dimension) / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 2D tensor to 2D (2nd dimension) / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 2D tensor to 2D (all dimensions) / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 2D tensor to 3D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 2D tensor to 4D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 2D tensor to 5D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 3D tensor to 3D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 3D tensor to 4D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 3D tensor to 5D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 4D tensor to 4D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 4D tensor to 5D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] expand float32 0D scalar to 1D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 0D scalar to 2D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 0D scalar to 3D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 0D scalar to 4D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 0D scalar to 5D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 1D constant tensor to 1D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 1D tensor to 1D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 1D tensor to 2D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 1D tensor to 3D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 1D tensor to 4D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 1D tensor to 5D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 2D tensor to 2D (1st dimension) / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 2D tensor to 2D (2nd dimension) / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 2D tensor to 2D (all dimensions) / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 2D tensor to 3D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 2D tensor to 4D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 2D tensor to 5D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 3D tensor to 3D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 3D tensor to 4D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 3D tensor to 5D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 4D tensor to 4D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] expand float32 4D tensor to 5D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/gather.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/gather.https.any-expected.txt
new file mode 100644
index 0000000..8edf761b
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/gather.https.any-expected.txt
@@ -0,0 +1,39 @@
+This is a testharness.js-based test.
+[FAIL] gather float32 1D tensor and uint32 0D scalar indices default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gather float32 1D tensor and int64 0D scalar indices default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gather float32 1D tensor and int64 1D indices default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gather float32 1D tensor and int64 2D indices default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gather float32 1D tensor and int64 3D indices default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gather float32 1D tensor and int64 4D indices default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gather float32 2D tensor and 0D scalar indices default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gather float32 2D tensor and 1D indices default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gather float32 2D tensor and 2D indices default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gather float32 2D tensor and 3D indices default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gather float32 2D tensor and 4D indices default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gather float32 3D tensor and 2D indices default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gather float32 4D tensor and 2D indices default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gather float32 5D tensor and 1D indices default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gather float32 3D tensor and 1D indices options.axis=1 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gather float32 3D tensor and 2D indices options.axis=2 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gather float32 4D tensor and 2D indices explict options.axis=0 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gather float32 5D tensor and 0D scalar indices options.axis=4 / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/gather.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/gather.https.any.worker-expected.txt
new file mode 100644
index 0000000..0a54d96
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/gather.https.any.worker-expected.txt
@@ -0,0 +1,75 @@
+This is a testharness.js-based test.
+[FAIL] gather float32 1D tensor and uint32 0D scalar indices default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 1D tensor and int64 0D scalar indices default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 1D tensor and int64 1D indices default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 1D tensor and int64 2D indices default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 1D tensor and int64 3D indices default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 1D tensor and int64 4D indices default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 2D tensor and 0D scalar indices default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 2D tensor and 1D indices default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 2D tensor and 2D indices default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 2D tensor and 3D indices default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 2D tensor and 4D indices default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 3D tensor and 2D indices default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 4D tensor and 2D indices default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 5D tensor and 1D indices default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 3D tensor and 1D indices options.axis=1 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 3D tensor and 2D indices options.axis=2 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 4D tensor and 2D indices explict options.axis=0 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 5D tensor and 0D scalar indices options.axis=4 / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gather float32 1D tensor and uint32 0D scalar indices default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gather float32 1D tensor and int64 0D scalar indices default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gather float32 1D tensor and int64 1D indices default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gather float32 1D tensor and int64 2D indices default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gather float32 1D tensor and int64 3D indices default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gather float32 1D tensor and int64 4D indices default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gather float32 2D tensor and 0D scalar indices default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gather float32 2D tensor and 1D indices default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gather float32 2D tensor and 2D indices default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gather float32 2D tensor and 3D indices default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gather float32 2D tensor and 4D indices default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gather float32 3D tensor and 2D indices default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gather float32 4D tensor and 2D indices default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gather float32 5D tensor and 1D indices default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gather float32 3D tensor and 1D indices options.axis=1 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gather float32 3D tensor and 2D indices options.axis=2 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gather float32 4D tensor and 2D indices explict options.axis=0 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gather float32 5D tensor and 0D scalar indices options.axis=4 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/gemm.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/gemm.https.any-expected.txt
index d132607..0605d6c6 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/gemm.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/gemm.https.any-expected.txt
@@ -3,6 +3,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] gemm two float32 2D tensors default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] gemm two float32 2D constant tensors options.c / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] gemm two float32 2D tensors options.c / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] gemm two float32 2D tensors broadcast options.c [1, 5] => [3, 5] / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/gemm.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/gemm.https.any.worker-expected.txt
index c73f225..29b077f2a 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/gemm.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/gemm.https.any.worker-expected.txt
@@ -3,6 +3,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] gemm two float32 2D tensors default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] gemm two float32 2D constant tensors options.c / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] gemm two float32 2D tensors options.c / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] gemm two float32 2D tensors broadcast options.c [1, 5] => [3, 5] / sync
@@ -47,6 +49,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] gemm two float32 2D tensors default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] gemm two float32 2D constant tensors options.c / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] gemm two float32 2D tensors options.c / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] gemm two float32 2D tensors broadcast options.c [1, 5] => [3, 5] / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/hard_sigmoid.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/hard_sigmoid.https.any-expected.txt
new file mode 100644
index 0000000..b7d927bd
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/hard_sigmoid.https.any-expected.txt
@@ -0,0 +1,31 @@
+This is a testharness.js-based test.
+[FAIL] hardSigmoid float32 positive 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] hardSigmoid float32 positive 1D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] hardSigmoid float32 positive 2D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] hardSigmoid float32 positive 3D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] hardSigmoid float32 positive 4D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] hardSigmoid float32 positive 5D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] hardSigmoid float32 positive 4D tensor specified positive options.alpha default options.beta / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] hardSigmoid float32 negative 4D tensor specified negative options.alpha default options.beta / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] hardSigmoid float32 positive 4D tensor specified positive options.beta default options.alpha / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] hardSigmoid float32 negative 4D tensor specified negative options.beta default options.alpha / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] hardSigmoid float32 positive 4D tensor specified all options (positive options.alpha and positive options.beta) / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] hardSigmoid float32 positive 4D tensor specified all options (negative options.alpha and negative options.beta) / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] hardSigmoid float32 negative 4D tensor all options (positive options.alpha and negative options.beta) / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] hardSigmoid float32 negative 4D tensor specified all options (negative options.alpha and positive options.beta) / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/hard_sigmoid.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/hard_sigmoid.https.any.worker-expected.txt
new file mode 100644
index 0000000..f1ac8475
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/hard_sigmoid.https.any.worker-expected.txt
@@ -0,0 +1,59 @@
+This is a testharness.js-based test.
+[FAIL] hardSigmoid float32 positive 1D constant tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] hardSigmoid float32 positive 1D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] hardSigmoid float32 positive 2D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] hardSigmoid float32 positive 3D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] hardSigmoid float32 positive 4D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] hardSigmoid float32 positive 5D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] hardSigmoid float32 positive 4D tensor specified positive options.alpha default options.beta / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] hardSigmoid float32 negative 4D tensor specified negative options.alpha default options.beta / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] hardSigmoid float32 positive 4D tensor specified positive options.beta default options.alpha / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] hardSigmoid float32 negative 4D tensor specified negative options.beta default options.alpha / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] hardSigmoid float32 positive 4D tensor specified all options (positive options.alpha and positive options.beta) / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] hardSigmoid float32 positive 4D tensor specified all options (negative options.alpha and negative options.beta) / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] hardSigmoid float32 negative 4D tensor all options (positive options.alpha and negative options.beta) / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] hardSigmoid float32 negative 4D tensor specified all options (negative options.alpha and positive options.beta) / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] hardSigmoid float32 positive 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] hardSigmoid float32 positive 1D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] hardSigmoid float32 positive 2D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] hardSigmoid float32 positive 3D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] hardSigmoid float32 positive 4D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] hardSigmoid float32 positive 5D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] hardSigmoid float32 positive 4D tensor specified positive options.alpha default options.beta / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] hardSigmoid float32 negative 4D tensor specified negative options.alpha default options.beta / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] hardSigmoid float32 positive 4D tensor specified positive options.beta default options.alpha / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] hardSigmoid float32 negative 4D tensor specified negative options.beta default options.alpha / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] hardSigmoid float32 positive 4D tensor specified all options (positive options.alpha and positive options.beta) / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] hardSigmoid float32 positive 4D tensor specified all options (negative options.alpha and negative options.beta) / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] hardSigmoid float32 negative 4D tensor all options (positive options.alpha and negative options.beta) / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] hardSigmoid float32 negative 4D tensor specified all options (negative options.alpha and positive options.beta) / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/hard_swish.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/hard_swish.https.any-expected.txt
index b1a7f73..5336c7e2 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/hard_swish.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/hard_swish.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] hardSwish float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] hardSwish float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] hardSwish float32 2D tensor / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/hard_swish.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/hard_swish.https.any.worker-expected.txt
index 2ef13b29..717ef1c 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/hard_swish.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/hard_swish.https.any.worker-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] hardSwish float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] hardSwish float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] hardSwish float32 2D tensor / sync
@@ -9,6 +11,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] hardSwish float32 5D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] hardSwish float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] hardSwish float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] hardSwish float32 2D tensor / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/idlharness.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/idlharness.https.any-expected.txt
index fd23c36..41ddadb 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/idlharness.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/idlharness.https.any-expected.txt
@@ -1,19 +1,11 @@
 This is a testharness.js-based test.
-Found 48 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 39 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] idl_test setup
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] NavigatorML must be primary interface of navigator
   assert_own_property: self does not have own property "NavigatorML" expected property "NavigatorML" missing
 [FAIL] Stringification of navigator
   assert_class_string: class string of navigator expected "[object NavigatorML]" but got "[object Navigator]"
-[FAIL] MLGraph must be primary interface of graph
-  assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: graph is not defined"
-[FAIL] Stringification of graph
-  assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: graph is not defined"
-[FAIL] MLContext interface: operation createCommandEncoder()
-  assert_own_property: interface prototype object missing non-static operation expected property "createCommandEncoder" missing
-[FAIL] MLContext interface: context must inherit property "createCommandEncoder()" with the proper type
-  assert_inherits: property "createCommandEncoder" not found in prototype chain
 [FAIL] MLCommandEncoder interface: existence and properties of interface object
   assert_own_property: self does not have own property "MLCommandEncoder" expected property "MLCommandEncoder" missing
 [FAIL] MLCommandEncoder interface object length
@@ -32,30 +24,36 @@
   assert_own_property: self does not have own property "MLCommandEncoder" expected property "MLCommandEncoder" missing
 [FAIL] MLCommandEncoder interface: operation finish(optional GPUCommandBufferDescriptor)
   assert_own_property: self does not have own property "MLCommandEncoder" expected property "MLCommandEncoder" missing
+[FAIL] MLContext interface: operation createCommandEncoder()
+  assert_own_property: interface prototype object missing non-static operation expected property "createCommandEncoder" missing
+[FAIL] MLContext interface: context must inherit property "createCommandEncoder()" with the proper type
+  assert_inherits: property "createCommandEncoder" not found in prototype chain
+[FAIL] MLGraph must be primary interface of graph
+  assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: graph is not defined"
+[FAIL] Stringification of graph
+  assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: graph is not defined"
 [FAIL] MLGraphBuilder interface: operation constant(MLOperandDescriptor, MLBufferView)
   assert_equals: property has wrong .length expected 1 but got 2
 [FAIL] MLGraphBuilder interface: operation constant(double, optional MLOperandDataType)
   assert_equals: property has wrong .length expected 1 but got 2
+[FAIL] MLGraphBuilder interface: operation not(MLOperand)
+  assert_own_property: interface prototype object missing non-static operation expected property "not" missing
 [FAIL] MLGraphBuilder interface: operation gru(MLOperand, MLOperand, MLOperand, unsigned long, unsigned long, optional MLGruOptions)
   assert_own_property: interface prototype object missing non-static operation expected property "gru" missing
 [FAIL] MLGraphBuilder interface: operation gruCell(MLOperand, MLOperand, MLOperand, MLOperand, unsigned long, optional MLGruCellOptions)
   assert_own_property: interface prototype object missing non-static operation expected property "gruCell" missing
-[FAIL] MLGraphBuilder interface: operation hardSigmoid(MLOperand, optional MLHardSigmoidOptions)
-  assert_own_property: interface prototype object missing non-static operation expected property "hardSigmoid" missing
-[FAIL] MLGraphBuilder interface: operation hardSigmoid(optional MLHardSigmoidOptions)
-  assert_own_property: interface prototype object missing non-static operation expected property "hardSigmoid" missing
 [FAIL] MLGraphBuilder interface: operation lstm(MLOperand, MLOperand, MLOperand, unsigned long, unsigned long, optional MLLstmOptions)
   assert_own_property: interface prototype object missing non-static operation expected property "lstm" missing
 [FAIL] MLGraphBuilder interface: operation lstmCell(MLOperand, MLOperand, MLOperand, MLOperand, MLOperand, unsigned long, optional MLLstmCellOptions)
   assert_own_property: interface prototype object missing non-static operation expected property "lstmCell" missing
 [FAIL] MLGraphBuilder interface: operation l2Pool2d(MLOperand, optional MLPool2dOptions)
   assert_own_property: interface prototype object missing non-static operation expected property "l2Pool2d" missing
-[FAIL] MLGraphBuilder interface: operation softplus(MLOperand, optional MLSoftplusOptions)
-  assert_own_property: interface prototype object missing non-static operation expected property "softplus" missing
-[FAIL] MLGraphBuilder interface: operation softplus(optional MLSoftplusOptions)
-  assert_own_property: interface prototype object missing non-static operation expected property "softplus" missing
-[FAIL] MLGraphBuilder interface: operation squeeze(MLOperand, optional MLSqueezeOptions)
-  assert_own_property: interface prototype object missing non-static operation expected property "squeeze" missing
+[FAIL] MLGraphBuilder interface: operation triangular(MLOperand, optional MLTriangularOptions)
+  assert_own_property: interface prototype object missing non-static operation expected property "triangular" missing
+[FAIL] MLGraphBuilder interface: builder must inherit property "not(MLOperand)" with the proper type
+  assert_inherits: property "not" not found in prototype chain
+[FAIL] MLGraphBuilder interface: calling not(MLOperand) on builder with too few arguments must throw TypeError
+  assert_inherits: property "not" not found in prototype chain
 [FAIL] MLGraphBuilder interface: builder must inherit property "gru(MLOperand, MLOperand, MLOperand, unsigned long, unsigned long, optional MLGruOptions)" with the proper type
   assert_inherits: property "gru" not found in prototype chain
 [FAIL] MLGraphBuilder interface: calling gru(MLOperand, MLOperand, MLOperand, unsigned long, unsigned long, optional MLGruOptions) on builder with too few arguments must throw TypeError
@@ -64,14 +62,6 @@
   assert_inherits: property "gruCell" not found in prototype chain
 [FAIL] MLGraphBuilder interface: calling gruCell(MLOperand, MLOperand, MLOperand, MLOperand, unsigned long, optional MLGruCellOptions) on builder with too few arguments must throw TypeError
   assert_inherits: property "gruCell" not found in prototype chain
-[FAIL] MLGraphBuilder interface: builder must inherit property "hardSigmoid(MLOperand, optional MLHardSigmoidOptions)" with the proper type
-  assert_inherits: property "hardSigmoid" not found in prototype chain
-[FAIL] MLGraphBuilder interface: calling hardSigmoid(MLOperand, optional MLHardSigmoidOptions) on builder with too few arguments must throw TypeError
-  assert_inherits: property "hardSigmoid" not found in prototype chain
-[FAIL] MLGraphBuilder interface: builder must inherit property "hardSigmoid(optional MLHardSigmoidOptions)" with the proper type
-  assert_inherits: property "hardSigmoid" not found in prototype chain
-[FAIL] MLGraphBuilder interface: calling hardSigmoid(optional MLHardSigmoidOptions) on builder with too few arguments must throw TypeError
-  assert_inherits: property "hardSigmoid" not found in prototype chain
 [FAIL] MLGraphBuilder interface: builder must inherit property "lstm(MLOperand, MLOperand, MLOperand, unsigned long, unsigned long, optional MLLstmOptions)" with the proper type
   assert_inherits: property "lstm" not found in prototype chain
 [FAIL] MLGraphBuilder interface: calling lstm(MLOperand, MLOperand, MLOperand, unsigned long, unsigned long, optional MLLstmOptions) on builder with too few arguments must throw TypeError
@@ -84,17 +74,9 @@
   assert_inherits: property "l2Pool2d" not found in prototype chain
 [FAIL] MLGraphBuilder interface: calling l2Pool2d(MLOperand, optional MLPool2dOptions) on builder with too few arguments must throw TypeError
   assert_inherits: property "l2Pool2d" not found in prototype chain
-[FAIL] MLGraphBuilder interface: builder must inherit property "softplus(MLOperand, optional MLSoftplusOptions)" with the proper type
-  assert_inherits: property "softplus" not found in prototype chain
-[FAIL] MLGraphBuilder interface: calling softplus(MLOperand, optional MLSoftplusOptions) on builder with too few arguments must throw TypeError
-  assert_inherits: property "softplus" not found in prototype chain
-[FAIL] MLGraphBuilder interface: builder must inherit property "softplus(optional MLSoftplusOptions)" with the proper type
-  assert_inherits: property "softplus" not found in prototype chain
-[FAIL] MLGraphBuilder interface: calling softplus(optional MLSoftplusOptions) on builder with too few arguments must throw TypeError
-  assert_inherits: property "softplus" not found in prototype chain
-[FAIL] MLGraphBuilder interface: builder must inherit property "squeeze(MLOperand, optional MLSqueezeOptions)" with the proper type
-  assert_inherits: property "squeeze" not found in prototype chain
-[FAIL] MLGraphBuilder interface: calling squeeze(MLOperand, optional MLSqueezeOptions) on builder with too few arguments must throw TypeError
-  assert_inherits: property "squeeze" not found in prototype chain
+[FAIL] MLGraphBuilder interface: builder must inherit property "triangular(MLOperand, optional MLTriangularOptions)" with the proper type
+  assert_inherits: property "triangular" not found in prototype chain
+[FAIL] MLGraphBuilder interface: calling triangular(MLOperand, optional MLTriangularOptions) on builder with too few arguments must throw TypeError
+  assert_inherits: property "triangular" not found in prototype chain
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/idlharness.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/idlharness.https.any.worker-expected.txt
index 9f2ea46b2..613172f 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/idlharness.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/idlharness.https.any.worker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 55 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 46 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] idl_test setup
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented"
 [FAIL] NavigatorML must be primary interface of navigator
@@ -8,20 +8,6 @@
   assert_class_string: class string of navigator expected "[object NavigatorML]" but got "[object WorkerNavigator]"
 [FAIL] NavigatorML interface: navigator must not have property "ml"
   assert_false: expected false got true
-[FAIL] MLGraph must be primary interface of graph
-  assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: graph is not defined"
-[FAIL] Stringification of graph
-  assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: graph is not defined"
-[FAIL] MLContext interface: operation compute(MLGraph, MLNamedArrayBufferViews, MLNamedArrayBufferViews)
-  assert_own_property: interface prototype object missing non-static operation expected property "compute" missing
-[FAIL] MLContext interface: operation createCommandEncoder()
-  assert_own_property: interface prototype object missing non-static operation expected property "createCommandEncoder" missing
-[FAIL] MLContext interface: context must inherit property "compute(MLGraph, MLNamedArrayBufferViews, MLNamedArrayBufferViews)" with the proper type
-  assert_inherits: property "compute" not found in prototype chain
-[FAIL] MLContext interface: calling compute(MLGraph, MLNamedArrayBufferViews, MLNamedArrayBufferViews) on context with too few arguments must throw TypeError
-  assert_inherits: property "compute" not found in prototype chain
-[FAIL] MLContext interface: context must inherit property "createCommandEncoder()" with the proper type
-  assert_inherits: property "createCommandEncoder" not found in prototype chain
 [FAIL] MLCommandEncoder interface: existence and properties of interface object
   assert_own_property: self does not have own property "MLCommandEncoder" expected property "MLCommandEncoder" missing
 [FAIL] MLCommandEncoder interface object length
@@ -40,36 +26,48 @@
   assert_own_property: self does not have own property "MLCommandEncoder" expected property "MLCommandEncoder" missing
 [FAIL] MLCommandEncoder interface: operation finish(optional GPUCommandBufferDescriptor)
   assert_own_property: self does not have own property "MLCommandEncoder" expected property "MLCommandEncoder" missing
+[FAIL] MLContext interface: operation compute(MLGraph, MLNamedArrayBufferViews, MLNamedArrayBufferViews)
+  assert_own_property: interface prototype object missing non-static operation expected property "compute" missing
+[FAIL] MLContext interface: operation createCommandEncoder()
+  assert_own_property: interface prototype object missing non-static operation expected property "createCommandEncoder" missing
+[FAIL] MLContext interface: context must inherit property "compute(MLGraph, MLNamedArrayBufferViews, MLNamedArrayBufferViews)" with the proper type
+  assert_inherits: property "compute" not found in prototype chain
+[FAIL] MLContext interface: calling compute(MLGraph, MLNamedArrayBufferViews, MLNamedArrayBufferViews) on context with too few arguments must throw TypeError
+  assert_inherits: property "compute" not found in prototype chain
+[FAIL] MLContext interface: context must inherit property "createCommandEncoder()" with the proper type
+  assert_inherits: property "createCommandEncoder" not found in prototype chain
+[FAIL] MLGraph must be primary interface of graph
+  assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: graph is not defined"
+[FAIL] Stringification of graph
+  assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: graph is not defined"
 [FAIL] MLGraphBuilder interface: operation constant(MLOperandDescriptor, MLBufferView)
   assert_equals: property has wrong .length expected 1 but got 2
 [FAIL] MLGraphBuilder interface: operation constant(double, optional MLOperandDataType)
   assert_equals: property has wrong .length expected 1 but got 2
 [FAIL] MLGraphBuilder interface: operation build(MLNamedOperands)
   assert_own_property: interface prototype object missing non-static operation expected property "build" missing
+[FAIL] MLGraphBuilder interface: operation not(MLOperand)
+  assert_own_property: interface prototype object missing non-static operation expected property "not" missing
 [FAIL] MLGraphBuilder interface: operation gru(MLOperand, MLOperand, MLOperand, unsigned long, unsigned long, optional MLGruOptions)
   assert_own_property: interface prototype object missing non-static operation expected property "gru" missing
 [FAIL] MLGraphBuilder interface: operation gruCell(MLOperand, MLOperand, MLOperand, MLOperand, unsigned long, optional MLGruCellOptions)
   assert_own_property: interface prototype object missing non-static operation expected property "gruCell" missing
-[FAIL] MLGraphBuilder interface: operation hardSigmoid(MLOperand, optional MLHardSigmoidOptions)
-  assert_own_property: interface prototype object missing non-static operation expected property "hardSigmoid" missing
-[FAIL] MLGraphBuilder interface: operation hardSigmoid(optional MLHardSigmoidOptions)
-  assert_own_property: interface prototype object missing non-static operation expected property "hardSigmoid" missing
 [FAIL] MLGraphBuilder interface: operation lstm(MLOperand, MLOperand, MLOperand, unsigned long, unsigned long, optional MLLstmOptions)
   assert_own_property: interface prototype object missing non-static operation expected property "lstm" missing
 [FAIL] MLGraphBuilder interface: operation lstmCell(MLOperand, MLOperand, MLOperand, MLOperand, MLOperand, unsigned long, optional MLLstmCellOptions)
   assert_own_property: interface prototype object missing non-static operation expected property "lstmCell" missing
 [FAIL] MLGraphBuilder interface: operation l2Pool2d(MLOperand, optional MLPool2dOptions)
   assert_own_property: interface prototype object missing non-static operation expected property "l2Pool2d" missing
-[FAIL] MLGraphBuilder interface: operation softplus(MLOperand, optional MLSoftplusOptions)
-  assert_own_property: interface prototype object missing non-static operation expected property "softplus" missing
-[FAIL] MLGraphBuilder interface: operation softplus(optional MLSoftplusOptions)
-  assert_own_property: interface prototype object missing non-static operation expected property "softplus" missing
-[FAIL] MLGraphBuilder interface: operation squeeze(MLOperand, optional MLSqueezeOptions)
-  assert_own_property: interface prototype object missing non-static operation expected property "squeeze" missing
+[FAIL] MLGraphBuilder interface: operation triangular(MLOperand, optional MLTriangularOptions)
+  assert_own_property: interface prototype object missing non-static operation expected property "triangular" missing
 [FAIL] MLGraphBuilder interface: builder must inherit property "build(MLNamedOperands)" with the proper type
   assert_inherits: property "build" not found in prototype chain
 [FAIL] MLGraphBuilder interface: calling build(MLNamedOperands) on builder with too few arguments must throw TypeError
   assert_inherits: property "build" not found in prototype chain
+[FAIL] MLGraphBuilder interface: builder must inherit property "not(MLOperand)" with the proper type
+  assert_inherits: property "not" not found in prototype chain
+[FAIL] MLGraphBuilder interface: calling not(MLOperand) on builder with too few arguments must throw TypeError
+  assert_inherits: property "not" not found in prototype chain
 [FAIL] MLGraphBuilder interface: builder must inherit property "gru(MLOperand, MLOperand, MLOperand, unsigned long, unsigned long, optional MLGruOptions)" with the proper type
   assert_inherits: property "gru" not found in prototype chain
 [FAIL] MLGraphBuilder interface: calling gru(MLOperand, MLOperand, MLOperand, unsigned long, unsigned long, optional MLGruOptions) on builder with too few arguments must throw TypeError
@@ -78,14 +76,6 @@
   assert_inherits: property "gruCell" not found in prototype chain
 [FAIL] MLGraphBuilder interface: calling gruCell(MLOperand, MLOperand, MLOperand, MLOperand, unsigned long, optional MLGruCellOptions) on builder with too few arguments must throw TypeError
   assert_inherits: property "gruCell" not found in prototype chain
-[FAIL] MLGraphBuilder interface: builder must inherit property "hardSigmoid(MLOperand, optional MLHardSigmoidOptions)" with the proper type
-  assert_inherits: property "hardSigmoid" not found in prototype chain
-[FAIL] MLGraphBuilder interface: calling hardSigmoid(MLOperand, optional MLHardSigmoidOptions) on builder with too few arguments must throw TypeError
-  assert_inherits: property "hardSigmoid" not found in prototype chain
-[FAIL] MLGraphBuilder interface: builder must inherit property "hardSigmoid(optional MLHardSigmoidOptions)" with the proper type
-  assert_inherits: property "hardSigmoid" not found in prototype chain
-[FAIL] MLGraphBuilder interface: calling hardSigmoid(optional MLHardSigmoidOptions) on builder with too few arguments must throw TypeError
-  assert_inherits: property "hardSigmoid" not found in prototype chain
 [FAIL] MLGraphBuilder interface: builder must inherit property "lstm(MLOperand, MLOperand, MLOperand, unsigned long, unsigned long, optional MLLstmOptions)" with the proper type
   assert_inherits: property "lstm" not found in prototype chain
 [FAIL] MLGraphBuilder interface: calling lstm(MLOperand, MLOperand, MLOperand, unsigned long, unsigned long, optional MLLstmOptions) on builder with too few arguments must throw TypeError
@@ -98,17 +88,9 @@
   assert_inherits: property "l2Pool2d" not found in prototype chain
 [FAIL] MLGraphBuilder interface: calling l2Pool2d(MLOperand, optional MLPool2dOptions) on builder with too few arguments must throw TypeError
   assert_inherits: property "l2Pool2d" not found in prototype chain
-[FAIL] MLGraphBuilder interface: builder must inherit property "softplus(MLOperand, optional MLSoftplusOptions)" with the proper type
-  assert_inherits: property "softplus" not found in prototype chain
-[FAIL] MLGraphBuilder interface: calling softplus(MLOperand, optional MLSoftplusOptions) on builder with too few arguments must throw TypeError
-  assert_inherits: property "softplus" not found in prototype chain
-[FAIL] MLGraphBuilder interface: builder must inherit property "softplus(optional MLSoftplusOptions)" with the proper type
-  assert_inherits: property "softplus" not found in prototype chain
-[FAIL] MLGraphBuilder interface: calling softplus(optional MLSoftplusOptions) on builder with too few arguments must throw TypeError
-  assert_inherits: property "softplus" not found in prototype chain
-[FAIL] MLGraphBuilder interface: builder must inherit property "squeeze(MLOperand, optional MLSqueezeOptions)" with the proper type
-  assert_inherits: property "squeeze" not found in prototype chain
-[FAIL] MLGraphBuilder interface: calling squeeze(MLOperand, optional MLSqueezeOptions) on builder with too few arguments must throw TypeError
-  assert_inherits: property "squeeze" not found in prototype chain
+[FAIL] MLGraphBuilder interface: builder must inherit property "triangular(MLOperand, optional MLTriangularOptions)" with the proper type
+  assert_inherits: property "triangular" not found in prototype chain
+[FAIL] MLGraphBuilder interface: calling triangular(MLOperand, optional MLTriangularOptions) on builder with too few arguments must throw TypeError
+  assert_inherits: property "triangular" not found in prototype chain
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/instance_normalization.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/instance_normalization.https.any-expected.txt
new file mode 100644
index 0000000..61f6053
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/instance_normalization.https.any-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+[FAIL] instanceNormalization float32 4D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] instanceNormalization float32 4D tensor options.scale / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] instanceNormalization float32 4D tensor options.bias / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] instanceNormalization float32 4D tensor options.epsilon / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] instanceNormalization float32 4D tensor explict options.layout='nchw' / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] instanceNormalization float32 4D tensor options.layout='nhwc' / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] instanceNormalization float32 4D tensor all options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/instance_normalization.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/instance_normalization.https.any.worker-expected.txt
new file mode 100644
index 0000000..66ea830
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/instance_normalization.https.any.worker-expected.txt
@@ -0,0 +1,31 @@
+This is a testharness.js-based test.
+[FAIL] instanceNormalization float32 4D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] instanceNormalization float32 4D tensor options.scale / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] instanceNormalization float32 4D tensor options.bias / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] instanceNormalization float32 4D tensor options.epsilon / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] instanceNormalization float32 4D tensor explict options.layout='nchw' / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] instanceNormalization float32 4D tensor options.layout='nhwc' / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] instanceNormalization float32 4D tensor all options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] instanceNormalization float32 4D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] instanceNormalization float32 4D tensor options.scale / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] instanceNormalization float32 4D tensor options.bias / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] instanceNormalization float32 4D tensor options.epsilon / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] instanceNormalization float32 4D tensor explict options.layout='nchw' / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] instanceNormalization float32 4D tensor options.layout='nhwc' / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] instanceNormalization float32 4D tensor all options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/layer_normalization.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/layer_normalization.https.any-expected.txt
new file mode 100644
index 0000000..4bc83d8
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/layer_normalization.https.any-expected.txt
@@ -0,0 +1,25 @@
+This is a testharness.js-based test.
+[FAIL] layerNormalization float32 2D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] layerNormalization float32 3D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] layerNormalization float32 4D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] layerNormalization float32 5D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] layerNormalization float32 4D tensor options.scale / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] layerNormalization float32 4D tensor options.bias / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] layerNormalization float32 4D tensor options.axes=[2] / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] layerNormalization float32 4D tensor options.epsilon / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] layerNormalization float32 4D tensor options.scale and options.axes=[0, 2] / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] layerNormalization float32 4D tensor options.bias and options.axes=[3, 1, 2] / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] layerNormalization float32 4D tensor all options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/layer_normalization.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/layer_normalization.https.any.worker-expected.txt
new file mode 100644
index 0000000..49a131fa
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/layer_normalization.https.any.worker-expected.txt
@@ -0,0 +1,47 @@
+This is a testharness.js-based test.
+[FAIL] layerNormalization float32 2D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] layerNormalization float32 3D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] layerNormalization float32 4D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] layerNormalization float32 5D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] layerNormalization float32 4D tensor options.scale / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] layerNormalization float32 4D tensor options.bias / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] layerNormalization float32 4D tensor options.axes=[2] / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] layerNormalization float32 4D tensor options.epsilon / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] layerNormalization float32 4D tensor options.scale and options.axes=[0, 2] / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] layerNormalization float32 4D tensor options.bias and options.axes=[3, 1, 2] / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] layerNormalization float32 4D tensor all options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] layerNormalization float32 2D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] layerNormalization float32 3D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] layerNormalization float32 4D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] layerNormalization float32 5D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] layerNormalization float32 4D tensor options.scale / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] layerNormalization float32 4D tensor options.bias / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] layerNormalization float32 4D tensor options.axes=[2] / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] layerNormalization float32 4D tensor options.epsilon / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] layerNormalization float32 4D tensor options.scale and options.axes=[0, 2] / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] layerNormalization float32 4D tensor options.bias and options.axes=[3, 1, 2] / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] layerNormalization float32 4D tensor all options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/leaky_relu.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/leaky_relu.https.any-expected.txt
index b11e983..b40a396 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/leaky_relu.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/leaky_relu.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] leakyRelu float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] leakyRelu float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] leakyRelu float32 2D tensor default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/leaky_relu.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/leaky_relu.https.any.worker-expected.txt
index 5da0a0fc..91020d7 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/leaky_relu.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/leaky_relu.https.any.worker-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] leakyRelu float32 1D constant tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] leakyRelu float32 1D tensor default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] leakyRelu float32 2D tensor default options / sync
@@ -15,6 +17,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] leakyRelu float32 5D tensor options.alpha=0.0 / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] leakyRelu float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] leakyRelu float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] leakyRelu float32 2D tensor default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/linear.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/linear.https.any-expected.txt
index 7d73181..30ad2647 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/linear.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/linear.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] linear float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] linear float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] linear float32 2D tensor default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/linear.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/linear.https.any.worker-expected.txt
index 06ff164..ff6570c 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/linear.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/linear.https.any.worker-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] linear float32 1D constant tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] linear float32 1D tensor default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] linear float32 2D tensor default options / sync
@@ -21,6 +23,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] linear float32 negative 4D tensor all options (positive options.alpha and negative options.beta) / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] linear float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] linear float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] linear float32 2D tensor default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/matmul.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/matmul.https.any-expected.txt
index 248f733..6d2beb80 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/matmul.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/matmul.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] matmul float32 constant 1D and 1D tensors all positive produces a scalar / async
+  promise_test: Unhandled rejection with value: object "DataError: Failed to execute 'matmul' on 'MLGraphBuilder': The rank of input must be larger than or equal to 2."
 [FAIL] matmul float32 1D and 1D tensors all positive produces a scalar / async
   promise_test: Unhandled rejection with value: object "DataError: Failed to execute 'matmul' on 'MLGraphBuilder': The rank of input must be larger than or equal to 2."
 [FAIL] matmul float32 1D and 1D tensors all negative produces a scalar / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/matmul.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/matmul.https.any.worker-expected.txt
index 2422cc4..6a7d182 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/matmul.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/matmul.https.any.worker-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] matmul float32 constant 1D and 1D tensors all positive produces a scalar / sync
+  Failed to execute 'matmul' on 'MLGraphBuilder': The rank of input must be larger than or equal to 2.
 [FAIL] matmul float32 1D and 1D tensors all positive produces a scalar / sync
   Failed to execute 'matmul' on 'MLGraphBuilder': The rank of input must be larger than or equal to 2.
 [FAIL] matmul float32 1D and 1D tensors all negative produces a scalar / sync
@@ -31,6 +33,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] matmul float32 5D and 2D tensors / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] matmul float32 constant 1D and 1D tensors all positive produces a scalar / async
+  promise_test: Unhandled rejection with value: object "DataError: Failed to execute 'matmul' on 'MLGraphBuilder': The rank of input must be larger than or equal to 2."
 [FAIL] matmul float32 1D and 1D tensors all positive produces a scalar / async
   promise_test: Unhandled rejection with value: object "DataError: Failed to execute 'matmul' on 'MLGraphBuilder': The rank of input must be larger than or equal to 2."
 [FAIL] matmul float32 1D and 1D tensors all negative produces a scalar / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/pad.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/pad.https.any-expected.txt
index d1c1f36..2882708 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/pad.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/pad.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] pad float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] pad float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] pad float32 2D tensor default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/pad.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/pad.https.any.worker-expected.txt
index 6d31c82..3b61ced5 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/pad.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/pad.https.any.worker-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] pad float32 1D constant tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] pad float32 1D tensor default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] pad float32 2D tensor default options / sync
@@ -19,6 +21,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] pad float32 4D tensor options.mode='symmetric' / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] pad float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] pad float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] pad float32 2D tensor default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/pooling.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/pooling.https.any-expected.txt
index f489196e..d95151f 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/pooling.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/pooling.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] averagePool2d float32 4D constant tensor all positive default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] averagePool2d float32 4D tensor all positive default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] averagePool2d float32 4D tensor all negative default options / async
@@ -39,6 +41,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] averagePool2d float32 4D tensor options.dilations with options.strides / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] maxPool2d float32 4D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] maxPool2d float32 4D tensor default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] maxPool2d float32 4D tensor options.windowDimensions / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/pooling.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/pooling.https.any.worker-expected.txt
index 15406db22..5eb77ab 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/pooling.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/pooling.https.any.worker-expected.txt
@@ -1,5 +1,7 @@
 This is a testharness.js-based test.
-Found 74 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 78 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] averagePool2d float32 4D constant tensor all positive default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] averagePool2d float32 4D tensor all positive default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] averagePool2d float32 4D tensor all negative default options / sync
@@ -40,6 +42,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] averagePool2d float32 4D tensor options.dilations with options.strides / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] maxPool2d float32 4D constant tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] maxPool2d float32 4D tensor default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] maxPool2d float32 4D tensor options.windowDimensions / sync
@@ -74,6 +78,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] maxPool2d float32 4D tensor options.dilations with options.strides / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] averagePool2d float32 4D constant tensor all positive default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] averagePool2d float32 4D tensor all positive default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] averagePool2d float32 4D tensor all negative default options / async
@@ -114,6 +120,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] averagePool2d float32 4D tensor options.dilations with options.strides / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] maxPool2d float32 4D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] maxPool2d float32 4D tensor default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] maxPool2d float32 4D tensor options.windowDimensions / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/prelu.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/prelu.https.any-expected.txt
index 68f8e3a..2751add1 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/prelu.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/prelu.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] prelu float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] prelu float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] prelu float32 2D tensors / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/prelu.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/prelu.https.any.worker-expected.txt
index 02f3a55..ae9382be 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/prelu.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/prelu.https.any.worker-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] prelu float32 1D constant tensors / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] prelu float32 1D tensors / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] prelu float32 2D tensors / sync
@@ -19,6 +21,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] prelu float32 broadcast 4D x 4D slope / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] prelu float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] prelu float32 1D tensors / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] prelu float32 2D tensors / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/reduction.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/reduction.https.any-expected.txt
index 3e6ccb6..d0db52c 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/reduction.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/reduction.https.any-expected.txt
@@ -1,5 +1,7 @@
 This is a testharness.js-based test.
-Found 149 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 159 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] reduceL1 float32 1D constant tensor all positive default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceL1 float32 1D tensor all positive default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceL1 float32 1D tensor all negative default options / async
@@ -32,6 +34,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceL1 float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reduceL2 float32 1D constant tensor all positive default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceL2 float32 1D tensor all positive default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceL2 float32 1D tensor all negative default options / async
@@ -64,6 +68,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceL2 float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reduceLogSum float32 1D constant tensor all non-negative default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceLogSum float32 1D tensor all non-negative default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceLogSum float32 1D tensor all non-negative integers default options / async
@@ -92,6 +98,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceLogSum float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reduceLogSumExp float32 1D constant tensor all positive default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceLogSumExp float32 1D tensor all positive default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceLogSumExp float32 1D tensor all negative default options / async
@@ -124,6 +132,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceLogSumExp float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reduceMax float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceMax float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceMax float32 2D tensor default options / async
@@ -150,6 +160,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceMax float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reduceMean float32 1D constant tensor all positive default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceMean float32 1D tensor all positive default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceMean float32 1D tensor all negative default options / async
@@ -182,6 +194,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceMean float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reduceMin float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceMin float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceMin float32 2D tensor default options / async
@@ -208,6 +222,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceMin float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reduceProduct float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceProduct float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceProduct float32 2D tensor default options / async
@@ -234,6 +250,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceProduct float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reduceSum float32 1D constant tensor all positive default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceSum float32 1D tensor all positive default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceSum float32 1D tensor all negative default options / async
@@ -266,6 +284,8 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceSum float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reduceSumSquare float32 1D constant tensor all positive default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceSumSquare float32 1D tensor all positive default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reduceSumSquare float32 1D tensor all negative default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/reduction.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/reduction.https.any.worker-expected.txt
index a661985..a545001 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/reduction.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/reduction.https.any.worker-expected.txt
@@ -1,5 +1,7 @@
 This is a testharness.js-based test.
-Found 298 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 318 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] reduceL1 float32 1D constant tensor all positive default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceL1 float32 1D tensor all positive default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceL1 float32 1D tensor all negative default options / sync
@@ -32,6 +34,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceL1 float32 4D tensor options.axes with options.keepDimensions=true / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reduceL2 float32 1D constant tensor all positive default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceL2 float32 1D tensor all positive default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceL2 float32 1D tensor all negative default options / sync
@@ -64,6 +68,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceL2 float32 4D tensor options.axes with options.keepDimensions=true / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reduceLogSum float32 1D constant tensor all non-negative default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceLogSum float32 1D tensor all non-negative default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceLogSum float32 1D tensor all non-negative integers default options / sync
@@ -92,6 +98,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceLogSum float32 4D tensor options.axes with options.keepDimensions=true / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reduceLogSumExp float32 1D constant tensor all positive default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceLogSumExp float32 1D tensor all positive default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceLogSumExp float32 1D tensor all negative default options / sync
@@ -124,6 +132,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceLogSumExp float32 4D tensor options.axes with options.keepDimensions=true / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reduceMax float32 1D constant tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceMax float32 1D tensor default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceMax float32 2D tensor default options / sync
@@ -150,6 +160,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceMax float32 4D tensor options.axes with options.keepDimensions=true / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reduceMean float32 1D constant tensor all positive default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceMean float32 1D tensor all positive default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceMean float32 1D tensor all negative default options / sync
@@ -182,6 +194,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceMean float32 4D tensor options.axes with options.keepDimensions=true / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reduceMin float32 1D constant tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceMin float32 1D tensor default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceMin float32 2D tensor default options / sync
@@ -208,6 +222,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceMin float32 4D tensor options.axes with options.keepDimensions=true / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reduceProduct float32 1D constant tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceProduct float32 1D tensor default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceProduct float32 2D tensor default options / sync
@@ -234,6 +250,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceProduct float32 4D tensor options.axes with options.keepDimensions=true / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reduceSum float32 1D constant tensor all positive default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceSum float32 1D tensor all positive default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceSum float32 1D tensor all negative default options / sync
@@ -266,6 +284,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceSum float32 4D tensor options.axes with options.keepDimensions=true / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reduceSumSquare float32 1D constant tensor all positive default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceSumSquare float32 1D tensor all positive default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceSumSquare float32 1D tensor all negative default options / sync
@@ -298,6 +318,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reduceSumSquare float32 4D tensor options.axes with options.keepDimensions=true / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reduceL1 float32 1D constant tensor all positive default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceL1 float32 1D tensor all positive default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceL1 float32 1D tensor all negative default options / async
@@ -330,6 +352,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceL1 float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reduceL2 float32 1D constant tensor all positive default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceL2 float32 1D tensor all positive default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceL2 float32 1D tensor all negative default options / async
@@ -362,6 +386,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceL2 float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reduceLogSum float32 1D constant tensor all non-negative default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceLogSum float32 1D tensor all non-negative default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceLogSum float32 1D tensor all non-negative integers default options / async
@@ -390,6 +416,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceLogSum float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reduceLogSumExp float32 1D constant tensor all positive default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceLogSumExp float32 1D tensor all positive default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceLogSumExp float32 1D tensor all negative default options / async
@@ -422,6 +450,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceLogSumExp float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reduceMax float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceMax float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceMax float32 2D tensor default options / async
@@ -448,6 +478,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceMax float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reduceMean float32 1D constant tensor all positive default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceMean float32 1D tensor all positive default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceMean float32 1D tensor all negative default options / async
@@ -480,6 +512,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceMean float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reduceMin float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceMin float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceMin float32 2D tensor default options / async
@@ -506,6 +540,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceMin float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reduceProduct float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceProduct float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceProduct float32 2D tensor default options / async
@@ -532,6 +568,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceProduct float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reduceSum float32 1D constant tensor all positive default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceSum float32 1D tensor all positive default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceSum float32 1D tensor all negative default options / async
@@ -564,6 +602,8 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceSum float32 4D tensor options.axes with options.keepDimensions=true / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reduceSumSquare float32 1D constant tensor all positive default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceSumSquare float32 1D tensor all positive default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reduceSumSquare float32 1D tensor all negative default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/relu.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/relu.https.any-expected.txt
index 15605af..d8ab976 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/relu.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/relu.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] relu float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] relu float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] relu float32 2D tensor / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/relu.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/relu.https.any.worker-expected.txt
index e693197..074f88f 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/relu.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/relu.https.any.worker-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] relu float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] relu float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] relu float32 2D tensor / sync
@@ -9,6 +11,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] relu float32 5D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] relu float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] relu float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] relu float32 2D tensor / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/reshape.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/reshape.https.any-expected.txt
index 4397335..a357cb3e 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/reshape.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/reshape.https.any-expected.txt
@@ -9,5 +9,59 @@
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] reshape float32 tensor to 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (squeeze) float32 2D tensor by eliminating one dimension / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (squeeze) float32 3D tensor by eliminating one dimension / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (squeeze) float32 3D tensor by eliminating two dimensions / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (squeeze) float32 4D tensor by eliminating two dimensions / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (squeeze) float32 4D tensor by eliminating all dimensions / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (squeeze) float32 5D tensor by eliminating four dimensions / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (squeeze) float32 2D tensor by eliminating 1st dimension / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (squeeze) float32 3D tensor by eliminating 2nd and 3rd dimensions / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (squeeze) float32 4D tensor by eliminating 1st and 4th dimensions / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (squeeze) float32 5D tensor by eliminating 2nd and 3rd dimensions / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (squeeze) float32 5D tensor by eliminating 1st, 2nd and 5th dimensions / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (unsqueeze) float32 0D tensor to 4D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (unsqueeze) float32 1D tensor by adding one dimension / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (unsqueeze) float32 1D tensor by adding two dimensions / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (unsqueeze) float32 1D tensor to 5D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (unsqueeze) float32 1D tensor by adding 2nd and 3rd dimensions / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (unsqueeze) float32 2D tensor by adding one dimension / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (unsqueeze) float32 2D tensor by adding two dimensions / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (unsqueeze) float32 2D tensor by adding 1st dimension / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (unsqueeze) float32 2D tensor by adding 1st and 4th dimensions / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (unsqueeze) float32 3D tensor by adding 2nd and 3rd dimensions / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (unsqueeze) float32 4D tensor by adding 2nd dimension / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (unsqueeze) float32 5D tensor by adding 4th dimension / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (flatten) float32 3D tensor to 2D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (flatten) float32 4D to 2D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (flatten) float32 4D to 2D exclusive 1st dimension / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] reshape (flatten) float32 4D to 2D exclusive 4th dimension / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/reshape.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/reshape.https.any.worker-expected.txt
index 3c71ece9..5b516086 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/reshape.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/reshape.https.any.worker-expected.txt
@@ -1,4 +1,5 @@
 This is a testharness.js-based test.
+Found 64 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] reshape float32 tensor to a new shape (reorder all dimensions) / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reshape float32 tensor to a new shape (reduce dimensions) / sync
@@ -9,6 +10,60 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reshape float32 tensor to 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (squeeze) float32 2D tensor by eliminating one dimension / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (squeeze) float32 3D tensor by eliminating one dimension / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (squeeze) float32 3D tensor by eliminating two dimensions / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (squeeze) float32 4D tensor by eliminating two dimensions / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (squeeze) float32 4D tensor by eliminating all dimensions / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (squeeze) float32 5D tensor by eliminating four dimensions / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (squeeze) float32 2D tensor by eliminating 1st dimension / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (squeeze) float32 3D tensor by eliminating 2nd and 3rd dimensions / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (squeeze) float32 4D tensor by eliminating 1st and 4th dimensions / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (squeeze) float32 5D tensor by eliminating 2nd and 3rd dimensions / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (squeeze) float32 5D tensor by eliminating 1st, 2nd and 5th dimensions / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (unsqueeze) float32 0D tensor to 4D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (unsqueeze) float32 1D tensor by adding one dimension / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (unsqueeze) float32 1D tensor by adding two dimensions / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (unsqueeze) float32 1D tensor to 5D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (unsqueeze) float32 1D tensor by adding 2nd and 3rd dimensions / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (unsqueeze) float32 2D tensor by adding one dimension / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (unsqueeze) float32 2D tensor by adding two dimensions / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (unsqueeze) float32 2D tensor by adding 1st dimension / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (unsqueeze) float32 2D tensor by adding 1st and 4th dimensions / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (unsqueeze) float32 3D tensor by adding 2nd and 3rd dimensions / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (unsqueeze) float32 4D tensor by adding 2nd dimension / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (unsqueeze) float32 5D tensor by adding 4th dimension / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (flatten) float32 3D tensor to 2D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (flatten) float32 4D to 2D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (flatten) float32 4D to 2D exclusive 1st dimension / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] reshape (flatten) float32 4D to 2D exclusive 4th dimension / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] reshape float32 tensor to a new shape (reorder all dimensions) / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reshape float32 tensor to a new shape (reduce dimensions) / async
@@ -19,5 +74,59 @@
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] reshape float32 tensor to 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (squeeze) float32 2D tensor by eliminating one dimension / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (squeeze) float32 3D tensor by eliminating one dimension / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (squeeze) float32 3D tensor by eliminating two dimensions / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (squeeze) float32 4D tensor by eliminating two dimensions / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (squeeze) float32 4D tensor by eliminating all dimensions / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (squeeze) float32 5D tensor by eliminating four dimensions / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (squeeze) float32 2D tensor by eliminating 1st dimension / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (squeeze) float32 3D tensor by eliminating 2nd and 3rd dimensions / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (squeeze) float32 4D tensor by eliminating 1st and 4th dimensions / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (squeeze) float32 5D tensor by eliminating 2nd and 3rd dimensions / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (squeeze) float32 5D tensor by eliminating 1st, 2nd and 5th dimensions / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (unsqueeze) float32 0D tensor to 4D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (unsqueeze) float32 1D tensor by adding one dimension / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (unsqueeze) float32 1D tensor by adding two dimensions / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (unsqueeze) float32 1D tensor to 5D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (unsqueeze) float32 1D tensor by adding 2nd and 3rd dimensions / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (unsqueeze) float32 2D tensor by adding one dimension / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (unsqueeze) float32 2D tensor by adding two dimensions / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (unsqueeze) float32 2D tensor by adding 1st dimension / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (unsqueeze) float32 2D tensor by adding 1st and 4th dimensions / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (unsqueeze) float32 3D tensor by adding 2nd and 3rd dimensions / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (unsqueeze) float32 4D tensor by adding 2nd dimension / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (unsqueeze) float32 5D tensor by adding 4th dimension / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (flatten) float32 3D tensor to 2D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (flatten) float32 4D to 2D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (flatten) float32 4D to 2D exclusive 1st dimension / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] reshape (flatten) float32 4D to 2D exclusive 4th dimension / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/sigmoid.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/sigmoid.https.any-expected.txt
index 153be7d..39fab46 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/sigmoid.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/sigmoid.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] sigmoid float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] sigmoid float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] sigmoid float32 2D tensor / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/sigmoid.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/sigmoid.https.any.worker-expected.txt
index 843b94d..821c22f8 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/sigmoid.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/sigmoid.https.any.worker-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] sigmoid float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] sigmoid float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] sigmoid float32 2D tensor / sync
@@ -9,6 +11,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] sigmoid float32 5D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] sigmoid float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] sigmoid float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] sigmoid float32 2D tensor / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/slice.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/slice.https.any-expected.txt
index e920dfb..f89b401 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/slice.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/slice.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] slice float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] slice float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] slice float32 2D tensor / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/slice.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/slice.https.any.worker-expected.txt
index 4ac3fc2..35a58c9 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/slice.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/slice.https.any.worker-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] slice float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] slice float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] slice float32 2D tensor / sync
@@ -9,6 +11,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] slice float32 5D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] slice float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] slice float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] slice float32 2D tensor / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softmax.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softmax.https.any-expected.txt
index 5b124e9..dc6fca8 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softmax.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softmax.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] softmax float32 2D constant tensor all positive / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] softmax float32 2D tensor all positive / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] softmax float32 2D tensor all negative / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softmax.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softmax.https.any.worker-expected.txt
index d0d52e2..010c1c8 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softmax.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softmax.https.any.worker-expected.txt
@@ -1,8 +1,12 @@
 This is a testharness.js-based test.
+[FAIL] softmax float32 2D constant tensor all positive / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] softmax float32 2D tensor all positive / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] softmax float32 2D tensor all negative / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] softmax float32 2D constant tensor all positive / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] softmax float32 2D tensor all positive / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] softmax float32 2D tensor all negative / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softplus.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softplus.https.any-expected.txt
new file mode 100644
index 0000000..c123287
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softplus.https.any-expected.txt
@@ -0,0 +1,19 @@
+This is a testharness.js-based test.
+[FAIL] softplus float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] softplus float32 1D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] softplus float32 2D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] softplus float32 3D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] softplus float32 4D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] softplus float32 5D tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] softplus both positive float32 4D tensor and options.steepness / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] softplus both negative float32 4D tensor and options.steepness / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softplus.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softplus.https.any.worker-expected.txt
new file mode 100644
index 0000000..e174c180
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softplus.https.any.worker-expected.txt
@@ -0,0 +1,35 @@
+This is a testharness.js-based test.
+[FAIL] softplus float32 1D constant tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] softplus float32 1D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] softplus float32 2D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] softplus float32 3D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] softplus float32 4D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] softplus float32 5D tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] softplus both positive float32 4D tensor and options.steepness / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] softplus both negative float32 4D tensor and options.steepness / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] softplus float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] softplus float32 1D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] softplus float32 2D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] softplus float32 3D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] softplus float32 4D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] softplus float32 5D tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] softplus both positive float32 4D tensor and options.steepness / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] softplus both negative float32 4D tensor and options.steepness / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softsign.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softsign.https.any-expected.txt
index 7c8156f..7fbd29d7 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softsign.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softsign.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] softsign positive float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] softsign positive float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] softsign negative float32 1D tensor / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softsign.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softsign.https.any.worker-expected.txt
index a2b138b..e78f2cb3 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softsign.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/softsign.https.any.worker-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] softsign positive float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] softsign positive float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] softsign negative float32 1D tensor / sync
@@ -11,6 +13,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] softsign float32 5D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] softsign positive float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] softsign positive float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] softsign negative float32 1D tensor / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/split.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/split.https.any-expected.txt
index 4e7ffab..855f13aa 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/split.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/split.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] split float32 1D constant tensor number splits default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] split float32 1D tensor number splits default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] split float32 2D tensor number splits default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/split.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/split.https.any.worker-expected.txt
index 976d673..9991b62 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/split.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/split.https.any.worker-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] split float32 1D constant tensor number splits default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] split float32 1D tensor number splits default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] split float32 2D tensor number splits default options / sync
@@ -15,6 +17,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] split float32 5D tensor array splits options.axis / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] split float32 1D constant tensor number splits default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] split float32 1D tensor number splits default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] split float32 2D tensor number splits default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/tanh.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/tanh.https.any-expected.txt
index df2924d1..ac3b24a 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/tanh.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/tanh.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] tanh float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] tanh float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] tanh float32 2D tensor / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/tanh.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/tanh.https.any.worker-expected.txt
index 5272959..129e673 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/tanh.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/tanh.https.any.worker-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] tanh float32 1D constant tensor / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] tanh float32 1D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] tanh float32 2D tensor / sync
@@ -9,6 +11,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] tanh float32 5D tensor / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] tanh float32 1D constant tensor / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] tanh float32 1D tensor / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] tanh float32 2D tensor / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/transpose.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/transpose.https.any-expected.txt
index 614f014..6e0c9303 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/transpose.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/transpose.https.any-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] transpose float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] transpose float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
 [FAIL] transpose float32 2D tensor default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/transpose.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/transpose.https.any.worker-expected.txt
index 780cd28..dcda25780 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/transpose.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/transpose.https.any.worker-expected.txt
@@ -1,4 +1,6 @@
 This is a testharness.js-based test.
+[FAIL] transpose float32 1D constant tensor default options / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] transpose float32 1D tensor default options / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] transpose float32 2D tensor default options / sync
@@ -19,6 +21,8 @@
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
 [FAIL] transpose float32 5D tensor options.permutation / sync
   Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] transpose float32 1D constant tensor default options / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] transpose float32 1D tensor default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] transpose float32 2D tensor default options / async
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/where.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/where.https.any-expected.txt
new file mode 100644
index 0000000..36c6225d
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/where.https.any-expected.txt
@@ -0,0 +1,37 @@
+This is a testharness.js-based test.
+[FAIL] where float32 0D scalars / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] where float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] where float32 1D tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] where float32 2D tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] where float32 3D tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] where float32 4D tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] where float32 5D tensors / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] where float32 4D tensors only broadcast condition 0D to 4D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] where float32 4D tensors only broadcast condition 1D to 4D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] where float32 4D tensors only broadcast condition 2D to 4D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] where float32 4D tensors only broadcast condition 3D to 4D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] where float32 4D tensors only broadcast condition 4D to 4D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] where float32 4D tensors only broadcast trueValues 2D to 4D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] where float32 4D tensors only broadcast trueValues 4D to 4D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] where float32 4D tensors only broadcast falseValues 3D to 4D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] where float32 4D tensors only broadcast falseValues 4D to 4D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+[FAIL] where float32 4D tensors all broadcast 4D / async
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/where.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/where.https.any.worker-expected.txt
new file mode 100644
index 0000000..6f4e638
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/webnn/where.https.any.worker-expected.txt
@@ -0,0 +1,71 @@
+This is a testharness.js-based test.
+[FAIL] where float32 0D scalars / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] where float32 1D constant tensors / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] where float32 1D tensors / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] where float32 2D tensors / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] where float32 3D tensors / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] where float32 4D tensors / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] where float32 5D tensors / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] where float32 4D tensors only broadcast condition 0D to 4D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] where float32 4D tensors only broadcast condition 1D to 4D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] where float32 4D tensors only broadcast condition 2D to 4D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] where float32 4D tensors only broadcast condition 3D to 4D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] where float32 4D tensors only broadcast condition 4D to 4D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] where float32 4D tensors only broadcast trueValues 2D to 4D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] where float32 4D tensors only broadcast trueValues 4D to 4D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] where float32 4D tensors only broadcast falseValues 3D to 4D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] where float32 4D tensors only broadcast falseValues 4D to 4D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] where float32 4D tensors all broadcast 4D / sync
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Not implemented
+[FAIL] where float32 0D scalars / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] where float32 1D constant tensors / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] where float32 1D tensors / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] where float32 2D tensors / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] where float32 3D tensors / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] where float32 4D tensors / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] where float32 5D tensors / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] where float32 4D tensors only broadcast condition 0D to 4D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] where float32 4D tensors only broadcast condition 1D to 4D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] where float32 4D tensors only broadcast condition 2D to 4D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] where float32 4D tensors only broadcast condition 3D to 4D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] where float32 4D tensors only broadcast condition 4D to 4D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] where float32 4D tensors only broadcast trueValues 2D to 4D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] where float32 4D tensors only broadcast trueValues 4D to 4D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] where float32 4D tensors only broadcast falseValues 3D to 4D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] where float32 4D tensors only broadcast falseValues 4D to 4D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] where float32 4D tensors all broadcast 4D / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/fast/forms/file/file-appearance-bidi-filenames-expected.png b/third_party/blink/web_tests/platform/win11-arm64/fast/forms/file/file-appearance-bidi-filenames-expected.png
index 0a1c8b3..07dc38a 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/fast/forms/file/file-appearance-bidi-filenames-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/fast/forms/file/file-appearance-bidi-filenames-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/fast/ruby/nested-ruby-expected.png b/third_party/blink/web_tests/platform/win11-arm64/fast/ruby/nested-ruby-expected.png
index 52d952f..50d096e6 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/fast/ruby/nested-ruby-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/fast/ruby/nested-ruby-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/http/tests/inspector-protocol/fetch-later/activate-and-redirect-cross-site-when-document-alive.https-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/http/tests/inspector-protocol/fetch-later/activate-and-redirect-cross-site-when-document-alive.https-expected.txt
index 4350b23..07f3efc1 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/http/tests/inspector-protocol/fetch-later/activate-and-redirect-cross-site-when-document-alive.https-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/http/tests/inspector-protocol/fetch-later/activate-and-redirect-cross-site-when-document-alive.https-expected.txt
@@ -41,6 +41,7 @@
     redirectHasExtraInfo : false
     redirectResponse : {
         alternateProtocolUsage : unspecifiedReason
+        charset : 
         connectionId : <number>
         connectionReused : true
         encodedDataLength : 247
diff --git a/third_party/blink/web_tests/platform/win11-arm64/http/tests/inspector-protocol/fetch-later/activate-and-redirect-when-document-alive.https-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/http/tests/inspector-protocol/fetch-later/activate-and-redirect-when-document-alive.https-expected.txt
index e5c2339..4b908dc 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/http/tests/inspector-protocol/fetch-later/activate-and-redirect-when-document-alive.https-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/http/tests/inspector-protocol/fetch-later/activate-and-redirect-when-document-alive.https-expected.txt
@@ -41,6 +41,7 @@
     redirectHasExtraInfo : false
     redirectResponse : {
         alternateProtocolUsage : unspecifiedReason
+        charset : 
         connectionId : <number>
         connectionReused : true
         encodedDataLength : 225
@@ -95,6 +96,7 @@
     requestId : <string>
     response : {
         alternateProtocolUsage : unspecifiedReason
+        charset : 
         connectionId : <number>
         connectionReused : true
         encodedDataLength : 257
diff --git a/third_party/blink/web_tests/platform/win11-arm64/http/tests/inspector-protocol/fetch-later/activate-when-document-alive.https-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/http/tests/inspector-protocol/fetch-later/activate-when-document-alive.https-expected.txt
index d3a6124..3cfc133 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/http/tests/inspector-protocol/fetch-later/activate-when-document-alive.https-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/http/tests/inspector-protocol/fetch-later/activate-when-document-alive.https-expected.txt
@@ -36,6 +36,7 @@
     requestId : <string>
     response : {
         alternateProtocolUsage : unspecifiedReason
+        charset : 
         connectionId : <number>
         connectionReused : true
         encodedDataLength : 333
diff --git a/third_party/blink/web_tests/platform/win11-arm64/http/tests/inspector-protocol/network/response-charset-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/http/tests/inspector-protocol/network/response-charset-expected.txt
new file mode 100644
index 0000000..80bb757
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/http/tests/inspector-protocol/network/response-charset-expected.txt
@@ -0,0 +1,12 @@
+Tests that Network.Response includes the charset
+Network Enabled
+Fetching with no charset
+Network.Response.charset: 
+Fetching with utf-8
+Network.Response.charset: 
+Fetching with iso-8869-1
+Network.Response.charset: 
+Fetching utf-16 content
+Network.Response.charset: utf-16
+Response body: <p>Iñtërnâtiônàlizætiøn☃𝌆</p>
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/media/track/track-cue-rendering-ruby-expected.png b/third_party/blink/web_tests/platform/win11-arm64/media/track/track-cue-rendering-ruby-expected.png
index 16c9937..09c547f1 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/media/track/track-cue-rendering-ruby-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/media/track/track-cue-rendering-ruby-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/paint/markers/vertical-lr-expected.png b/third_party/blink/web_tests/platform/win11-arm64/paint/markers/vertical-lr-expected.png
index d6b8a823..ef35cfa 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/paint/markers/vertical-lr-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/paint/markers/vertical-lr-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/paint/markers/vertical-rl-expected.png b/third_party/blink/web_tests/platform/win11-arm64/paint/markers/vertical-rl-expected.png
index 732c0e9b..8edf7f71 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/paint/markers/vertical-rl-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/paint/markers/vertical-rl-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/svg/text/bidi-textlength-expected.png b/third_party/blink/web_tests/platform/win11-arm64/svg/text/bidi-textlength-expected.png
index dcb4d74..b35a799 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/svg/text/bidi-textlength-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/svg/text/bidi-textlength-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/svg/text/surrogate-pair-queries-expected.png b/third_party/blink/web_tests/platform/win11-arm64/svg/text/surrogate-pair-queries-expected.png
index f31cd1de..b315e0f 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/svg/text/surrogate-pair-queries-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/svg/text/surrogate-pair-queries-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/meter/meter-appearance-basic-vertical-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/meter/meter-appearance-basic-vertical-expected.png
index 091ed81..6dfdbc1aa 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/meter/meter-appearance-basic-vertical-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/meter/meter-appearance-basic-vertical-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/meter/meter-appearance-basic-vertical-rtl-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/meter/meter-appearance-basic-vertical-rtl-expected.png
new file mode 100644
index 0000000..121223f8
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/virtual/dark-color-scheme/fast/forms/color-scheme/meter/meter-appearance-basic-vertical-rtl-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/dynamic-color-scheme-change-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/dynamic-color-scheme-change-expected.png
deleted file mode 100644
index 81f3092..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/dynamic-color-scheme-change-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/horizontal-scrollbar-basic-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/horizontal-scrollbar-basic-expected.png
deleted file mode 100644
index 318f688..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-dark-mode/fast/forms/color-scheme/scrollbar/horizontal-scrollbar-basic-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-dark-mode/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-dark-mode/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
deleted file mode 100644
index ea5c7f6..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-dark-mode/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-dsf-150/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-dsf-150/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
deleted file mode 100644
index 4c7f74c..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-dsf-150/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-dsf-200/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-dsf-200/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
deleted file mode 100644
index 57d1d8a23..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-dsf-200/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
deleted file mode 100644
index 43a764f..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
deleted file mode 100644
index 48ef571..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
deleted file mode 100644
index 77e10b7..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar/composited/basic-scrollbar-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
deleted file mode 100644
index dbc5882..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-overlay-scrollbar-dark-mode/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-overlay-scrollbar-dark-mode/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
deleted file mode 100644
index cec275f..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-overlay-scrollbar-dark-mode/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
deleted file mode 100644
index bc150a8..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-overlay-scrollbar-hc/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-overlay-scrollbar/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-overlay-scrollbar/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
deleted file mode 100644
index 4847c25d..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-overlay-scrollbar/virtual/fluent-non-overlay-scrollbar/hover-over-scrollbar-thumb-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-overlay-scrollbar/visual/scrollbar-show-tickmarks-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-overlay-scrollbar/visual/scrollbar-show-tickmarks-expected.png
deleted file mode 100644
index 8dacd5aa..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/fluent-overlay-scrollbar/visual/scrollbar-show-tickmarks-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/text-antialias/color-emoji-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/text-antialias/color-emoji-expected.png
index d1cf373..befd43e 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/text-antialias/color-emoji-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/virtual/text-antialias/color-emoji-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/text-antialias/emoticons-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/text-antialias/emoticons-expected.png
index 5081fc0..3ccae2a 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/text-antialias/emoticons-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/virtual/text-antialias/emoticons-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/text-antialias/fallback-traits-fixup-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/text-antialias/fallback-traits-fixup-expected.png
index 4bc4d971..7bb6e50 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/text-antialias/fallback-traits-fixup-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/virtual/text-antialias/fallback-traits-fixup-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/text-antialias/unicode-fallback-font-expected.png b/third_party/blink/web_tests/platform/win11-arm64/virtual/text-antialias/unicode-fallback-font-expected.png
index 0acc91e..44dfe4c 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/text-antialias/unicode-fallback-font-expected.png
+++ b/third_party/blink/web_tests/platform/win11-arm64/virtual/text-antialias/unicode-fallback-font-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-enabled/external/wpt/webnn/gpu/cast.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-enabled/external/wpt/webnn/gpu/cast.https.any-expected.txt
new file mode 100644
index 0000000..d2490db
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-enabled/external/wpt/webnn/gpu/cast.https.any-expected.txt
@@ -0,0 +1,3 @@
+This is a testharness.js-based test.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-enabled/external/wpt/webnn/gpu/cast.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-enabled/external/wpt/webnn/gpu/cast.https.any.worker-expected.txt
new file mode 100644
index 0000000..de57b15c0
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-enabled/external/wpt/webnn/gpu/cast.https.any.worker-expected.txt
@@ -0,0 +1,96 @@
+This is a testharness.js-based test.
+Found 46 FAIL, 0 TIMEOUT, 0 NOTRUN.
+[FAIL] cast float32 0D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 1D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 2D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 3D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 5D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 4D tensor to uint32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float32 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float16 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float16 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float16 4D tensor to uint32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float16 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float16 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast float16 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int32 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int32 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int32 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int32 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int32 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint32 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint32 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint32 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint32 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint32 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint32 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int64 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int64 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int64 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int64 4D tensor to uint32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int64 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int64 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int8 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int8 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int8 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int8 4D tensor to uint32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int8 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast int8 4D tensor to uint8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint8 4D tensor to float32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint8 4D tensor to float16 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint8 4D tensor to int32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint8 4D tensor to uint32 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint8 4D tensor to int64 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+[FAIL] cast uint8 4D tensor to int8 / async
+  promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win11-arm64/wpt_internal/webcodecs/avc_encoder_config.https.any-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/wpt_internal/webcodecs/avc_encoder_config.https.any-expected.txt
deleted file mode 100644
index 829df1bc..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/wpt_internal/webcodecs/avc_encoder_config.https.any-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] Test AvcConfig supports 'avc' and 'annexb'
-  promise_test: Unhandled rejection with value: object "EncodingError: Flushing error."
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win11-arm64/wpt_internal/webcodecs/avc_encoder_config.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/wpt_internal/webcodecs/avc_encoder_config.https.any.worker-expected.txt
deleted file mode 100644
index 829df1bc..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/wpt_internal/webcodecs/avc_encoder_config.https.any.worker-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-[FAIL] Test AvcConfig supports 'avc' and 'annexb'
-  promise_test: Unhandled rejection with value: object "EncodingError: Flushing error."
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 916d9b8d..1dfaf7a 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -1212,6 +1212,7 @@
 [Worker]     method identity
 [Worker]     method input
 [Worker]     method instanceNormalization
+[Worker]     method l2Pool2d
 [Worker]     method layerNormalization
 [Worker]     method leakyRelu
 [Worker]     method lesser
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index 7a9557d..b0212eb 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -5679,6 +5679,7 @@
     method identity
     method input
     method instanceNormalization
+    method l2Pool2d
     method layerNormalization
     method leakyRelu
     method lesser
diff --git a/third_party/catapult b/third_party/catapult
index 432aa4a..c2c3cef 160000
--- a/third_party/catapult
+++ b/third_party/catapult
@@ -1 +1 @@
-Subproject commit 432aa4ae6c6931b15f595218bffb6c63512ac179
+Subproject commit c2c3cef34d1a1cee17fffcf34c98a6a9a352d064
diff --git a/third_party/devtools-frontend-internal b/third_party/devtools-frontend-internal
index abdf931..30cbeb8 160000
--- a/third_party/devtools-frontend-internal
+++ b/third_party/devtools-frontend-internal
@@ -1 +1 @@
-Subproject commit abdf93162b756e81b7d5d51ffa58bdf210cb4dde
+Subproject commit 30cbeb81ec54e2be41b6de16ad50353ea798740d
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index 294f601c..3a11358 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit 294f601c1dc3f2eeafe0c65278cc65668eb2c865
+Subproject commit 3a113586c2d333056dc944e92db447ddaa492762
diff --git a/third_party/lit/v3_0/lit.ts b/third_party/lit/v3_0/lit.ts
index 706a967..590a62f8 100644
--- a/third_party/lit/v3_0/lit.ts
+++ b/third_party/lit/v3_0/lit.ts
@@ -2,5 +2,5 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-export {css, html, nothing, LitElement} from 'lit/index.js';
+export {css, html, LitElement, nothing, PropertyValues} from 'lit/index.js';
 export {CrLitElement} from './cr_lit_element.js';
diff --git a/third_party/perfetto b/third_party/perfetto
index 3deb235..786ec3a 160000
--- a/third_party/perfetto
+++ b/third_party/perfetto
@@ -1 +1 @@
-Subproject commit 3deb2358149574207c12407c7a6b2a885a5cef3b
+Subproject commit 786ec3a414ad41aa627a88b83c7fd9bae5d59136
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 648d7ae1..d88c2729 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -34509,6 +34509,15 @@
   </description>
 </action>
 
+<action name="Signin_Impression_FromTipsNotification">
+  <owner>scottyoder@google.com</owner>
+  <description>
+    Recorded when sign-in is shown after the user interacts with a Tips
+    Notification on iOS.
+    (signin_metrics::AccessPoint::signin_metrics::AccessPoint)
+  </description>
+</action>
+
 <action name="Signin_Impression_FromUserManager" not_user_triggered="true">
   <owner>jkrcal@chromium.org</owner>
   <owner>droger@chromium.org</owner>
@@ -35292,6 +35301,14 @@
   </description>
 </action>
 
+<action name="Signin_Signin_FromTipsNotification">
+  <owner>scottyoder@google.com</owner>
+  <description>
+    Recorded on sign in start from access point
+    signin_metrics::AccessPoint::ACCESS_POINT_TIPS_NOTIFICATION. iOS Only.
+  </description>
+</action>
+
 <action name="Signin_Signin_FromUnknownAccessPoint">
   <owner>gogerald@chromium.org</owner>
   <description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 3605a2f..105c53ac 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -16698,6 +16698,7 @@
   <int value="-1850988416" label="(Obsolete) ExplicitLanguageAsk:disabled"/>
   <int value="-1850155382" label="EnablePerfettoSystemTracing:enabled"/>
   <int value="-1849706663" label="enable-password-force-saving:disabled"/>
+  <int value="-1849100017" label="DataSharingAndroid:disabled"/>
   <int value="-1847835522" label="disable-touch-adjustment"/>
   <int value="-1847776781"
       label="enable-loading-ipc-optimization-for-small-resources"/>
@@ -16992,6 +16993,7 @@
   <int value="-1695774453" label="skip-extra-ash-window-positioning"/>
   <int value="-1695608731"
       label="PageInfoAboutThisSiteDescriptionPlaceholder:disabled"/>
+  <int value="-1695235937" label="CampbellGlyph:enabled"/>
   <int value="-1694900665" label="HandwritingGestureEditing:enabled"/>
   <int value="-1693498375" label="CdmFactoryDaemon:enabled"/>
   <int value="-1693140558" label="FiltersInRecentsV2:disabled"/>
@@ -18150,6 +18152,7 @@
   <int value="-1182777927" label="ShareButtonInTopToolbar:enabled"/>
   <int value="-1182771360"
       label="AutofillVirtualCardsOnTouchToFillAndroid:disabled"/>
+  <int value="-1182667070" label="CampbellGlyph:disabled"/>
   <int value="-1182246276" label="EnableRFC8925:enabled"/>
   <int value="-1182087678"
       label="CrossOriginOpenerPolicyAccessReporting:disabled"/>
@@ -23571,6 +23574,7 @@
       label="SuppressClipboardSuggestionAfterFirstUsed:enabled"/>
   <int value="1333354155" label="FluentScrollbar:disabled"/>
   <int value="1333847867" label="NoScriptPreviews:enabled"/>
+  <int value="1334130934" label="DataSharingAndroid:enabled"/>
   <int value="1335454908" label="ShoppingCollection:enabled"/>
   <int value="1338356182" label="AutofillAssistantChromeEntry:disabled"/>
   <int value="1338510325" label="lacros-selection"/>
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index 1b3d4d4..76d886f 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -4506,6 +4506,17 @@
   </summary>
 </histogram>
 
+<histogram name="Android.Wallet.BoardingPass.Detected" enum="BooleanDetected"
+    expires_after="2024-12-31">
+  <owner>hanfeng@google.com</owner>
+  <owner>wallet-1p-integrations@google.com</owner>
+  <summary>
+    Records detected flight boarding pass barcode images on each page load. It's
+    only enabled on the Chrome Android app. It's only emitted once on page load,
+    either detected or not detected.
+  </summary>
+</histogram>
+
 <histogram name="Android.WebContentsState.SavedStateVersion" units="version"
     expires_after="2024-06-01">
   <owner>ellyjones@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 89cff7c4..f6864c57 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -196,6 +196,13 @@
   <variant name="TabletMode" summary="Tablet mode"/>
 </variants>
 
+<variants name="DriveFsSearchType">
+  <variant name="Modified" summary="Most recently modified files"/>
+  <variant name="Shared" summary="Files most recently shared with user"/>
+  <variant name="Total" summary="Total time to run all queries"/>
+  <variant name="Viewed" summary="Most recently viewed files"/>
+</variants>
+
 <variants name="GooglePhotosApi">
   <variant name="GetAlbum" summary="returns a single album"/>
   <variant name="GetAlbums" summary="returns all albums"/>
@@ -6264,6 +6271,98 @@
   </summary>
 </histogram>
 
+<histogram
+    name="Ash.Search.FileSuggestions.DriveRecents.DurationOnError.{SearchType}"
+    units="ms" expires_after="2024-10-01">
+  <owner>tbarzic@chromium.org</owner>
+  <owner>chromeos-launcher@google.com</owner>
+  <summary>
+    The duration of failed local Drive FS search when generating file
+    suggestions based on recent drive activity. The suggestions are generated on
+    demand when the user opens a supported UI surface - e.g. continue section in
+    the launcher. The suggestions are generated by performing multiple queries
+    on Drive FS. {SearchType} describes the type of query the search is
+    handling.
+  </summary>
+  <token key="SearchType" variants="DriveFsSearchType"/>
+</histogram>
+
+<histogram
+    name="Ash.Search.FileSuggestions.DriveRecents.DurationOnSuccess.{SearchType}"
+    units="ms" expires_after="2024-10-01">
+  <owner>tbarzic@chromium.org</owner>
+  <owner>chromeos-launcher@google.com</owner>
+  <summary>
+    The duration of successful local Drive FS search when generating file
+    suggestions based on recent drive activity. The suggestions are generated on
+    demand when the user opens a supported UI surface - e.g. continue section in
+    the launcher. The suggestions are generated by performing multiple queries
+    on Drive FS. {SearchType} describes the type of query the search is
+    handling. &quot;Total&quot; variant records the total time needed to
+    generate file suggestions.
+  </summary>
+  <token key="SearchType" variants="DriveFsSearchType"/>
+</histogram>
+
+<histogram
+    name="Ash.Search.FileSuggestions.DriveRecents.FirstSharedSuggestionIndex"
+    units="int" expires_after="2024-10-01">
+  <owner>tbarzic@chromium.org</owner>
+  <owner>chromeos-launcher@google.com</owner>
+  <summary>
+    The index of the first file suggested because it was shared with user in the
+    ordered list of drive file suggestions based on the local Drive FS search.
+    The suggestions are, for example, displayed in Launcher Continue Section.
+  </summary>
+</histogram>
+
+<histogram
+    name="Ash.Search.FileSuggestions.DriveRecents.ItemCount.{SearchType}"
+    units="int" expires_after="2024-10-01">
+  <owner>tbarzic@chromium.org</owner>
+  <owner>chromeos-launcher@google.com</owner>
+  <summary>
+    The number of items returned by local Drive FS search while generating file
+    suggestions based on recent drive activity. The suggestions are generated on
+    demand when the user opens a supported UI surface - e.g. continue section in
+    the launcher. The suggestions are generated by performing multiple queries
+    on Drive FS. {SearchType} describes the type of query the search is
+    handling. &quot;Total&quot; variant records the total number of generated
+    suggestions.
+  </summary>
+  <token key="SearchType" variants="DriveFsSearchType"/>
+</histogram>
+
+<histogram
+    name="Ash.Search.FileSuggestions.DriveRecents.ModifyingUserMetadataPresent"
+    enum="Boolean" expires_after="2024-10-01">
+  <owner>tbarzic@chromium.org</owner>
+  <owner>chromeos-launcher@google.com</owner>
+  <summary>
+    Whether a drive file returned by local drive FS search while generating file
+    suggestions based on recent drive activity (used for example in launcher
+    continue section) contains last modifying user metadata. Recorded while
+    generating file suggestions for each file suggestion that's surfaced because
+    it's been recently modified, in which case the suggestion justification
+    string depends on last modifying user metadata.
+  </summary>
+</histogram>
+
+<histogram
+    name="Ash.Search.FileSuggestions.DriveRecents.QueryResult.{SearchType}"
+    enum="DriveFileError" expires_after="2024-10-01">
+  <owner>tbarzic@chromium.org</owner>
+  <owner>chromeos-launcher@google.com</owner>
+  <summary>
+    The result of a local Drive FS query operation performed while generating
+    file suggestions based on recent drive activity. The suggestions are
+    generated on demand when the user opens a supported UI surface - e.g.
+    continue section in the launcher. The suggestions are generated by
+    performing multiple queries on Drive FS.
+  </summary>
+  <token key="SearchType" variants="DriveFsSearchType"/>
+</histogram>
+
 <histogram name="Ash.SearchModelUpdateTime.{TabletOrClamshell}" units="ms"
     expires_after="2023-10-01">
   <owner>yulunwu@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/content/histograms.xml b/tools/metrics/histograms/metadata/content/histograms.xml
index 13c95c79..d8003d16 100644
--- a/tools/metrics/histograms/metadata/content/histograms.xml
+++ b/tools/metrics/histograms/metadata/content/histograms.xml
@@ -1476,21 +1476,6 @@
   </summary>
 </histogram>
 
-<histogram name="ContentSuggestions.Feed.WebFeed.FollowCount.Engaged"
-    units="follows" expires_after="2024-06-30">
-  <owner>harringtond@chromium.org</owner>
-  <owner>feed@chromium.org</owner>
-  <summary>
-    Replaced with the ContentSuggestions.{FeedType}.FollowCount.Engaged2
-    histogram pattern because this one had a misleading name. It will be
-    effectively obsoleted in the future.
-
-    Android: The number of web feeds the user is following. Reported at most
-    once per feed visit, when the user engages (FeedEngagementType.Engaged) with
-    either the For-You or Following Feeds.
-  </summary>
-</histogram>
-
 <histogram name="ContentSuggestions.Feed.WebFeed.FollowCount.{Event}"
     units="follows" expires_after="2024-07-28">
   <owner>harringtond@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml
index 5d9dcc0..62f4d8fe 100644
--- a/tools/metrics/histograms/metadata/network/histograms.xml
+++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -2588,7 +2588,7 @@
   </summary>
 </histogram>
 
-<histogram name="Network.Shill.PortalDector.CAPPORTAdvertised.{Technology}"
+<histogram name="Network.Shill.PortalDector.CAPPORTAdvertised"
     enum="NetworkCAPPORTSupport" expires_after="2024-12-31">
   <owner>hugobenichi@google.com</owner>
   <owner>cros-network-metrics@google.com</owner>
@@ -2601,13 +2601,13 @@
     This metric is a redefinition of the same portal detection metric
     (&quot;Network.Shill.PortalDetector.CAPPORTAdvertised&quot;), but with a
     name matching the typo existing in the platform for m121 and m122 and fixed
-    in crrev/c/5223768. This metric can be removed once captive portal metrics
-    data on m121 and m121 is not needed anymore.
+    in crrev/c/5223768, and without the shill network Technology suffix. This
+    metric can be removed once captive portal metrics data on m121 and m121 is
+    not needed anymore.
   </summary>
-  <token key="Technology" variants="PhysicalTechnology"/>
 </histogram>
 
-<histogram name="Network.Shill.PortalDector.CAPPORTSupported.{Technology}"
+<histogram name="Network.Shill.PortalDector.CAPPORTSupported"
     enum="NetworkCAPPORTSupport" expires_after="2024-12-31">
   <owner>hugobenichi@google.com</owner>
   <owner>cros-network-metrics@google.com</owner>
@@ -2619,10 +2619,10 @@
     This metric is a redefinition of the same portal detection metric
     (&quot;Network.Shill.PortalDetector.CAPPORTAdvertised&quot;), but with a
     name matching the typo existing in the platform for m121 and m122 and fixed
-    in crrev/c/5223768. This metric can be removed once captive portal metrics
-    data on m121 and m121 is not needed anymore.
+    in crrev/c/5223768, and without the shill network Technology suffix. This
+    metric can be removed once captive portal metrics data on m121 and m121 is
+    not needed anymore.
   </summary>
-  <token key="Technology" variants="PhysicalTechnology"/>
 </histogram>
 
 <histogram name="Network.Shill.PortalDetector.AggregateResult.{Technology}"
@@ -2700,6 +2700,56 @@
   <token key="Technology" variants="PhysicalTechnology"/>
 </histogram>
 
+<histogram name="Network.Shill.PortalDetector.HTTPReponseCode.{Technology}"
+    units="response code" expires_after="2024-12-31">
+  <owner>hugobenichi@google.com</owner>
+  <owner>cros-network-metrics@google.com</owner>
+  <summary>
+    HTTP response code received by an HTTP probe used for network validation.
+    Response codes received for encrypted HTTPS probes are ignored because it is
+    assumed that HTTPS probes cannot be spoofed and always receive the expected
+    204 result.
+
+    Possible values are HTTP response codes in the [100, 599] range or one of
+    the three special values: 0 to indicate a bad response with an invalid
+    response code, 1 to indicate a 302 or 307 redirect response without a
+    Location header or with an invalid Location header which was not a URL, 2
+    for a 200 response without a Content-Length header or with an invalid
+    Content-Lenght header.
+
+    This metric is a redefinition of the same portal detection metric
+    (&quot;Network.Shill.PortalDetector.HTTPResponseCode&quot;), but with a name
+    matching the typo existing in the platform for m121 and m122 and fixed in
+    crrev/c/5267618. This metric can be removed once captive portal metrics data
+    on m121 and m121 is not needed anymore.
+  </summary>
+  <token key="Technology" variants="PhysicalTechnology"/>
+</histogram>
+
+<histogram
+    name="Network.Shill.PortalDetector.HTTPReponseContentLength.{Technology}"
+    units="bytes" expires_after="2024-12-31">
+  <owner>hugobenichi@google.com</owner>
+  <owner>cros-network-metrics@google.com</owner>
+  <summary>
+    Length in bytes of 200 responses received by a network validation HTTP probe
+    during a network validation attempt. 200 responses with no content or a
+    single byte of content are treated as 204 answers. These events are expected
+    to be recorded only once for a given network connection (network with
+    Internet acess). 200 responses with some actual content are treated as a
+    suspected portal redirect and trigger the portal sign-in flow. These events
+    are expected to be recorded multiple times until the user has signed into
+    the portal.
+
+    This metric is a redefinition of the same portal detection metric
+    (&quot;Network.Shill.PortalDetector.HTTPResponseContentLength&quot;), but
+    with a name matching the typo existing in the platform for m121 and m122 and
+    fixed in crrev/c/5267618. This metric can be removed once captive portal
+    metrics data on m121 and m121 is not needed anymore.
+  </summary>
+  <token key="Technology" variants="PhysicalTechnology"/>
+</histogram>
+
 <histogram name="Network.Shill.PortalDetector.HTTPResponseCode.{Technology}"
     units="response code" expires_after="2024-12-31">
   <owner>hugobenichi@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/preloading/histograms.xml b/tools/metrics/histograms/metadata/preloading/histograms.xml
index c5647e91..e0a4500 100644
--- a/tools/metrics/histograms/metadata/preloading/histograms.xml
+++ b/tools/metrics/histograms/metadata/preloading/histograms.xml
@@ -49,6 +49,9 @@
                the link element."/>
   <variant name="MouseBackButton"
       summary="When a mouse down of a mouse back button is seen."/>
+  <variant name="MouseHoverOrMouseDownOnBookmarkBar"
+      summary="When preloading is triggered by mouse hover bookmarkbar or
+               mouse down bookmark bar."/>
   <variant name="OmniboxDirectURLInput"
       summary="When preloading is triggered from the Omnibox DUI."/>
   <variant name="OmniboxMousePredictor"
diff --git a/tools/metrics/histograms/metadata/signin/enums.xml b/tools/metrics/histograms/metadata/signin/enums.xml
index 26e5ad25..681060f 100644
--- a/tools/metrics/histograms/metadata/signin/enums.xml
+++ b/tools/metrics/histograms/metadata/signin/enums.xml
@@ -409,6 +409,7 @@
   <int value="55" label="Restore primary account on profile load"/>
   <int value="56" label="Tab organization"/>
   <int value="57" label="Save to Drive iOS"/>
+  <int value="58" label="Tips Notification on iOS"/>
 </enum>
 
 <enum name="SigninAccountReconcilorState">
diff --git a/tools/metrics/histograms/metadata/web_apk/enums.xml b/tools/metrics/histograms/metadata/web_apk/enums.xml
index 2031464e..f78b06c38 100644
--- a/tools/metrics/histograms/metadata/web_apk/enums.xml
+++ b/tools/metrics/histograms/metadata/web_apk/enums.xml
@@ -131,13 +131,6 @@
   <int value="9" label="Download icon and hash error"/>
 </enum>
 
-<enum name="WebApkUpdateManifestResult">
-  <int value="0" label="Treated as another WebAPK"/>
-  <int value="1"
-      label="Treated as another WebAPK for legacy WebAPK(without ID)"/>
-  <int value="2" label="Found a manifest for update"/>
-</enum>
-
 <enum name="WebApkUpdateRequestQueued">
   <int value="0" label="Queued for the first time"/>
   <int value="1" label="Queued for the second time"/>
diff --git a/tools/metrics/histograms/metadata/web_apk/histograms.xml b/tools/metrics/histograms/metadata/web_apk/histograms.xml
index 826409e..b57362a 100644
--- a/tools/metrics/histograms/metadata/web_apk/histograms.xml
+++ b/tools/metrics/histograms/metadata/web_apk/histograms.xml
@@ -266,17 +266,6 @@
   <token key="WebApkDistributorType" variants="WebApkDistributorType"/>
 </histogram>
 
-<histogram name="WebApk.Update.DidGetInstallableData"
-    enum="WebApkUpdateManifestResult" expires_after="2024-03-10">
-  <owner>eirage@chromium.org</owner>
-  <owner>hartmanng@chromium.org</owner>
-  <owner>src/chrome/android/webapk/OWNERS</owner>
-  <summary>
-    When WebApkUpdateDataFetcher found a valid manifest, record whether the
-    manifest can be used to update the WebAPK.
-  </summary>
-</histogram>
-
 <histogram name="WebApk.Update.GooglePlayUpdateResult"
     enum="WebApkGooglePlayInstallResult" expires_after="2024-06-30">
   <owner>hartmanng@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 6b76de26..70a8364 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,24 +5,24 @@
             "full_remote_path": "perfetto-luci-artifacts/v42.0/linux-arm64/trace_processor_shell"
         },
         "win": {
-            "hash": "59fbcac876764b24915cc1c341d53efe7ed92a5b",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/4ab344d392b8b390c73132128d3c23e7f03818fe/trace_processor_shell.exe"
+            "hash": "f2c6b8d097054a1dbc1aeb47e10d17e3eab62744",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/e7e3adbde3052fa8c453eec0aa909b826540dbd9/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "46739eeb4b8f2a65a8a0aac57743767e6407f7bb",
             "full_remote_path": "perfetto-luci-artifacts/v42.0/linux-arm/trace_processor_shell"
         },
         "mac": {
-            "hash": "d28db75c3eac5b5bbf79825576bc5cd3926728e5",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/4ab344d392b8b390c73132128d3c23e7f03818fe/trace_processor_shell"
+            "hash": "2580362caa500ef18d61f3a0273b6191c855c9c9",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/e7e3adbde3052fa8c453eec0aa909b826540dbd9/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "789f24a091d50faafdd5d7c5096bb923d073f138",
             "full_remote_path": "perfetto-luci-artifacts/v42.0/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "01b55669645cf3d35cb61b06d0f27f4467a16e85",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/3deb2358149574207c12407c7a6b2a885a5cef3b/trace_processor_shell"
+            "hash": "20b7c0fc1a3dcfd10f7b4c6f3d9df15f60bf7baa",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/786ec3a414ad41aa627a88b83c7fd9bae5d59136/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/typescript/definitions/context_menus.d.ts b/tools/typescript/definitions/context_menus.d.ts
index da0ee02a..d37b221 100644
--- a/tools/typescript/definitions/context_menus.d.ts
+++ b/tools/typescript/definitions/context_menus.d.ts
@@ -4,9 +4,9 @@
 
 /**
  * @fileoverview Definitions for chrome.contextMenus API
- * Generated from: chrome/common/extensions/api/context_menus.json
+ * Partially generated from: chrome/common/extensions/api/context_menus.json
  * run `tools/json_schema_compiler/compiler.py
- * chrome/common/extensions/api/context_menus.json -g definitions` to
+ * chrome/common/extensions/api/context_menus.json -g ts_definitions` to
  * regenerate.
  */
 
@@ -57,19 +57,21 @@
         checked?: boolean;
       }
 
-      export function create(createProperties: {
-        type?: ItemType,
-        id?: string,
-        title?: string,
-        checked?: boolean,
-        contexts?: ContextType[],
-        visible?: boolean,
-        onclick?: (info: OnClickData, tab: tabs.Tab) => void,
-        parentId?: number|string,
-        documentUrlPatterns?: string[],
-        targetUrlPatterns?: string[],
-        enabled?: boolean,
-      }): number|string;
+      export interface CreateProperties {
+        type?: ItemType;
+        id?: string;
+        title?: string;
+        checked?: boolean;
+        contexts?: ContextType[];
+        visible?: boolean;
+        onclick?: (info: OnClickData, tab: tabs.Tab) => void;
+        parentId?: number|string;
+        documentUrlPatterns?: string[];
+        targetUrlPatterns?: string[];
+        enabled?: boolean;
+      }
+
+      export function create(createProperties: CreateProperties): number|string;
 
       export function update(id: number|string, updateProperties: {
         type?: ItemType,
diff --git a/tools/typescript/definitions/runtime.d.ts b/tools/typescript/definitions/runtime.d.ts
index d5012f2..2e85e972 100644
--- a/tools/typescript/definitions/runtime.d.ts
+++ b/tools/typescript/definitions/runtime.d.ts
@@ -12,7 +12,7 @@
     export namespace runtime {
       export let lastError: {
         message?: string,
-      } | undefined;
+      }|undefined;
 
       export let id: string;
 
@@ -26,11 +26,9 @@
         origin?: string;
       }
 
-      export interface ExtensionMessageEvent
-        extends ChromeEvent<(
-          message: any,
-          sender: MessageSender,
-          sendResponse: (response?: any) => void) => void> { }
+      export interface ExtensionMessageEvent extends ChromeEvent<
+          (message: any, sender: MessageSender,
+           sendResponse: (response?: any) => void) => void> {}
 
       export const onMessageExternal: ExtensionMessageEvent;
 
@@ -51,6 +49,11 @@
 
       export function getBackgroundPage(
           callback: (backgroundPage?: Window) => void): void;
+
+      // NOTE: This function supports multiple signatures, add as you need it.
+      export function sendMessage(
+          extensionId: string|null, message: any,
+          callback?: (response?: any) => void): void;
     }
   }
 }
diff --git a/ui/accessibility/accessibility_features.cc b/ui/accessibility/accessibility_features.cc
index 2f6ceeca..d4ee37e 100644
--- a/ui/accessibility/accessibility_features.cc
+++ b/ui/accessibility/accessibility_features.cc
@@ -187,7 +187,7 @@
 
 BASE_FEATURE(kExperimentalAccessibilityGoogleTtsHighQualityVoices,
              "ExperimentalAccessibilityGoogleTtsHighQualityVoices",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 bool IsExperimentalAccessibilityGoogleTtsHighQualityVoicesEnabled() {
   return base::FeatureList::IsEnabled(
       ::features::kExperimentalAccessibilityGoogleTtsHighQualityVoices);
diff --git a/ui/accessibility/ax_mode.cc b/ui/accessibility/ax_mode.cc
index 358ebe4..f97d5a7 100644
--- a/ui/accessibility/ax_mode.cc
+++ b/ui/accessibility/ax_mode.cc
@@ -51,8 +51,8 @@
       case AXMode::kLabelImages:
         flag_name = "kLabelImages";
         break;
-      case AXMode::kPDF:
-        flag_name = "kPDF";
+      case AXMode::kPDFPrinting:
+        flag_name = "kPDFPrinting";
         break;
       case AXMode::kPDFOcr:
         flag_name = "kPDFOcr";
diff --git a/ui/accessibility/ax_mode.h b/ui/accessibility/ax_mode.h
index 2b9f1e1..28a5b8c0 100644
--- a/ui/accessibility/ax_mode.h
+++ b/ui/accessibility/ax_mode.h
@@ -78,8 +78,8 @@
   static constexpr uint32_t kLabelImages = 1 << 6;
 
   // The accessibility tree will contain enough information to export
-  // an accessible PDF.
-  static constexpr uint32_t kPDF = 1 << 7;
+  // an accessible PDF when printing to PDF.
+  static constexpr uint32_t kPDFPrinting = 1 << 7;
 
   // The PDF renderer process will run OCR to extract text from an inaccessible
   // PDF and add it to the accessibility tree.
diff --git a/ui/accessibility/ax_mode_histogram_logger.cc b/ui/accessibility/ax_mode_histogram_logger.cc
index e2ba342..b5dc26e 100644
--- a/ui/accessibility/ax_mode_histogram_logger.cc
+++ b/ui/accessibility/ax_mode_histogram_logger.cc
@@ -73,7 +73,7 @@
                      AXMode::ModeFlagHistogramValue::UMA_AX_MODE_LABEL_IMAGES);
     }
 
-    if (new_mode_flags & ui::AXMode::kPDF) {
+    if (new_mode_flags & ui::AXMode::kPDFPrinting) {
       RecordModeFlag(prefix, AXMode::ModeFlagHistogramValue::UMA_AX_MODE_PDF);
     }
   }
diff --git a/ui/color/color_id.h b/ui/color/color_id.h
index 854dd08..b691556 100644
--- a/ui/color/color_id.h
+++ b/ui/color/color_id.h
@@ -548,6 +548,7 @@
   E_CPONLY(kColorWebNativeControlScrollbarThumb) \
   E_CPONLY(kColorWebNativeControlScrollbarThumbHovered) \
   E_CPONLY(kColorWebNativeControlScrollbarThumbInactive) \
+  E_CPONLY(kColorWebNativeControlScrollbarThumbOverlayMinimalMode) \
   E_CPONLY(kColorWebNativeControlScrollbarThumbPressed) \
   E_CPONLY(kColorWebNativeControlScrollbarTrack) \
   E_CPONLY(kColorWebNativeControlSlider) \
diff --git a/ui/color/color_id.mojom b/ui/color/color_id.mojom
index cd21c3a..53d7769 100644
--- a/ui/color/color_id.mojom
+++ b/ui/color/color_id.mojom
@@ -57,6 +57,7 @@
   kColorWebNativeControlScrollbarThumb,
   kColorWebNativeControlScrollbarThumbHovered,
   kColorWebNativeControlScrollbarThumbInactive,
+  kColorWebNativeControlScrollbarThumbOverlayMinimalMode,
   kColorWebNativeControlScrollbarThumbPressed,
   kColorWebNativeControlScrollbarTrack,
   kColorWebNativeControlSlider,
diff --git a/ui/color/color_provider_utils.cc b/ui/color/color_provider_utils.cc
index 05088426..f7b6561 100644
--- a/ui/color/color_provider_utils.cc
+++ b/ui/color/color_provider_utils.cc
@@ -118,6 +118,8 @@
      kColorWebNativeControlScrollbarThumbHovered},
     {RendererColorId::kColorWebNativeControlScrollbarThumbInactive,
      kColorWebNativeControlScrollbarThumbInactive},
+    {RendererColorId::kColorWebNativeControlScrollbarThumbOverlayMinimalMode,
+     kColorWebNativeControlScrollbarThumbOverlayMinimalMode},
     {RendererColorId::kColorWebNativeControlScrollbarThumbPressed,
      kColorWebNativeControlScrollbarThumbPressed},
     {RendererColorId::kColorWebNativeControlScrollbarTrack,
@@ -397,6 +399,8 @@
   // Set the colors for the scrollbar parts based on the emulated definitions
   // above.
   mixer[kColorWebNativeControlScrollbarArrowForeground] = {kColorForcedBtnText};
+  mixer[kColorWebNativeControlScrollbarThumbOverlayMinimalMode] = {
+      kColorWebNativeControlScrollbarArrowForeground};
   mixer[kColorWebNativeControlScrollbarArrowForegroundPressed] = {
       kColorForcedHighlight};
   mixer[kColorWebNativeControlScrollbarCorner] = {kColorForcedBtnFace};
@@ -446,6 +450,8 @@
   mixer[kColorWebNativeControlScrollbarThumbHovered] = {
       SkColorSetRGB(0x1A, 0xEB, 0xFF)};
   mixer[kColorWebNativeControlScrollbarThumbInactive] = {SK_ColorWHITE};
+  mixer[kColorWebNativeControlScrollbarThumbOverlayMinimalMode] = {
+      SK_ColorBLACK};
   mixer[kColorWebNativeControlScrollbarThumbPressed] = {
       SkColorSetRGB(0x1A, 0xEB, 0xFF)};
   mixer[kColorWebNativeControlScrollbarTrack] = {SK_ColorWHITE};
@@ -523,6 +529,8 @@
     mixer[kColorWebNativeControlScrollbarThumbHovered] = {
         SkColorSetA(SK_ColorWHITE, 0x4D)};
     mixer[kColorWebNativeControlScrollbarThumbInactive] = {SK_ColorWHITE};
+    mixer[kColorWebNativeControlScrollbarThumbOverlayMinimalMode] = {
+        SkColorSetA(SK_ColorWHITE, 0x8B)};
     mixer[kColorWebNativeControlScrollbarThumbPressed] = {
         SkColorSetA(SK_ColorWHITE, 0x80)};
     mixer[kColorWebNativeControlScrollbarTrack] = {
@@ -596,6 +604,8 @@
         SkColorSetA(SK_ColorBLACK, 0x4D)};
     mixer[kColorWebNativeControlScrollbarThumbInactive] = {
         SkColorSetRGB(0xEA, 0xEA, 0xEA)};
+    mixer[kColorWebNativeControlScrollbarThumbOverlayMinimalMode] = {
+        SkColorSetA(SK_ColorBLACK, 0x72)};
     mixer[kColorWebNativeControlScrollbarThumbPressed] = {
         SkColorSetA(SK_ColorBLACK, 0x80)};
     mixer[kColorWebNativeControlScrollbarTrack] = {
@@ -659,6 +669,8 @@
   mixer[kColorWebNativeControlScrollbarArrowForeground] = {kColorForcedBtnText};
   mixer[kColorWebNativeControlScrollbarArrowForegroundPressed] = {
       kColorForcedHighlight};
+  mixer[kColorWebNativeControlScrollbarThumbOverlayMinimalMode] = {
+      kColorForcedBtnText};
   mixer[kColorWebNativeControlScrollbarCorner] = {kColorForcedBtnFace};
   mixer[kColorWebNativeControlSlider] = {kColorForcedHighlight};
   mixer[kColorWebNativeControlSliderDisabled] = {kColorForcedGrayText};
diff --git a/ui/color/ui_color_mixer.cc b/ui/color/ui_color_mixer.cc
index 1bef8b4..b4893b6 100644
--- a/ui/color/ui_color_mixer.cc
+++ b/ui/color/ui_color_mixer.cc
@@ -406,6 +406,9 @@
                 : SkColorSetA(SK_ColorBLACK, 0x4D)};
   mixer[kColorWebNativeControlScrollbarThumbInactive] = {
       dark_mode ? SK_ColorWHITE : SkColorSetRGB(0xEA, 0xEA, 0xEA)};
+  mixer[kColorWebNativeControlScrollbarThumbOverlayMinimalMode] = {
+      dark_mode ? SkColorSetA(SK_ColorWHITE, 0x8B)
+                : SkColorSetA(SK_ColorBLACK, 0x72)};
   mixer[kColorWebNativeControlScrollbarThumbPressed] = {
       dark_mode ? SkColorSetA(SK_ColorWHITE, 0x80)
                 : SkColorSetA(SK_ColorBLACK, 0x80)};
diff --git a/ui/file_manager/file_manager/foreground/js/BUILD.gn b/ui/file_manager/file_manager/foreground/js/BUILD.gn
index f1917cb..82b412c 100644
--- a/ui/file_manager/file_manager/foreground/js/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/BUILD.gn
@@ -22,7 +22,7 @@
 files_app_path =
     rebase_path("$target_gen_dir/../../../tsc/file_manager/", root_build_dir)
 image_loader_path =
-    rebase_path("$root_gen_dir/ui/file_manager/preprocessed/image_loader",
+    rebase_path("$root_gen_dir/ui/file_manager/tsc/image_loader",
                 root_build_dir)
 
 optimize_webui("build") {
@@ -43,9 +43,9 @@
   ]
 
   deps = [
+    "//ash/webui/common/resources/cr_elements:build_ts",
     "//ui/file_manager:build_ts",
     "//ui/webui/resources/cr_components/color_change_listener:build_ts",
-    "//ash/webui/common/resources/cr_elements:build_ts",
     "//ui/webui/resources/js:build_ts",
   ]
 }
diff --git a/ui/file_manager/file_names.gni b/ui/file_manager/file_names.gni
index db33dfa..4ae80f3 100644
--- a/ui/file_manager/file_names.gni
+++ b/ui/file_manager/file_names.gni
@@ -1,7 +1,6 @@
 # Static files are used as-is from the repository.
 image_loader_static_js_files = [
   "image_loader/image_loader.js",
-  "image_loader/image_loader_client.js",
   "image_loader/image_loader_util.js",
   "image_loader/image_request_task.js",
   "image_loader/load_image_request.js",
@@ -14,7 +13,7 @@
 
   # "image_loader/image_loader.ts",
 
-  # "image_loader/image_loader_client.ts",
+  "image_loader/image_loader_client.ts",
 
   # "image_loader/image_loader_util.ts",
 
diff --git a/ui/file_manager/image_loader/BUILD.gn b/ui/file_manager/image_loader/BUILD.gn
index b557afb..1c437d54 100644
--- a/ui/file_manager/image_loader/BUILD.gn
+++ b/ui/file_manager/image_loader/BUILD.gn
@@ -40,7 +40,7 @@
     "background.ts",
     "cache.ts",
     "image_loader.js",
-    "image_loader_client.js",
+    "image_loader_client.ts",
     "image_loader_util.js",
     "image_orientation.ts",
     "image_request_task.js",
diff --git a/ui/file_manager/image_loader/image_loader_client.js b/ui/file_manager/image_loader/image_loader_client.js
deleted file mode 100644
index 53bfc585..0000000
--- a/ui/file_manager/image_loader/image_loader_client.js
+++ /dev/null
@@ -1,253 +0,0 @@
-// Copyright 2013 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {LruCache} from 'chrome://file-manager/common/js/lru_cache.js';
-
-import {LoadImageRequest, LoadImageResponse, LoadImageResponseStatus} from './load_image_request.js';
-
-/**
- * Client used to connect to the remote ImageLoader extension. Client class runs
- * in the extension, where the client.js is included (eg. Files app).
- * It sends remote requests using IPC to the ImageLoader class and forwards
- * its responses.
- *
- * Implements cache, which is stored in the calling extension.
- */
-export class ImageLoaderClient {
-  constructor() {
-    /**
-     * @type {number}
-     * @private
-     */
-    this.lastTaskId_ = 0;
-
-    /**
-     * LRU cache for images.
-     * @type {!LruCache.<{
-     *   timestamp: ?number,
-     *   width: number,
-     *   height: number,
-     *   ifd: ?string,
-     *   data: string
-     * }>}
-     * @private
-     */
-    this.cache_ = new LruCache(CACHE_MEMORY_LIMIT);
-  }
-
-  /**
-   * Returns a singleton instance.
-   * @return {ImageLoaderClient} Client instance.
-   */
-  static getInstance() {
-    // @ts-ignore: error TS2339: Property 'instance_' does not exist on type
-    // 'typeof ImageLoaderClient'.
-    if (!ImageLoaderClient.instance_) {
-      // @ts-ignore: error TS2339: Property 'instance_' does not exist on type
-      // 'typeof ImageLoaderClient'.
-      ImageLoaderClient.instance_ = new ImageLoaderClient();
-    }
-    // @ts-ignore: error TS2339: Property 'instance_' does not exist on type
-    // 'typeof ImageLoaderClient'.
-    return ImageLoaderClient.instance_;
-  }
-
-  /**
-   * Records binary metrics. Counts for true and false are stored as a
-   * histogram.
-   * @param {string} name Histogram's name.
-   * @param {boolean} value True or false.
-   */
-  static recordBinary(name, value) {
-    chrome.metricsPrivate.recordValue(
-        {
-          metricName: 'ImageLoader.Client.' + name,
-          type: chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LINEAR,
-          min: 1,  // According to histogram.h, this should be 1 for enums.
-          max: 2,  // Maximum should be exclusive.
-          buckets: 3,
-        },  // Number of buckets: 0, 1 and overflowing 2.
-        value ? 1 : 0);
-  }
-
-  /**
-   * Records percent metrics, stored as a histogram.
-   * @param {string} name Histogram's name.
-   * @param {number} value Value (0..100).
-   */
-  static recordPercentage(name, value) {
-    chrome.metricsPrivate.recordPercentage(
-        'ImageLoader.Client.' + name, Math.round(value));
-  }
-
-  /**
-   * Sends a message to the Image Loader extension.
-   * @param {!LoadImageRequest} request The image request.
-   * @param {!function(!LoadImageResponse)=} callback Response handling
-   *     callback. The response is passed as a hash array.
-   * @private
-   */
-  static sendMessage_(request, callback) {
-    // @ts-ignore: error TS2339: Property 'sendMessage' does not exist on type
-    // 'typeof runtime'.
-    chrome.runtime.sendMessage(EXTENSION_ID, request, callback);
-  }
-
-  /**
-   * Loads and resizes and image.
-   *
-   * @param {!LoadImageRequest} request
-   * @param {!function(!LoadImageResponse)=} callback Response handling
-   *     callback.
-   * @return {?number} Remote task id or null if loaded from cache.
-   */
-  load(request, callback) {
-    // Record cache usage.
-    ImageLoaderClient.recordPercentage(
-        'Cache.Usage', this.cache_.size() / CACHE_MEMORY_LIMIT * 100.0);
-
-    // Replace the client origin with the image loader extension origin.
-    // @ts-ignore: error TS18048: 'request.url' is possibly 'undefined'.
-    request.url = request.url.replace(CLIENT_URL_REGEX, IMAGE_LOADER_URL);
-    request.url = request.url.replace(CLIENT_SWA_REGEX, IMAGE_LOADER_URL);
-
-    // Try to load from cache, if available.
-    const cacheKey = LoadImageRequest.cacheKey(request);
-    if (cacheKey) {
-      if (request.cache) {
-        // Load from cache.
-        ImageLoaderClient.recordBinary('Cached', true);
-        let cachedValue = this.cache_.get(cacheKey);
-        // Check if the image in cache is up to date. If not, then remove it.
-        // It relies on comparing `null` equals to `undefined`.
-        // eslint-disable-next-line eqeqeq
-        if (cachedValue && cachedValue.timestamp != request.timestamp) {
-          this.cache_.remove(cacheKey);
-          cachedValue = null;
-        }
-        if (cachedValue && cachedValue.data && cachedValue.width &&
-            cachedValue.height) {
-          ImageLoaderClient.recordBinary('Cache.HitMiss', true);
-          // @ts-ignore: error TS2722: Cannot invoke an object which is possibly
-          // 'undefined'.
-          callback(
-              new LoadImageResponse(LoadImageResponseStatus.SUCCESS, null, {
-                width: cachedValue.width,
-                height: cachedValue.height,
-                ifd: cachedValue.ifd,
-                data: cachedValue.data,
-              }));
-          return null;
-        } else {
-          ImageLoaderClient.recordBinary('Cache.HitMiss', false);
-        }
-      } else {
-        // Remove from cache.
-        ImageLoaderClient.recordBinary('Cached', false);
-        this.cache_.remove(cacheKey);
-      }
-    }
-
-    // Not available in cache, performing a request to a remote extension.
-    this.lastTaskId_++;
-    request.taskId = this.lastTaskId_;
-
-    ImageLoaderClient.sendMessage_(request, (result_data) => {
-      if (chrome.runtime.lastError) {
-        console.warn(chrome.runtime.lastError.message);
-        // @ts-ignore: error TS2722: Cannot invoke an object which is possibly
-        // 'undefined'.
-        callback(new LoadImageResponse(
-            LoadImageResponseStatus.ERROR,
-            /** @type {number} */ (request.taskId)));
-        return;
-      }
-      // TODO(tapted): Move to a prototype for better type checking.
-      const result = /** @type {!LoadImageResponse} */ (result_data);
-      // Save to cache.
-      if (cacheKey && request.cache) {
-        const value = LoadImageResponse.cacheValue(result, request.timestamp);
-        if (value) {
-          this.cache_.put(cacheKey, value, value.data.length);
-        }
-      }
-      // @ts-ignore: error TS2722: Cannot invoke an object which is possibly
-      // 'undefined'.
-      callback(result);
-    });
-    return request.taskId;
-  }
-
-  /**
-   * Cancels the request. Note the original callback may still be invoked if
-   * this message doesn't reach the ImageLoader before it starts processing.
-   * @param {number} taskId Task id returned by ImageLoaderClient.load().
-   */
-  cancel(taskId) {
-    ImageLoaderClient.sendMessage_(
-        LoadImageRequest.createCancel(taskId), (_result) => {});
-  }
-
-  // Helper functions.
-
-  /**
-   * Loads and resizes and image.
-   *
-   * @param {!LoadImageRequest} request
-   * @param {HTMLImageElement} image Image node to load the requested picture
-   *     into.
-   * @param {VoidCallback} onSuccess Callback for success.
-   * @param {VoidCallback} onError Callback for failure.
-   * @return {?number} Remote task id or null if loaded from cache.
-   */
-  static loadToImage(request, image, onSuccess, onError) {
-    // @ts-ignore: error TS7006: Parameter 'result' implicitly has an 'any'
-    // type.
-    const callback = (result) => {
-      if (!result || result.status === LoadImageResponseStatus.ERROR) {
-        onError();
-        return;
-      }
-      image.src = result.data;
-      onSuccess();
-    };
-
-    return ImageLoaderClient.getInstance().load(request, callback);
-  }
-}
-
-/**
- * Image loader's extension id.
- * @const
- * @type {string}
- */
-const EXTENSION_ID = 'pmfjbimdmchhbnneeidfognadeopoehp';
-
-/**
- * Image loader client extension request URL matcher.
- * @const {!RegExp}
- */
-const CLIENT_URL_REGEX = /filesystem:chrome-extension:\/\/[a-z]+/;
-
-/**
- * Image loader client chrome://file-manager request URL matcher.
- * @const {!RegExp}
- */
-const CLIENT_SWA_REGEX = /filesystem:chrome:\/\/file-manager/;
-
-/**
- * All client request URL match CLIENT_URL_REGEX and all are
- * rewritten: the client extension id part of the request URL is replaced with
- * the image loader extension id.
- * @const {string}
- */
-const IMAGE_LOADER_URL = 'filesystem:chrome-extension://' + EXTENSION_ID;
-
-/**
- * Memory limit for images data in bytes.
- *
- * @const
- * @type {number}
- */
-const CACHE_MEMORY_LIMIT = 20 * 1024 * 1024;  // 20 MB.
diff --git a/ui/file_manager/image_loader/image_loader_client.ts b/ui/file_manager/image_loader/image_loader_client.ts
new file mode 100644
index 0000000..89807bb
--- /dev/null
+++ b/ui/file_manager/image_loader/image_loader_client.ts
@@ -0,0 +1,223 @@
+// Copyright 2013 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {LruCache} from 'chrome://file-manager/common/js/lru_cache.js';
+
+import {LoadImageRequest, LoadImageResponse, LoadImageResponseStatus} from './load_image_request.js';
+
+// TODO(b/319188711): Share this definition with load_image_request.js when it's
+// converted to TS.
+interface CacheValue {
+  timestamp: number|null;
+  width: number;
+  height: number;
+  ifd: string|null;
+  data: string;
+}
+
+let instance: ImageLoaderClient|null = null;
+
+/**
+ * Client used to connect to the remote ImageLoader extension. Client class runs
+ * in the extension, where the client.js is included (eg. Files app).
+ * It sends remote requests using IPC to the ImageLoader class and forwards
+ * its responses.
+ *
+ * Implements cache, which is stored in the calling extension.
+ */
+export class ImageLoaderClient {
+  private lastTaskId_: number = 0;
+  /**
+   * LRU cache for images.
+   */
+  private cache_ = new LruCache<CacheValue>(CACHE_MEMORY_LIMIT);
+
+  /**
+   * Returns a singleton instance.
+   */
+  static getInstance(): ImageLoaderClient {
+    if (!instance) {
+      instance = new ImageLoaderClient();
+    }
+    return instance;
+  }
+
+  /**
+   * Records binary metrics. Counts for true and false are stored as a
+   * histogram.
+   * @param name Histogram's name.
+   * @param value True or false.
+   */
+  static recordBinary(name: string, value: boolean) {
+    chrome.metricsPrivate.recordValue(
+        {
+          metricName: 'ImageLoader.Client.' + name,
+          type: chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LINEAR,
+          min: 1,      // According to histogram.h, this should be 1 for enums.
+          max: 2,      // Maximum should be exclusive.
+          buckets: 3,  // Number of buckets: 0, 1 and overflowing 2.
+        },
+        value ? 1 : 0);
+  }
+
+  /**
+   * Records percent metrics, stored as a histogram.
+   * @param name Histogram's name.
+   * @param value Value (0..100).
+   */
+  static recordPercentage(name: string, value: number) {
+    chrome.metricsPrivate.recordPercentage(
+        'ImageLoader.Client.' + name, Math.round(value));
+  }
+
+  /**
+   * Sends a message to the Image Loader extension.
+   * @param request The image request.
+   * @param callback Response handling callback. The response is passed as a
+   *     hash array.
+   */
+  private static sendMessage_(
+      request: LoadImageRequest, callback?: (r: LoadImageResponse) => void) {
+    chrome.runtime.sendMessage(EXTENSION_ID, request, callback);
+  }
+
+  /**
+   * Loads and resizes and image.
+   *
+   * @param callback Response handling callback.
+   * @return Remote task id or null if loaded from cache.
+   */
+  load(request: LoadImageRequest, callback: (r: LoadImageResponse) => void):
+      null|number {
+    // Record cache usage.
+    ImageLoaderClient.recordPercentage(
+        'Cache.Usage', this.cache_.size() / CACHE_MEMORY_LIMIT * 100.0);
+
+    // Replace the client origin with the image loader extension origin.
+    request.url = request.url ?? '';
+    request.url = request.url.replace(CLIENT_URL_REGEX, IMAGE_LOADER_URL);
+    request.url = request.url.replace(CLIENT_SWA_REGEX, IMAGE_LOADER_URL);
+
+    // Try to load from cache, if available.
+    const cacheKey = LoadImageRequest.cacheKey(request);
+    if (cacheKey) {
+      if (request.cache) {
+        // Load from cache.
+        ImageLoaderClient.recordBinary('Cached', true);
+        let cachedValue: CacheValue|null = this.cache_.get(cacheKey);
+        // Check if the image in cache is up to date. If not, then remove it.
+        // It relies on comparing `null` equals to `undefined`.
+        // eslint-disable-next-line eqeqeq
+        if (cachedValue && cachedValue.timestamp != request.timestamp) {
+          this.cache_.remove(cacheKey);
+          cachedValue = null;
+        }
+        if (cachedValue && cachedValue.data && cachedValue.width &&
+            cachedValue.height) {
+          ImageLoaderClient.recordBinary('Cache.HitMiss', true);
+          callback(
+              new LoadImageResponse(LoadImageResponseStatus.SUCCESS, null, {
+                width: cachedValue.width,
+                height: cachedValue.height,
+                ifd: cachedValue.ifd,
+                data: cachedValue.data,
+              }));
+          return null;
+        } else {
+          ImageLoaderClient.recordBinary('Cache.HitMiss', false);
+        }
+      } else {
+        // Remove from cache.
+        ImageLoaderClient.recordBinary('Cached', false);
+        this.cache_.remove(cacheKey);
+      }
+    }
+
+    // Not available in cache, performing a request to a remote extension.
+    this.lastTaskId_++;
+    request.taskId = this.lastTaskId_;
+
+    ImageLoaderClient.sendMessage_(request, (resultData) => {
+      if (chrome.runtime.lastError) {
+        console.warn(chrome.runtime.lastError.message);
+        callback(new LoadImageResponse(
+            LoadImageResponseStatus.ERROR, request.taskId!));
+        return;
+      }
+      const result = resultData;
+      // Save to cache.
+      if (cacheKey && request.cache) {
+        const value: CacheValue|null =
+            LoadImageResponse.cacheValue(result, request.timestamp);
+        if (value) {
+          this.cache_.put(cacheKey, value, value.data.length);
+        }
+      }
+      callback(result);
+    });
+    return request.taskId;
+  }
+
+  /**
+   * Cancels the request. Note the original callback may still be invoked if
+   * this message doesn't reach the ImageLoader before it starts processing.
+   * @param taskId Task id returned by ImageLoaderClient.load().
+   */
+  cancel(taskId: number) {
+    ImageLoaderClient.sendMessage_(
+        LoadImageRequest.createCancel(taskId), (_result) => {});
+  }
+
+  // Helper functions.
+
+  /**
+   * Loads and resizes and image.
+   *
+   * @param image Image node to load the requested picture into.
+   * @param onSuccess Callback for success.
+   * @param onError Callback for failure.
+   * @return Remote task id or null if loaded from cache.
+   */
+  static loadToImage(
+      request: LoadImageRequest, image: HTMLImageElement,
+      onSuccess: VoidCallback, onError: VoidCallback): null|number {
+    const callback = (result: LoadImageResponse) => {
+      if (!result || result.status === LoadImageResponseStatus.ERROR) {
+        onError();
+        return;
+      }
+      image.src = result.data!;
+      onSuccess();
+    };
+
+    return ImageLoaderClient.getInstance().load(request, callback);
+  }
+}
+
+/**
+ * Image loader's extension id.
+ */
+const EXTENSION_ID = 'pmfjbimdmchhbnneeidfognadeopoehp';
+
+/**
+ * Image loader client extension request URL matcher.
+ */
+const CLIENT_URL_REGEX = /filesystem:chrome-extension:\/\/[a-z]+/;
+
+/**
+ * Image loader client chrome://file-manager request URL matcher.
+ */
+const CLIENT_SWA_REGEX = /filesystem:chrome:\/\/file-manager/;
+
+/**
+ * All client request URL match CLIENT_URL_REGEX and all are
+ * rewritten: the client extension id part of the request URL is replaced with
+ * the image loader extension id.
+ */
+const IMAGE_LOADER_URL = 'filesystem:chrome-extension://' + EXTENSION_ID;
+
+/**
+ * Memory limit for images data in bytes.
+ */
+const CACHE_MEMORY_LIMIT = 20 * 1024 * 1024;  // 20 MB.
diff --git a/ui/native_theme/native_theme.h b/ui/native_theme/native_theme.h
index 772c7a34..342dafa 100644
--- a/ui/native_theme/native_theme.h
+++ b/ui/native_theme/native_theme.h
@@ -301,6 +301,7 @@
     // This allows clients to directly override the color values to support
     // element-specific web platform CSS.
     absl::optional<SkColor> thumb_color;
+    bool is_thumb_minimal_mode = false;
   };
 
 #if BUILDFLAG(IS_APPLE)
diff --git a/ui/native_theme/native_theme_fluent.cc b/ui/native_theme/native_theme_fluent.cc
index 17e3dca..8483cc3 100644
--- a/ui/native_theme/native_theme_fluent.cc
+++ b/ui/native_theme/native_theme_fluent.cc
@@ -119,12 +119,14 @@
   path.addRRect(rrect);
   canvas->clipPath(path, true);
 
-  auto get_color = [color_provider, state]() {
+  auto get_color = [color_provider, state, extra_params]() {
     ColorId thumb_color_id = kColorWebNativeControlScrollbarThumb;
     if (state == NativeTheme::kPressed) {
       thumb_color_id = kColorWebNativeControlScrollbarThumbPressed;
     } else if (state == NativeTheme::kHovered) {
       thumb_color_id = kColorWebNativeControlScrollbarThumbHovered;
+    } else if (extra_params.is_thumb_minimal_mode) {
+      thumb_color_id = kColorWebNativeControlScrollbarThumbOverlayMinimalMode;
     }
     return color_provider->GetColor(thumb_color_id);
   };
diff --git a/ui/webui/resources/cr_elements/BUILD.gn b/ui/webui/resources/cr_elements/BUILD.gn
index f35bd140..a47b77c0 100644
--- a/ui/webui/resources/cr_elements/BUILD.gn
+++ b/ui/webui/resources/cr_elements/BUILD.gn
@@ -95,6 +95,7 @@
     css_files = [
       "action_link.css",
       "cr_actionable_row_style.css",
+      "cr_actionable_row_style_lit.css",
       "cr_hidden_style.css",
       "cr_hidden_style_lit.css",
       "cr_icons.css",
@@ -112,6 +113,7 @@
       "search_highlight_style.css",
       "cr_action_menu/cr_action_menu.css",
       "cr_dialog/cr_dialog.css",
+      "cr_expand_button/cr_expand_button.css",
       "cr_input/cr_input_style.css",
     ]
 
diff --git a/ui/webui/resources/cr_elements/cr_actionable_row_style_lit.css b/ui/webui/resources/cr_elements/cr_actionable_row_style_lit.css
new file mode 100644
index 0000000..5a405bce
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_actionable_row_style_lit.css
@@ -0,0 +1,41 @@
+/* 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. */
+
+/* #css_wrapper_metadata_start
+ * #type=style-lit
+ * #import=./cr_shared_vars.css.js
+ * #css_wrapper_metadata_end */
+
+:host {
+  align-items: center;
+  align-self: stretch;
+  display: flex;
+  margin: 0;
+  outline: none;
+}
+
+/* [effectively-disabled_] is a private attribute to allow custom elements
+ * to toggle the attribute based on state, such as whether or not the
+ * internal control element is disabled, without affecting any public
+ * attributes or properties. */
+:host(:not([effectively-disabled_])) {
+  cursor: pointer;
+}
+
+:host(:not([no-hover], [effectively-disabled_]):hover) {
+  background-color: var(--cr-hover-background-color);
+}
+
+:host(:not([no-hover], [effectively-disabled_]):active) {
+  background-color: var(--cr-active-background-color);
+}
+
+/* Do not show hover or active states for cr-icon-buttons that are
+ * embedded within the row to avoid showing multiple layers of
+ * backgrounds. */
+:host(:not([no-hover], [effectively-disabled_])) cr-icon-button {
+  --cr-icon-button-hover-background-color: transparent;
+  --cr-icon-button-active-background-color: transparent;
+}
+
diff --git a/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html b/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html
index 5c280bd..301406b 100644
--- a/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html
+++ b/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.html
@@ -71,7 +71,6 @@
         display: flex;
         font-size: 123.08%;  /* go to 16px from 13px */
         font-weight: var(--cr-drawer-header-font-weight, inherit);
-        font: var(--cr-drawer-header-font, inherit);
         min-height: 56px;
         padding-inline-start: var(--cr-drawer-header-padding, 24px);
       }
diff --git a/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.css b/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.css
new file mode 100644
index 0000000..a5f819f
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.css
@@ -0,0 +1,26 @@
+/* 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. */
+
+/* #css_wrapper_metadata_start
+ * #type=style-lit
+ * #scheme=relative
+ * #css_wrapper_metadata_end */
+:host([disabled]) {
+  opacity: 0.65;
+  pointer-events: none;
+}
+
+:host([disabled]) cr-icon-button {
+  display: var(--cr-expand-button-disabled-display, initial);
+}
+
+#label {
+  flex: 1;
+  padding: var(--cr-section-vertical-padding) 0;
+}
+
+cr-icon-button {
+  --cr-icon-button-icon-size: var(--cr-expand-button-icon-size, 20px);
+  --cr-icon-button-size: var(--cr-expand-button-size, 36px);
+}
diff --git a/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html b/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html
index c8ef74d..1b8c3f19 100644
--- a/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html
+++ b/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.html
@@ -1,26 +1,5 @@
-    <style include="cr-actionable-row-style">
-      :host([disabled]) {
-        opacity: 0.65;
-        pointer-events: none;
-      }
-
-      :host([disabled]) cr-icon-button {
-        display: var(--cr-expand-button-disabled-display, initial);
-      }
-
-      #label {
-        flex: 1;
-        padding: var(--cr-section-vertical-padding) 0;
-      }
-
-      cr-icon-button {
-        --cr-icon-button-icon-size: var(--cr-expand-button-icon-size, 20px);
-        --cr-icon-button-size: var(--cr-expand-button-size, 36px);
-      }
-    </style>
-
-    <div id="label" aria-hidden="true"><slot></slot></div>
-    <cr-icon-button id="icon" aria-labelledby="label"
-        aria-expanded="[[getAriaExpanded_(expanded)]]" disabled="[[disabled]]"
-        tabindex="[[tabIndex]]" part="icon" iron-icon="[[icon_]]">
-    </cr-icon-button>
+<div id="label" aria-hidden="true"><slot></slot></div>
+<cr-icon-button id="icon" aria-labelledby="label" ?disabled="${this.disabled}"
+    aria-expanded="${this.ariaExpanded_}"
+    tabindex="${this.tabIndex}" part="icon" iron-icon="${this.icon_}">
+</cr-icon-button>
diff --git a/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.ts b/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.ts
index bc3706fd..866673d8 100644
--- a/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.ts
+++ b/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.ts
@@ -7,17 +7,19 @@
  * 'cr-expand-button' is a chrome-specific wrapper around a button that toggles
  * between an opened (expanded) and closed state.
  */
-import '../cr_actionable_row_style.css.js';
+import '../cr_actionable_row_style_lit.css.js';
 import '../cr_icon_button/cr_icon_button.js';
 import '../cr_shared_vars.css.js';
 import '../icons.html.js';
 
 import {focusWithoutInk} from '//resources/js/focus_without_ink.js';
-import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {CrLitElement, PropertyValues} from '//resources/lit/v3_0/lit.rollup.js';
 
+import {getCss as getActionableRowCss} from '../cr_actionable_row_style_lit.css.js';
 import {CrIconButtonElement} from '../cr_icon_button/cr_icon_button.js';
 
-import {getTemplate} from './cr_expand_button.html.js';
+import {getCss} from './cr_expand_button.css.js';
+import {getHtml} from './cr_expand_button.html.js';
 
 export interface CrExpandButtonElement {
   $: {
@@ -25,16 +27,23 @@
   };
 }
 
-export class CrExpandButtonElement extends PolymerElement {
+export class CrExpandButtonElement extends CrLitElement {
   static get is() {
     return 'cr-expand-button';
   }
 
-  static get template() {
-    return getTemplate();
+  static override get styles() {
+    return [
+      getActionableRowCss(),
+      getCss(),
+    ];
   }
 
-  static get properties() {
+  override render() {
+    return getHtml.bind(this)();
+  }
+
+  static override get properties() {
     return {
       /**
        * If true, the button is in the expanded state and will show the icon
@@ -43,7 +52,6 @@
        */
       expanded: {
         type: Boolean,
-        value: false,
         notify: true,
       },
 
@@ -52,70 +60,62 @@
        */
       disabled: {
         type: Boolean,
-        value: false,
-        reflectToAttribute: true,
+        reflect: true,
       },
 
       /** A11y text descriptor for this control. */
-      ariaLabel: {
-        type: String,
-        observer: 'onAriaLabelChange_',
-      },
+      ariaLabel: {type: String},
 
-      tabIndex: {
-        type: Number,
-        value: 0,
-      },
-
-      expandIcon: {
-        type: String,
-        value: 'cr:expand-more',
-      },
-
-      collapseIcon: {
-        type: String,
-        value: 'cr:expand-less',
-      },
-
-      icon_: String,
-
-      expandTitle: String,
-      collapseTitle: String,
-
-      tooltipText_: {
-        type: String,
-        computed: 'computeTooltipText_(expandTitle, collapseTitle, expanded)',
-        observer: 'onTooltipTextChange_',
-      },
+      ariaExpanded_: {type: String},
+      tabIndex: {type: Number},
+      expandIcon: {type: String},
+      collapseIcon: {type: String},
+      expandTitle: {type: String},
+      collapseTitle: {type: String},
+      icon_: {type: String},
     };
   }
 
-  expanded: boolean;
-  disabled: boolean;
-  expandIcon: string;
-  collapseIcon: string;
+  expanded: boolean = false;
+  disabled: boolean = false;
+  protected ariaExpanded_: string = 'false';
+  expandIcon: string = 'cr:expand-more';
+  collapseIcon: string = 'cr:expand-less';
   expandTitle: string;
   collapseTitle: string;
-  private icon_: string;
-  private tooltipText_: string;
+  override tabIndex: number = 0;
+  protected icon_: string = '';
 
-  static get observers() {
-    return [
-      'updateIcon_(collapseIcon, expandIcon, expanded)',
-    ];
-  }
-
-  override ready() {
-    super.ready();
+  override firstUpdated() {
     this.addEventListener('click', this.toggleExpand_);
   }
 
-  private computeTooltipText_(): string {
-    return this.expanded ? this.collapseTitle : this.expandTitle;
+  override willUpdate(changedProperties: PropertyValues<this>) {
+    super.willUpdate(changedProperties);
+
+    if (changedProperties.has('expanded') ||
+        changedProperties.has('expandIcon') ||
+        changedProperties.has('collapseIcon')) {
+      this.icon_ = this.expanded ? this.collapseIcon : this.expandIcon;
+    }
+
+    if (changedProperties.has('expanded') ||
+        changedProperties.has('collapseTitle') ||
+        changedProperties.has('expandTitle')) {
+      this.title = this.expanded ? this.collapseTitle : this.expandTitle;
+    }
+
+    if (changedProperties.has('expanded')) {
+      this.ariaExpanded_ = this.expanded ? 'true' : 'false';
+    }
   }
 
-  private onTooltipTextChange_() {
-    this.title = this.tooltipText_;
+  override updated(changedProperties: PropertyValues<this>) {
+    super.updated(changedProperties);
+
+    if (changedProperties.has('ariaLabel')) {
+      this.onAriaLabelChange_();
+    }
   }
 
   override focus() {
@@ -132,10 +132,6 @@
     }
   }
 
-  private updateIcon_() {
-    this.icon_ = this.expanded ? this.collapseIcon : this.expandIcon;
-  }
-
   private toggleExpand_(event: Event) {
     // Prevent |click| event from bubbling. It can cause parents of this
     // elements to erroneously re-toggle this control.
@@ -146,10 +142,6 @@
     this.expanded = !this.expanded;
     focusWithoutInk(this.$.icon);
   }
-
-  private getAriaExpanded_(): string {
-    return this.expanded ? 'true' : 'false';
-  }
 }
 
 declare global {
diff --git a/v8 b/v8
index deda839..28312d3 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit deda839adfed890bdcfbbd0a73fd6b1daa94eb23
+Subproject commit 28312d3b2ac96a3a325a4a761851c15808a75c12