diff --git a/.github/prompts/refactor_bedrock_test_part_1.prompt.md b/.github/prompts/refactor_bedrock_test_part_1.prompt.md
index 87c670dd..333b298d 100644
--- a/.github/prompts/refactor_bedrock_test_part_1.prompt.md
+++ b/.github/prompts/refactor_bedrock_test_part_1.prompt.md
@@ -12,13 +12,51 @@
 ## Step by step instructions
 
 ```markdown
-[ ] 0. Before you start
-[ ] 1. Rename Test File
-[ ] 2. Tell the user they must manually update `chrome/test/BUILD.gn`
-[ ] 3. Tell the user they must format, stage and commit the changes
-[ ] 4. Tell the user to proceed to refactoring part 2
+[ ] 1. Review user input
+[ ] 2. Find the right `BUILD.gn` file
+[ ] 3. Consider updating the `BUILD.gn` file
+[ ] 4. Wait for the user to confirm they have updated the `BUILD.gn` file
+[ ] 5. Rename Test File
+[ ] 6. Tell the user to format, stage and commit the changes
+[ ] 7. Tell the user to proceed to refactoring part 2
 ```
 
+## Review user input
+Review the following information before messaging the user so you can help them
+effectively.
+
+You are responsible for determining the following variables:
+  - `${out_dir}`: The build directory (e.g., `out/debug_x64`).
+
+- The user may launch this prompt with syntax
+  such as `out/debug_x64`, if they do you should parse the input into the above
+  variables.
+- The user may have specified `## Developer Prompt Variables`. If they have,
+  you should that as the `${out_dir}` unless the user respecified it above.
+
+### If the user did not provide satisfactory input
+- If the user did not provide input, or provided some input, but did not provide
+satisfactory input, to know `${out_dir}` . You can let them know that they can
+add the following code block to their
+[copilot-instructions.md](../copilot-instructions.md) file to set the default
+`${out_dir}`.
+  ```markdown
+  ## Developer Prompt Variables
+  `${out_dir}` = `debug_x64`
+  ```
+
+## Find the right `BUILD.gn` file
+You will need to find the file that references the test file you are
+refactoring. You can find this with the following command:
+`gn refs out/{out_dir} ${file}`
+
+- If the output is `//chrome/browser/foo:bar`, the file will be
+  `chrome/browser/foo/BUILD.gn` and inside of the `${target}` `bar`.
+   You do not need to search for the `BUILD.gn` file, you can open it directly
+   since chrome is accessible relative to this file at
+   [`../../chrome/](../../chrome/).
+
+
 ## Rename Test File
 You **must** use `git mv` to rename the test file `${file}`.
 - The new filename should replace the `_unittest.cc` suffix with
@@ -26,19 +64,36 @@
 - *Example*: If `${file}` is `foo_unittest.cc`, the command would be
   `git mv foo_unittest.cc foo_browsertest.cc`.
 
-## Instructions for Updating `chrome/test/BUILD.gn`
-Tell the user they need to manually update the `chrome/test/BUILD.gn` file since
-its too long for your context window.
+## Consider updating the `BUILD.gn` file
+Check the file length of the `BUILD.gn` file you found in the previous step.
+- You must do this using `(Get-Content ${file}).Count`
 
-When refactoring a unit test to a browser test in Chromium, they will need to
-manually update the `chrome/test/BUILD.gn` file. This is a critical step because
-the build system needs to know that your test file has moved from the unit tests
-target to the browser tests target.
+## If the file is under 4000 lines
+You should attempt to follow the instructions below to update the
+`BUILD.gn` file yourself.
 
-Here's what they will need to do:
+## If the file is over 4000 lines
+If the file is over 4000 lines, tell the user the file is too long for your
+context window. Tell the user they need to manually update the `BUILD.gn` file
+since its too long for your context window.
 
-1. **Find your original test file in the unit_tests section**:
-   - Look for your original file path in the `test("unit_tests")` section
+### Updating the `BUILD.gn` file
+When refactoring a unit test to a browser test in Chromium, you will need to
+update the `BUILD.gn` file. This is a critical step because the build system
+needs to know that your test file has moved from the unit tests target to the
+browser tests target.
+
+You will need to explain your chain of thought and follow these step by step:
+```markdown
+[ ] 1. Find your original test file in the unit_tests section
+[ ] 2. Remove the entry from unit_tests
+[ ] 3. Add to browser_tests
+[ ] 4. Review modified lines
+```
+
+#### Find your original test file in the `${target}` section
+   - Look for your original file path in the the `${target}`, this will likely
+     be a `test("unit_tests")` or `source_set("...unit_tests")` section
    - The file path will be formatted as a relative path, like:
      `"../browser/path/to/your_unittest.cc"`
    - For example, if your original file was at
@@ -47,40 +102,80 @@
      sources list
    - you can tell them the name of the file they are looking for
 
-2. **Remove the entry from unit_tests**:
-   - Delete this line completely from the `sources = [ ... ]` list in the
-     `test("unit_tests")` section
+#### Remove the file entry from unit_tests
+   - Delete the file entry only line from the `sources = [ ... ]` list in the
+     `${target}` section
+  - Do not delete the entire `sources = [ ... ]` block, just the line with your
+    original test file
+  - For example, if you are removing the line:
+    `../browser/ui/views/my_feature_unittest_2.cc`,
+    ```gn
+    # Before
+    # sources = [
+    #   ...,
+    #   "../browser/ui/views/my_feature_unittest_1.cc",
+    #   "../browser/ui/views/my_feature_unittest_2.cc",
+    #   "../browser/ui/views/my_feature_unittest_3.cc",
+    #   ...,
+    # ]
+    # After
+    sources = [
+      ...,
+      "../browser/ui/views/my_feature_unittest_1.cc",
+      "../browser/ui/views/my_feature_unittest_3.cc",
+      ...,
+    ]
+    ```
 
-3. **Add to browser_tests**:
-   - Find the `test("browser_tests")` section in the file
-   - Add a new line with your renamed file path to its `sources = [ ... ]` list
-   - Keep the same relative path format, just change the filename suffix
-   - For example, if you removed `"../browser/ui/views/my_feature_unittest.cc"`,
-     you'd add `"../browser/ui/views/my_feature_browsertest.cc"`
-   - Let them know you will run a format tool to ensure the file is formatted
-     and sorted correctly
-
-4. **Respect any conditional blocks**:
+#### Find the location to add the new browser test
+   - Look for the `browser_tests` section in the same `BUILD.gn` file
+   - This will likely be a `test("browser_tests")` or
+     `source_set("...browser_tests")` section
+   - If you don't see a `browser_tests` section, you may need to create one and
+     hook it up to `chrome/test/BUILD.gn`.
    - Pay attention to any `if` statement blocks that might be surrounding your
      test file
    - If your original file was inside a conditional block like `if (is_win)` or
      `if (enable_extensions)`, make sure to add your new browsertest file in the
      corresponding conditional block in the browser_tests section
 
-Wait for the user to confirm that they have updated the `chrome/test/BUILD.gn`
-file.
+#### Add to browser_tests
+   - You must **add** a new line with your renamed file path to its
+     `sources = [ ... ]` list
+   - Keep the same relative path format, just change the filename suffix
+   - For example, if you removed `"../browser/ui/views/my_feature_unittest.cc"`,
+     you'd add `"../browser/ui/views/my_feature_browsertest.cc"`
+
+#### Review modified lines
+   - After making these changes, review the modified lines in the `BUILD.gn`
+     file to ensure they are correct
+   - Make sure you have removed the old unit test file and added the new
+     browser test file correctly
+   - No other lines should be modified
+
+Before moving on you must **wait** for the user to confirm that the `BUILD.gn`
+file has been code reviewed by the user and updated correctly.
 
 ## Tell the user to format, stage and commit the changes
-After the user has updated the `chrome/test/BUILD.gn` file, you **must** run the
-following commands:
+After `BUILD.gn` file has been updated you **must** run the following commands
+in the following step by step order:
+```markdown
+[ ] 1. `git cl format ${file} [build.gn file]`
+[ ] 2. `git add ${file} [build.gn file]`
+[ ] 3. `git commit -m "[Bedrock]: Refactor ${file} _unittest to _browsertest"`
+[ ] 4. `git cl upload`
+```
 
-1. `gn add ${file} chrome/test/BUILD.gn`
-2. `git cl format`
-3. `gn add ${file} chrome/test/BUILD.gn`
-4. `git commit -m "[Bedrock]: Refactor ${file} _unittest to _browsertest"`
+Tell the user they must run `git cl upload` before continuing to part 2
+to upload the changes the code review system before continuing the refactor so
+that code reviewers can clearly disambiguate the changes made in this part of
+the refactor compared to the base test. There is a bug in gerrit that causes
+large diffs of moved files to not show up correctly, so we want to
+upload the changes in two parts to work around
+[this known issue](https://g-issues.gerritcodereview.com/issues/40003516).
 
 ## Tell the user to proceed to refactoring part 2
 After completing the above steps, provide the user with a clickable link to
 their new file and tell the user to start a new chat and run
-[/refactor_unit_test_to_browser_test_part_2](refactor_unit_test_to_browser_test_part_2.prompt.md)
+[/refactor_bedrock_part_2](refactor_bedrock_test_part_2.prompt.md)
 with the new file path.
diff --git a/.github/prompts/refactor_bedrock_test_part_2.prompt.md b/.github/prompts/refactor_bedrock_test_part_2.prompt.md
index 3e878a5..1d4b5d37 100644
--- a/.github/prompts/refactor_bedrock_test_part_2.prompt.md
+++ b/.github/prompts/refactor_bedrock_test_part_2.prompt.md
@@ -5,11 +5,48 @@
 # Chromium Code Refactoring: Unit Test to Browser Test
 
 You are an AI assistant with 10 years of experience writing Chromium unit tests
-and browser tests. The C++ test file `${file}` (which should now be named
-`*_browsertest.cc`) has already been renamed and its entry in
-`chrome/test/BUILD.gn` has been updated. Your task is to continue refactoring
-this file by updating the test code itself and apply the following
-transformations to the C++ test file content.
+and browser tests.
+
+The C++ test file `${file}` (which should now be named `*_browsertest.cc`) has
+already been renamed and its entry in `chrome/test/BUILD.gn` has been updated.
+
+Your primary goal is the elimination of the following classes and utilities by
+conversion to browser tests. Significant test rework is not intended
+(except for where absolutely necessary):
+- `TestBrowserWindow`
+- `BrowserWithTestWindowTest`
+- `TestWithBrowserView`
+- `CreateBrowserWithTestWindowForParams`
+
+Your task is to continue refactoring this file by updating the test code itself
+and apply the following transformations to the C++ test file content.
+
+## Background
+There are existing test fixtures and utilities that encourage use of Browser in
+the unit_test target, namely those provided above.
+
+### Problem
+- Encourages use of Browser instead of dependency injection
+  - Tests end up depending on the entirety of `//chrome/browser:browser`
+    and `//chrome/browser/ui::ui`
+  - Unit tests should be narrowly scoped to the feature under test
+- Non representative tests
+  - Browser is partially / incorrectly constructed
+  - Incomplete construction of BrowserWindowFeatures
+  - Non representative environments (many services not instantiated)
+  - Construction / destruction / lifetimes do not match production
+
+### Solution
+An initial step in addressing Browser dependency in unit tests is the
+elimination of the test fixtures and utilities above.
+
+This can be done by converting such unit tests to browser tests. This ensures
+that these unit tests (which are effectively browser tests) run in a more
+representative environment. Once this conversion is complete the problematic
+fixtures and utilities can also be removed.
+
+There may also be cases where unit tests use of the above fixtures and utilities
+is unnecessary, and tests can simply be converted to a regular unit test.
 
 ## Step by step instructions
 
@@ -23,6 +60,8 @@
 [ ] 4. Adapt `TearDown` Method Signature
 [ ] 5. Update Test Case Definition Macro
 [ ] 6. Refactor Internal Test Logic
+[ ] 7. Update all Common Browser Interaction Patterns (Examples)
+[ ] 8. Tell the user to proceed to `/gtest`
 ```
 
 ## Tell the user to proceed to `gtest`
@@ -31,9 +70,22 @@
 test.
 
 ## Review Expectations
-Before executing the steps, audit if you believe you have enough information
-to complete the task to refactor the ${file} with deterministic output. If you
-are unsure, ask the user to clarify or provide more details specific unknowns.
+You are responsible for the following:
+- audit if you believe you have enough information to complete the task to
+  refactor the ${file} with deterministic output.
+- If you are unsure of how to convert a code pattern, ask the user to clarify
+  or provide more details specific unknowns.
+- You **must** minimize the diff required to refactor the test, you should
+  preserve as many lines of the original test as possible.
+- Do **not** add additional comments or explanations to the code.
+- Do **not** add additional asserts to the code that the original test did not
+  have.
+- When a **mock** is used, ask the user if they would like it to be
+  replaced with a real browser interaction or if it should be kept as a mock.
+  Let them know that ideally, browser tests should not use mocks because they
+  are not testing the browser's behavior, however, if changing the mock
+  causes a very large diff, it may be better to keep the mock for now and remove
+  the mock in a future refactoring step.
 
 ## Modify Test Fixture Base Class
 - Identify the primary test class declaration (e.g.,
@@ -44,10 +96,12 @@
     `class YourTestSuiteName : public BrowserWithTestWindowTest {`
 - Modify the base class to `InProcessBrowserTest`.
   - *Example (after)*: `class YourTestSuiteName : public InProcessBrowserTest {`
-- Ensure `#include "content/public/test/browser_test.h"` is present for
-  `InProcessBrowserTest`. If `BrowserWithTestWindowTest` was used, its header
+- Ensure `#include "chrome/test/base/in_process_browser_test.h"` and
+  `#include "content/public/test/browser_test.h"` are present
+  for `InProcessBrowserTest`.
+- If `BrowserWithTestWindowTest` was used, its header
   (`#include "chrome/test/base/browser_with_test_window_test.h"`) should be
-  removed if it is no longer needed.
+  removed, it is no longer needed.
 
 ## Adapt `SetUp` Method Signature
 - Identify the `SetUp` method within your test fixture.
@@ -87,10 +141,16 @@
       `chrome/test/base/ui_test_utils.h`).
 
 ## Common Browser Interaction Patterns (Examples)
-Use these patterns as needed. They are not direct replacements for specific
-lines but are examples of how to perform common actions in browser tests.
+Review the following common patterns and adapt your test code accordingly.
+If the code is using an older pattern, replace it with the new one.
+
+### Required Headers
+- if `browser()->` is used, ensure
+  `#include "chrome/browser/ui/browser.h"` is present.
 
 ### Adding a new tab to the active browser
+- Replace uses of `AddTab(...)` with
+  `ui_test_utils::NavigateToURLWithDisposition(..)`.
 - Requires `#include "chrome/test/base/ui_test_utils.h"` for `AddTabAtIndex`.
 - using `ui_test_utils` for more robust tab addition:
   ```cpp
@@ -109,20 +169,13 @@
       ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
   ```
 
-### Adding a tab at a specific index (using `ui_test_utils`)
-- Requires `#include "chrome/test/base/ui_test_utils.h"`.
-```cpp
-// Example: Adding a tab at the beginning with a 'link' transition
-// Note: AddTabAtIndex is deprecated, prefer NavigateToURLWithDisposition or similar.
-// If you must use it:
-// ui_test_utils::AddTabAtIndex(0, GURL("about:blank"), ui::PAGE_TRANSITION_LINK);
-// This assumes AddTabAtIndex is available and correctly scoped or called on browser()->tab_strip_model().
-// A more modern approach:
-NavigateParams params(browser(), GURL("about:blank"), ui::PAGE_TRANSITION_LINK);
-params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
-params.tabstrip_index = 0;
-ui_test_utils::Navigate(&params);
-```
+### Getting the profiles
+- For getting a `Profile*` the code must use
+  ```cpp
+  browser()->profile()
+  ```
+
+### Navigation
 
 ### Accessing the active WebContents
 - Requires `#include "chrome/browser/ui/tabs/tab_strip_model.h"` and
@@ -136,9 +189,13 @@
 
 ### Navigating the current tab to a URL and waiting for completion
 Requires `#include "chrome/test/base/ui_test_utils.h"` and `#include "url/gurl.h"`.
-```cpp
-ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL("chrome://version")));
-```
+- Replace uses of `NavigateAndCommit()` and `NavigateAndCommitActiveTab()`
+- using `ui_test_utils` for more robust tab addition:
+  ```cpp
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(), GURL("about:blank"), WindowOpenDisposition::CurrentTab,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
+  ```
 
 ### Executing JavaScript in a tab
 - Requires `#include "content/public/test/browser_test_utils.h"` and
@@ -155,6 +212,9 @@
 
 ### Waiting for conditions
 - Browser tests often require waiting for asynchronous operations.
-  Use appropriate waiting mechanisms, e.g.,
-  `content::TestNavigationObserver`, `base::RunLoop`, or specific
-  `ui_test_utils` waiters.
+  Use appropriate waiting mechanisms, e.g.,`content::TestNavigationObserver`
+  or specific `ui_test_utils` waiters.
+- Instead of `base::RunLoop` or other alternatives, use `base/test/run_until.h`
+  ```cpp
+  [[nodiscard]] bool RunUntil(base::FunctionRef<bool(void)> condition);
+  ```
diff --git a/.gn b/.gn
index 60f8591a..ae58a0b0 100644
--- a/.gn
+++ b/.gn
@@ -75,9 +75,6 @@
 
   clang_unsafe_buffers_paths = "//build/config/unsafe_buffers_paths.txt"
   clang_warning_suppression_file = "//build/config/warning_suppression.txt"
-
-  # Use Siso instead of Ninja.
-  use_siso = true
 }
 
 # These are the targets to skip header checking by default. The files in targets
diff --git a/BUILD.gn b/BUILD.gn
index e32e315..9b416fb 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1185,7 +1185,10 @@
     # https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/run_web_platform_tests.md
     script_test("chrome_wpt_tests") {
       script = "//third_party/blink/tools/run_wpt_tests.py"
-      args = _common_web_test_options + [ "--product=chrome" ]
+      args = _common_web_test_options + [
+               "--product=chrome",
+               "--verbose",
+             ]
       if (dcheck_always_on) {
         args += [ "--timeout-multiplier=2" ]
       } else {
@@ -1209,7 +1212,10 @@
     # https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/run_web_platform_tests.md
     script_test("headless_shell_wpt") {
       script = "//third_party/blink/tools/run_wpt_tests.py"
-      args = _common_web_test_options + [ "--product=headless_shell" ]
+      args = _common_web_test_options + [
+               "--product=headless_shell",
+               "--verbose",
+             ]
       data_deps = [
         ":blink_web_tests_expectations",
         ":blink_web_tests_support_data",
diff --git a/DEPS b/DEPS
index 95cb4801..45bf48d 100644
--- a/DEPS
+++ b/DEPS
@@ -295,19 +295,19 @@
   # 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': '6113fc67631d1ddb7a8918e5bb92e34d8492710b',
+  'src_internal_revision': '0cd9d611e47ef77b8acd24fba00403d8709bd2da',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'e2dc10af85db2b3c8e95fe0b7f5817614fb31419',
+  'skia_revision': '82d326fc2148181e8d9ca848b17237fa4db75331',
   # 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': 'e180c60cc3eb265924e992248b0fe2c68e122cab',
+  'v8_revision': '61ddd471ece346840bbebbb308dceb4b4ce31b28',
   # 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': '2f6f0514563d81e439e04ba09eee9e8a1d6ca8d1',
+  'angle_revision': '90668ecf2978f085de9a9bdef4d8e5bad79df71e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -315,7 +315,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'cf433ae5520d061db56391155b59b34e67484f39',
+  'pdfium_revision': '66b63bba62fc2587bf91d3a055a9079f5984b8c6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -371,7 +371,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': '61f9c08d6ae028f8440b1ddddb330cfdf028c159',
+  'catapult_revision': '3af14c3b4e2496ad1b85e1f33823f006e30fe8e0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
@@ -391,7 +391,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': 'a178b7d51c21c468b397db564aa21e34c7cc0aa2',
+  'devtools_frontend_revision': 'c7d5f74c859abdd3219524ec9f77ce98d54a9a15',
   # 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.
@@ -495,7 +495,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'libcxxabi_revision':    '9810fb23f6ba666f017c2b67c67de2bcac2b44bd',
+  'libcxxabi_revision':    '241ef367ab2d135197377a82da5f7aee49a082f8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -822,10 +822,10 @@
     'condition': 'non_git_source',
     'objects': [
       {
-        'object_name': '13eea9a3163f9e91f343e6a3197079986d7276b2',
-        'sha256sum': 'd347ed7e5ef83e062d1044df222448e6857aa40d9ac6dace45591dc02f9c61b7',
-        'size_bytes': 9650582,
-        'generation': 1747160834666855,
+        'object_name': '782009f3247d27e3c0a9663eb3a35c78bdca6745',
+        'sha256sum': '656900010234995fda28593c8cfa32067117aa7028a8ba062febbc8c28636bb6',
+        'size_bytes': 9659657,
+        'generation': 1747350963881164,
         'output_file': 'node_modules.tar.gz',
       },
     ],
@@ -1508,7 +1508,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '6a196fc5a4b07b4f6d8c64cb7ab20e43bdbeb43b',
+    'cef11550a1facb7d8a76e3d9169d1e0a64adf73a',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1667,7 +1667,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'mvb4FoiI7mx7wdZfh0eRwvgiV8OpsdFC_oluXPftl4gC',
+          'version': '4iWSQnDJqcLNK274cq1Z7mu50FgwKfBxZhbjbtnga2sC',
       },
     ],
     'condition': 'checkout_android and non_git_source',
@@ -2000,7 +2000,7 @@
 
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '0772b51a975ba1ecf983b52665528d5b1db8a433',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '0b1d80ab9e9f1413234641d193639e5daa92dd5b',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -2475,7 +2475,7 @@
   },
 
   'src/third_party/mutter/src': {
-      'url': Var('chromium_git') + '/external/gitlab.gnome.org/GNOME/mutter.git' + '@' + 'e99ff5359c4134093efe3cb2aa208e4addf565c6',
+      'url': Var('chromium_git') + '/external/gitlab.gnome.org/GNOME/mutter.git' + '@' + '881058e0a3c395b93986d734d2cff164376a1ec7',
       'condition': 'checkout_linux and checkout_mutter',
   },
 
@@ -2739,7 +2739,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/r8',
-              'version': 'QhYGRVpYYKZmt3f_Zb2HoJ9LIBEnWaeeLXRNei47Z30C',
+              'version': 'i5l_yPIc-ZuKle_ibElGMSf50XN8buMgspBkoObkkRAC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -2867,7 +2867,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@9b8253ba5637b5ad10835a8e412f3b29b4cd9dae',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@7a77f5b6428118e42f8a35586578a4fabeba7135',
   'src/third_party/glslang/src': '{chromium_git}/external/github.com/KhronosGroup/glslang@be4ee7d0e3bfd151bfda7b3a8e03f8c49c55ed7b',
   'src/third_party/spirv-cross/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Cross@b8fcf307f1f347089e3c46eb4451d27f32ebc8d3',
   'src/third_party/spirv-headers/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Headers@c9aad99f9276817f18f72a4696239237c83cb775',
@@ -2876,7 +2876,7 @@
   'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@c913466fdc5004584890f89ff91121bdb2ffd4ba',
   'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@60b640cb931814fcc6dabe4fc61f4738c56579f6',
   'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@49ac28931f28bffaa3cd73dc4ad997284d574962',
-  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@ee2b1e4837b496cacac158f13bac28ad543223f3',
+  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@30f98bc36f99860a6c2cd18c4af5f3f387e0b933',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '56300b29fbfcc693ee6609ddad3fdd5b7a449a21',
@@ -2915,7 +2915,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'c01b768bce4a143e152c1870b6ba99ea6267d2b0',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '905c7cbfeaac1cf3feb4c6056dd6f3dbaa06b074',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '00bbf5422c1b7a71285c51b2dc1e1637e618b916',
 
   'src/third_party/webpagereplay':
     Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'),
@@ -2935,7 +2935,7 @@
     Var('skia_git') + '/external/github.com/google/wuffs-mirror-release-c.git' + '@' +  Var('wuffs_revision'),
 
   'src/third_party/weston/src': {
-      'url': Var('chromium_git') + '/external/anongit.freedesktop.org/git/wayland/weston.git' + '@' + 'bdba2f9adaca673fd58339d8140bc04727ee279d',
+      'url': Var('chromium_git') + '/external/anongit.freedesktop.org/git/wayland/weston.git' + '@' + '4eb10b123b483327214d8da5da67e8bbeeaed8fe',
       'condition': 'checkout_linux',
   },
 
@@ -4641,7 +4641,7 @@
 
   'src/components/optimization_guide/internal': {
       'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' +
-        '2cc55d5ca41fa04a1ac7a1c7971a9aba449d01b3',
+        'abe28fc69cad880ec92b198727268aa7fbea55a0',
       'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
index 3260b84..f8a8546 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -1071,6 +1071,7 @@
         Flag.baseFeature(
                 "PrefetchServiceWorker",
                 "Enables SpeculationRules prefetch to ServiceWorker-controlled URLs."),
+        Flag.baseFeature("TimedHTMLParserBudget"),
         // Add new commandline switches and features above. The final entry should have a
         // trailing comma for cleaner diffs.
     };
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn
index 4cb3fd8d..939df9a 100644
--- a/android_webview/test/BUILD.gn
+++ b/android_webview/test/BUILD.gn
@@ -96,11 +96,13 @@
 }
 
 # Options shared by all script test targets that call `run_wpt_tests.py`.
+# TODO(crbug.com/419890016): Consolidate the common options.
 _common_web_test_options = [
   "--no-show-results",
   "--zero-tests-executed-ok",
   "--build-directory",
   "@WrappedPath(.)",
+  "--verbose",
 ]
 if (is_debug) {
   _common_web_test_options += [ "--debug" ]
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 4990d6d8..802ad8a 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -5656,9 +5656,6 @@
       <message name="IDS_ASH_MULTI_DEVICE_SETUP_NEW_USER_POTENTIAL_HOST_EXISTS_TITLE" desc="Title of the notification shown to a user that has not completed the MultiDevice setup when their Chrome device recognizes that they have a phone on their account that the Chrome device can connect to">
         Your devices work even better together
       </message>
-      <message name="IDS_ASH_MULTI_DEVICE_SETUP_NOTIFIER_TEXT_WITH_PHONE_HUB" desc="The text mentions Phone Hub that shows in the notifier of multidevice setup.">
-        Quickly send or reply to your phone's messages using Phone Hub
-      </message>
       <message name="IDS_ASH_MULTI_DEVICE_SETUP_NOTIFIER_TEXT_WITHOUT_PHONE_HUB" desc="The text does not mention Phone Hub that shows in the notifier of multidevice setup.">
         Save time by quickly replying to your phone's texts from your Chromebook
       </message>
diff --git a/ash/ash_strings_grd/IDS_ASH_MULTI_DEVICE_SETUP_NOTIFIER_TEXT_WITH_PHONE_HUB.png.sha1 b/ash/ash_strings_grd/IDS_ASH_MULTI_DEVICE_SETUP_NOTIFIER_TEXT_WITH_PHONE_HUB.png.sha1
deleted file mode 100644
index 324c353..0000000
--- a/ash/ash_strings_grd/IDS_ASH_MULTI_DEVICE_SETUP_NOTIFIER_TEXT_WITH_PHONE_HUB.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-90e72fa71ad7ad060307ceba2445ae6632f9a1ac
\ No newline at end of file
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index e8c6e6d..cb603d3 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -2406,42 +2406,6 @@
              "PhoneHubMonochromeNotificationIcons",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-// Determine whether we use revamped notifier to notify users to start
-// onboarding to Phone Hub.
-BASE_FEATURE(kPhoneHubOnboardingNotifierRevamp,
-             "PhoneHubOnboardingNotifierRevamp",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
-// Should we show nudge or notification to the user.
-const base::FeatureParam<bool> kPhoneHubOnboardingNotifierUseNudge{
-    &kPhoneHubOnboardingNotifierRevamp, "use_nudge", true};
-
-const base::FeatureParam<
-    PhoneHubNotifierTextGroup>::Option phone_hub_notifier_text_groups[] = {
-    {PhoneHubNotifierTextGroup::kNotifierTextGroupA, "notifier_with_text_A"},
-    {PhoneHubNotifierTextGroup::kNotifierTextGroupB, "notifier_with_text_B"},
-};
-// What text should we show to the user.
-const base::FeatureParam<PhoneHubNotifierTextGroup> kPhoneHubNotifierTextGroup{
-    &kPhoneHubOnboardingNotifierRevamp, "notifier_text_group",
-    PhoneHubNotifierTextGroup::kNotifierTextGroupB,
-    &phone_hub_notifier_text_groups};
-
-// The length of time passing till we display nudge to users again
-const base::FeatureParam<base::TimeDelta> kPhoneHubNudgeDelay{
-    &kPhoneHubOnboardingNotifierRevamp, "nudge_delay", base::Hours(24)};
-
-// Number of times nudge should be shown to user.
-const base::FeatureParam<int> kPhoneHubNudgeTotalAppearancesAllowed{
-    &kPhoneHubOnboardingNotifierRevamp, "nudge_total_appearances_allowed", 3};
-
-// Determines up to how many minutes into user session multdevice setup
-// notification can be shown.
-const base::FeatureParam<base::TimeDelta>
-    kMultiDeviceSetupNotificationTimeLimit{
-        &kPhoneHubOnboardingNotifierRevamp,
-        "MultiDeviceSetupNotificationTimitLimit", base::Minutes(5)};
-
 BASE_FEATURE(kPhoneHubPingOnBubbleOpen,
              "PhoneHubPingOnBubbleOpen",
              base::FEATURE_ENABLED_BY_DEFAULT);
@@ -4390,10 +4354,6 @@
   return base::FeatureList::IsEnabled(kPhoneHubMonochromeNotificationIcons);
 }
 
-bool IsPhoneHubOnboardingNotifierRevampEnabled() {
-  return base::FeatureList::IsEnabled(kPhoneHubOnboardingNotifierRevamp);
-}
-
 bool IsPhoneHubPingOnBubbleOpenEnabled() {
   return base::FeatureList::IsEnabled(kPhoneHubPingOnBubbleOpen);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 2e10fb9..b0b9e54 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -670,9 +670,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kMouseImposterCheck);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kMultiCalendarSupport);
-COMPONENT_EXPORT(ASH_CONSTANTS)
-extern const base::FeatureParam<base::TimeDelta>
-    kMultiDeviceSetupNotificationTimeLimit;
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kMultiZoneRgbKeyboard);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kNearbyPresence);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kNotificationLimit);
@@ -796,22 +793,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kPhoneHubMonochromeNotificationIcons);
 COMPONENT_EXPORT(ASH_CONSTANTS)
-BASE_DECLARE_FEATURE(kPhoneHubOnboardingNotifierRevamp);
-COMPONENT_EXPORT(ASH_CONSTANTS)
-extern const base::FeatureParam<bool> kPhoneHubOnboardingNotifierUseNudge;
-enum class PhoneHubNotifierTextGroup {
-  // The int values should not be changed as they are referenced on the server.
-  kNotifierTextGroupA = 1,
-  kNotifierTextGroupB = 2
-};
-COMPONENT_EXPORT(ASH_CONSTANTS)
-extern const base::FeatureParam<PhoneHubNotifierTextGroup>
-    kPhoneHubNotifierTextGroup;
-COMPONENT_EXPORT(ASH_CONSTANTS)
-extern const base::FeatureParam<base::TimeDelta> kPhoneHubNudgeDelay;
-COMPONENT_EXPORT(ASH_CONSTANTS)
-extern const base::FeatureParam<int> kPhoneHubNudgeTotalAppearancesAllowed;
-COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kPhoneHubPingOnBubbleOpen);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::FeatureParam<base::TimeDelta> kPhoneHubPingTimeout;
@@ -1352,8 +1333,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 bool IsPhoneHubMonochromeNotificationIconsEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS)
-bool IsPhoneHubOnboardingNotifierRevampEnabled();
-COMPONENT_EXPORT(ASH_CONSTANTS)
 bool IsPhoneHubPingOnBubbleOpenEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS)
 bool IsPhoneHubShortQuickActionPodsTitlesEnabled();
diff --git a/ash/multi_device_setup/multi_device_notification_presenter.cc b/ash/multi_device_setup/multi_device_notification_presenter.cc
index dfa1256..55f080c 100644
--- a/ash/multi_device_setup/multi_device_notification_presenter.cc
+++ b/ash/multi_device_setup/multi_device_notification_presenter.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include <utility>
 
-#include "ash/constants/ash_features.h"
 #include "ash/constants/notifier_catalogs.h"
 #include "ash/public/cpp/notification_utils.h"
 #include "ash/public/cpp/system_tray_client.h"
@@ -100,14 +99,6 @@
 void MultiDeviceNotificationPresenter::OnPotentialHostExistsForNewUser() {
   int title_message_id =
       IDS_ASH_MULTI_DEVICE_SETUP_NEW_USER_POTENTIAL_HOST_EXISTS_TITLE;
-  if (features::IsPhoneHubOnboardingNotifierRevampEnabled() &&
-      !features::kPhoneHubOnboardingNotifierUseNudge.Get()) {
-    title_message_id =
-        features::kPhoneHubNotifierTextGroup.Get() ==
-                features::PhoneHubNotifierTextGroup::kNotifierTextGroupA
-            ? IDS_ASH_MULTI_DEVICE_SETUP_NOTIFIER_TEXT_WITH_PHONE_HUB
-            : IDS_ASH_MULTI_DEVICE_SETUP_NOTIFIER_TEXT_WITHOUT_PHONE_HUB;
-  }
   std::u16string title = l10n_util::GetStringUTF16(title_message_id);
   std::u16string message = l10n_util::GetStringFUTF16(
       IDS_ASH_MULTI_DEVICE_SETUP_NEW_USER_POTENTIAL_HOST_EXISTS_MESSAGE,
diff --git a/ash/system/phonehub/onboarding_nudge_controller.cc b/ash/system/phonehub/onboarding_nudge_controller.cc
index 8ad8acd5..c24e015 100644
--- a/ash/system/phonehub/onboarding_nudge_controller.cc
+++ b/ash/system/phonehub/onboarding_nudge_controller.cc
@@ -7,7 +7,6 @@
 #include <algorithm>
 #include <memory>
 
-#include "ash/constants/ash_features.h"
 #include "ash/constants/notifier_catalogs.h"
 #include "ash/public/cpp/system/anchored_nudge_data.h"
 #include "ash/public/cpp/system/anchored_nudge_manager.h"
@@ -56,25 +55,13 @@
 OnboardingNudgeController::~OnboardingNudgeController() = default;
 
 void OnboardingNudgeController::ShowNudgeIfNeeded() {
-  if (!IsInPhoneHubNudgeExperimentGroup()) {
-    return;
-  }
-
   if (!ShouldShowNudge()) {
     return;
   }
-  PA_LOG(INFO)
-      << "Phone Hub onboarding nudge is being shown for text experiment group "
-      << (features::kPhoneHubNotifierTextGroup.Get() ==
-                  features::PhoneHubNotifierTextGroup::kNotifierTextGroupA
-              ? "A."
-              : "B.");
+  PA_LOG(INFO) << "Phone Hub onboarding nudge is being shown.";
 
   std::u16string nudge_text = l10n_util::GetStringUTF16(
-      features::kPhoneHubNotifierTextGroup.Get() ==
-              features::PhoneHubNotifierTextGroup::kNotifierTextGroupA
-          ? IDS_ASH_MULTI_DEVICE_SETUP_NOTIFIER_TEXT_WITH_PHONE_HUB
-          : IDS_ASH_MULTI_DEVICE_SETUP_NOTIFIER_TEXT_WITHOUT_PHONE_HUB);
+      IDS_ASH_MULTI_DEVICE_SETUP_NOTIFIER_TEXT_WITHOUT_PHONE_HUB);
   AnchoredNudgeData nudge_data = {kPhoneHubNudgeId, NudgeCatalogName::kPhoneHub,
                                   nudge_text, anchored_view_};
   nudge_data.anchored_to_shelf = true;
@@ -101,9 +88,6 @@
 }
 
 void OnboardingNudgeController::HideNudge() {
-  if (!IsInPhoneHubNudgeExperimentGroup()) {
-    return;
-  }
   if (AnchoredNudgeManager::Get()->IsNudgeShown(kPhoneHubNudgeId)) {
     // `HideNudge()` is only invoked when Phone Hub icon is clicked. If the
     // nudge is visible, it should be counted as interaction.
@@ -117,18 +101,11 @@
 }
 
 void OnboardingNudgeController::MaybeRecordNudgeAction() {
-  if (!IsInPhoneHubNudgeExperimentGroup()) {
-    return;
-  }
   AnchoredNudgeManager::Get()->MaybeRecordNudgeAction(
       NudgeCatalogName::kPhoneHub);
 }
 
 void OnboardingNudgeController::OnNudgeHoverStateChanged(bool is_hovering) {
-  if (!IsInPhoneHubNudgeExperimentGroup()) {
-    return;
-  }
-
   if (is_hovering) {
     PrefService* pref_service = GetPrefService();
     pref_service->SetTime(kPhoneHubNudgeLastActionTime, clock_->Now());
@@ -136,10 +113,6 @@
 }
 
 void OnboardingNudgeController::OnNudgeClicked() {
-  if (!IsInPhoneHubNudgeExperimentGroup()) {
-    return;
-  }
-
   is_nudge_clicked_ = true;
 
   // Action can be click or hover so define `kPhoneHubNudgeLastActionTime` on
@@ -151,10 +124,6 @@
 }
 
 void OnboardingNudgeController::OnNudgeDismissed() {
-  if (!IsInPhoneHubNudgeExperimentGroup()) {
-    return;
-  }
-
   if (is_nudge_clicked_ || is_phone_hub_icon_clicked_) {
     PrefService* pref_service = GetPrefService();
     base::UmaHistogramTimes(
@@ -225,11 +194,6 @@
   return base::Contains(devices_in_pref, base::Value(device.instance_id()));
 }
 
-bool OnboardingNudgeController::IsInPhoneHubNudgeExperimentGroup() {
-  return features::IsPhoneHubOnboardingNotifierRevampEnabled() &&
-         features::kPhoneHubOnboardingNotifierUseNudge.Get();
-}
-
 bool OnboardingNudgeController::ShouldShowNudge() {
   PrefService* pref_service = GetPrefService();
   if (!pref_service->GetTime(kPhoneHubNudgeLastClickTime).is_null()) {
@@ -238,9 +202,9 @@
   }
 
   if (pref_service->GetInteger(kPhoneHubNudgeTotalAppearances) >=
-      features::kPhoneHubNudgeTotalAppearancesAllowed.Get()) {
+      kPhoneHubNudgeTotalAppearancesAllowed) {
     PA_LOG(INFO) << "Nudge has been shown "
-                 << features::kPhoneHubNudgeTotalAppearancesAllowed.Get()
+                 << kPhoneHubNudgeTotalAppearancesAllowed
                  << " times. Do not show again.";
     return false;
   }
@@ -250,11 +214,10 @@
   }
 
   if ((clock_->Now() - pref_service->GetTime(kPhoneHubNudgeLastShownTime)) >=
-      features::kPhoneHubNudgeDelay.Get()) {
+      kPhoneHubNudgeDelay) {
     return true;
   }
-  PA_LOG(INFO) << "Nudge was shown less than "
-               << features::kPhoneHubNudgeDelay.Get()
+  PA_LOG(INFO) << "Nudge was shown less than " << kPhoneHubNudgeDelay
                << " hours ago. Not being shown this time.";
   return false;
 }
diff --git a/ash/system/phonehub/onboarding_nudge_controller.h b/ash/system/phonehub/onboarding_nudge_controller.h
index e6c27ae..cbb4d7b 100644
--- a/ash/system/phonehub/onboarding_nudge_controller.h
+++ b/ash/system/phonehub/onboarding_nudge_controller.h
@@ -9,6 +9,7 @@
 #include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
 #include "chromeos/ash/components/phonehub/feature_status_provider.h"
 
 class PrefRegistrySimple;
@@ -84,6 +85,9 @@
   FRIEND_TEST_ALL_PREFIXES(OnboardingNudgeControllerTest,
                            DoNotAddToSyncedDeviceListIfAlreadyFound);
 
+  static constexpr int kPhoneHubNudgeTotalAppearancesAllowed = 3;
+  static constexpr base::TimeDelta kPhoneHubNudgeDelay = base::Hours(24);
+
   bool IsDeviceStoredInPref(const multidevice::RemoteDeviceRef& device);
 
   void AddToEligibleDevicesPref(const multidevice::RemoteDeviceRef& device);
@@ -95,8 +99,6 @@
   void OnEligiblePhoneHubHostFound(
       const multidevice::RemoteDeviceRefList eligible_devices) override;
 
-  bool IsInPhoneHubNudgeExperimentGroup();
-
   bool ShouldShowNudge();
 
   bool is_nudge_clicked_ = false;
diff --git a/ash/system/phonehub/phone_hub_tray.cc b/ash/system/phonehub/phone_hub_tray.cc
index 873becd..07ab677 100644
--- a/ash/system/phonehub/phone_hub_tray.cc
+++ b/ash/system/phonehub/phone_hub_tray.cc
@@ -147,18 +147,15 @@
 
   UpdateTrayItemColor(is_active());
 
-  onboarding_nudge_controller_ =
-      features::IsPhoneHubOnboardingNotifierRevampEnabled()
-          ? std::make_unique<OnboardingNudgeController>(
-                /*phone_hub_tray=*/this,
-                /*animation_stop_callback=*/
-                base::BindRepeating(&PhoneHubTray::StopPulseAnimation,
-                                    weak_factory_.GetWeakPtr()),
-                /*start_animation_callback=*/
-                base::BindRepeating(&PhoneHubTray::StartPulseAnimation,
-                                    weak_factory_.GetWeakPtr()),
-                base::DefaultClock::GetInstance())
-          : nullptr;
+  onboarding_nudge_controller_ = std::make_unique<OnboardingNudgeController>(
+      /*phone_hub_tray=*/this,
+      /*animation_stop_callback=*/
+      base::BindRepeating(&PhoneHubTray::StopPulseAnimation,
+                          weak_factory_.GetWeakPtr()),
+      /*start_animation_callback=*/
+      base::BindRepeating(&PhoneHubTray::StartPulseAnimation,
+                          weak_factory_.GetWeakPtr()),
+      base::DefaultClock::GetInstance());
 
   Shell::Get()->display_manager()->AddDisplayManagerObserver(this);
 
@@ -172,8 +169,7 @@
   if (phone_hub_manager_) {
     phone_hub_manager_->GetAppStreamManager()->RemoveObserver(this);
   }
-  if (phone_hub_manager_ && IsInPhoneHubNudgeExperimentGroup() &&
-      onboarding_nudge_controller_) {
+  if (phone_hub_manager_ && onboarding_nudge_controller_) {
     phone_hub_manager_->GetFeatureStatusProvider()->RemoveObserver(
         onboarding_nudge_controller_.get());
   }
@@ -190,8 +186,7 @@
     phone_hub_manager->GetAppStreamManager()->AddObserver(this);
   }
   phone_hub_manager_ = phone_hub_manager;
-  if (phone_hub_manager_ && IsInPhoneHubNudgeExperimentGroup() &&
-      onboarding_nudge_controller_) {
+  if (phone_hub_manager_ && onboarding_nudge_controller_) {
     phone_hub_manager_->GetFeatureStatusProvider()->AddObserver(
         onboarding_nudge_controller_.get());
   }
@@ -287,9 +282,8 @@
     bool aborted) {
   TrayBackgroundView::OnVisibilityAnimationFinished(
       should_log_visible_pod_count, aborted);
-  if (IsInPhoneHubNudgeExperimentGroup() &&
-      ui_controller_->ui_state() ==
-          PhoneHubUiController::UiState::kOnboardingWithoutPhone) {
+  if (ui_controller_->ui_state() ==
+      PhoneHubUiController::UiState::kOnboardingWithoutPhone) {
     onboarding_nudge_controller_->ShowNudgeIfNeeded();
   }
 }
@@ -534,8 +528,7 @@
     return;
   }
 
-  if (features::IsPhoneHubOnboardingNotifierRevampEnabled() &&
-      AnchoredNudgeManager::Get()->IsNudgeShown(
+  if (AnchoredNudgeManager::Get()->IsNudgeShown(
           OnboardingNudgeController::kPhoneHubNudgeId)) {
     is_icon_clicked_when_nudge_visible_ = true;
     onboarding_nudge_controller_->HideNudge();
@@ -568,12 +561,7 @@
 
 bool PhoneHubTray::IsInsideUnlockWindow() {
   return (base::Time::NowFromSystemTime() - last_unlocked_timestamp_) <=
-         features::kMultiDeviceSetupNotificationTimeLimit.Get();
-}
-
-bool PhoneHubTray::IsInPhoneHubNudgeExperimentGroup() {
-  return features::IsPhoneHubOnboardingNotifierRevampEnabled() &&
-         features::kPhoneHubOnboardingNotifierUseNudge.Get();
+         kMultiDeviceSetupNotificationTimeLimit;
 }
 
 BEGIN_METADATA(PhoneHubTray)
diff --git a/ash/system/phonehub/phone_hub_tray.h b/ash/system/phonehub/phone_hub_tray.h
index c8fa21f7..f1603e4 100644
--- a/ash/system/phonehub/phone_hub_tray.h
+++ b/ash/system/phonehub/phone_hub_tray.h
@@ -20,6 +20,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/scoped_observation.h"
+#include "base/time/time.h"
 #include "chromeos/ash/components/phonehub/app_stream_manager.h"
 #include "chromeos/ash/components/phonehub/icon_decoder.h"
 #include "chromeos/ash/components/phonehub/phone_hub_manager.h"
@@ -133,6 +134,9 @@
   FRIEND_TEST_ALL_PREFIXES(PhoneHubTrayTest, TrayPressedMetrics);
   FRIEND_TEST_ALL_PREFIXES(PhoneHubTrayTest, AccessibleNames);
 
+  static constexpr base::TimeDelta kMultiDeviceSetupNotificationTimeLimit =
+      base::Minutes(5);
+
   // TrayBubbleView::Delegate:
   std::u16string GetAccessibleNameForBubble() override;
   bool ShouldEnableExtraKeyboardAccessibility() override;
@@ -170,8 +174,6 @@
   // Checks if nudge should be shown based on user login time.
   bool IsInsideUnlockWindow();
 
-  bool IsInPhoneHubNudgeExperimentGroup();
-
   bool is_icon_clicked_when_setup_notification_visible_ = false;
 
   bool is_icon_clicked_when_nudge_visible_ = false;
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 5b41b3d..1bec6ae 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1208,6 +1208,7 @@
       "android/scoped_hardware_buffer_handle.h",
       "android/scoped_input_event.cc",
       "android/scoped_input_event.h",
+      "android/self_compaction_manager.h",
       "android/shared_preferences/shared_preferences_manager.cc",
       "android/shared_preferences/shared_preferences_manager.h",
       "android/statistics_recorder_android.cc",
diff --git a/base/allocator/partition_alloc_features.cc b/base/allocator/partition_alloc_features.cc
index dac4af0..b2942fc 100644
--- a/base/allocator/partition_alloc_features.cc
+++ b/base/allocator/partition_alloc_features.cc
@@ -487,7 +487,11 @@
 #if PA_CONFIG(ENABLE_SHADOW_METADATA)
 BASE_FEATURE(kPartitionAllocShadowMetadata,
              "PartitionAllocShadowMetadata",
+#if BUILDFLAG(IS_LINUX)
+             FEATURE_ENABLED_BY_DEFAULT);
+#else
              FEATURE_DISABLED_BY_DEFAULT);
+#endif
 
 constexpr FeatureParam<ShadowMetadataEnabledProcesses>::Option
     kShadowMetadataEnabledProcessesOptions[] = {
diff --git a/base/android/child_process_service.cc b/base/android/child_process_service.cc
index 30663cd..2165bdd 100644
--- a/base/android/child_process_service.cc
+++ b/base/android/child_process_service.cc
@@ -7,7 +7,7 @@
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/android/library_loader/library_loader_hooks.h"
-#include "base/android/pre_freeze_background_memory_trimmer.h"
+#include "base/android/self_compaction_manager.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/file_descriptor_store.h"
 #include "base/logging.h"
@@ -84,7 +84,7 @@
 }
 
 void JNI_ChildProcessService_OnSelfFreeze(JNIEnv* env) {
-  PreFreezeBackgroundMemoryTrimmer::OnSelfFreeze();
+  SelfCompactionManager::OnSelfFreeze();
 }
 
 }  // namespace android
diff --git a/base/android/pre_freeze_background_memory_trimmer.cc b/base/android/pre_freeze_background_memory_trimmer.cc
index 88b6a8ff..68646d3 100644
--- a/base/android/pre_freeze_background_memory_trimmer.cc
+++ b/base/android/pre_freeze_background_memory_trimmer.cc
@@ -1112,4 +1112,23 @@
                           last_finished - last_cancelled);
 }
 
+void SelfCompactionManager::OnSelfFreeze() {
+  PreFreezeBackgroundMemoryTrimmer::OnSelfFreeze();
+}
+
+void SelfCompactionManager::OnRunningCompact() {
+  PreFreezeBackgroundMemoryTrimmer::OnRunningCompact();
+}
+
+void SelfCompactionManager::MaybeCancelCompaction(
+    base::android::CompactCancellationReason cancellation_reason) {
+  PreFreezeBackgroundMemoryTrimmer::MaybeCancelCompaction(cancellation_reason);
+}
+
+void SelfCompactionManager::SetOnStartSelfCompactionCallback(
+    base::RepeatingCallback<void()> callback) {
+  PreFreezeBackgroundMemoryTrimmer::SetOnStartSelfCompactionCallback(
+      std::move(callback));
+}
+
 }  // namespace base::android
diff --git a/base/android/pre_freeze_background_memory_trimmer.h b/base/android/pre_freeze_background_memory_trimmer.h
index d44791b..38197480 100644
--- a/base/android/pre_freeze_background_memory_trimmer.h
+++ b/base/android/pre_freeze_background_memory_trimmer.h
@@ -24,6 +24,15 @@
 BASE_EXPORT BASE_DECLARE_FEATURE(kShouldFreezeSelf);
 BASE_EXPORT BASE_DECLARE_FEATURE(kUseRunningCompact);
 
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class CompactCancellationReason {
+  kAppFreezer,
+  kPageResumed,
+  kTimeout,
+  kMaxValue = kTimeout
+};
+
 // Starting from Android U, apps are frozen shortly after being backgrounded
 // (with some exceptions). This causes some background tasks for reclaiming
 // resources in Chrome to not be run until Chrome is foregrounded again (which
@@ -36,15 +45,6 @@
 // be frozen.
 class BASE_EXPORT PreFreezeBackgroundMemoryTrimmer {
  public:
-  // These values are persisted to logs. Entries should not be renumbered and
-  // numeric values should never be reused.
-  enum class CompactCancellationReason {
-    kAppFreezer,
-    kPageResumed,
-    kTimeout,
-    kMaxValue = kTimeout
-  };
-
   static PreFreezeBackgroundMemoryTrimmer& Instance();
   ~PreFreezeBackgroundMemoryTrimmer() = delete;
 
@@ -425,6 +425,23 @@
   bool supports_modern_trim_;
 };
 
+class BASE_EXPORT SelfCompactionManager {
+ public:
+  using CompactCancellationReason = CompactCancellationReason;
+  static void OnSelfFreeze();
+  static void OnRunningCompact();
+
+  // If we are currently doing self compaction, cancel it. If it was running,
+  // record a metric with the reason for the cancellation.
+  static void MaybeCancelCompaction(
+      CompactCancellationReason cancellation_reason);
+
+  // The callback runs in the thread pool. The caller cannot make any thread
+  // safety assumptions for the callback execution (e.g. it could run
+  // concurrently with the thread that registered it).
+  static void SetOnStartSelfCompactionCallback(base::RepeatingClosure callback);
+};
+
 }  // namespace base::android
 
 #endif  // BASE_ANDROID_PRE_FREEZE_BACKGROUND_MEMORY_TRIMMER_H_
diff --git a/base/android/pre_freeze_background_memory_trimmer_unittest.cc b/base/android/pre_freeze_background_memory_trimmer_unittest.cc
index 5bf5cdd..cc1e0c4 100644
--- a/base/android/pre_freeze_background_memory_trimmer_unittest.cc
+++ b/base/android/pre_freeze_background_memory_trimmer_unittest.cc
@@ -882,8 +882,7 @@
   EXPECT_TRUE(ShouldContinueCompaction(triggered_at));
 
   PreFreezeBackgroundMemoryTrimmer::MaybeCancelCompaction(
-      PreFreezeBackgroundMemoryTrimmer::CompactCancellationReason::
-          kPageResumed);
+      SelfCompactionManager::CompactCancellationReason::kPageResumed);
 
   EXPECT_FALSE(ShouldContinueCompaction(triggered_at));
 }
@@ -907,8 +906,7 @@
   // We should not record the metric here, because we are not currently
   // running.
   PreFreezeBackgroundMemoryTrimmer::MaybeCancelCompaction(
-      PreFreezeBackgroundMemoryTrimmer::CompactCancellationReason::
-          kPageResumed);
+      SelfCompactionManager::CompactCancellationReason::kPageResumed);
 
   // This metric is used for both self compaction and running compaction, with
   // the same prefix for both.
@@ -940,8 +938,7 @@
   EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 1u);
 
   PreFreezeBackgroundMemoryTrimmer::MaybeCancelCompaction(
-      PreFreezeBackgroundMemoryTrimmer::CompactCancellationReason::
-          kPageResumed);
+      SelfCompactionManager::CompactCancellationReason::kPageResumed);
 
   task_environment_.FastForwardBy(
       task_environment_.NextMainThreadPendingTaskDelay());
@@ -962,8 +959,7 @@
   // Still only expect it to be recorded once, because we were not running the
   // second time we tried to cancel.
   PreFreezeBackgroundMemoryTrimmer::MaybeCancelCompaction(
-      PreFreezeBackgroundMemoryTrimmer::CompactCancellationReason::
-          kPageResumed);
+      SelfCompactionManager::CompactCancellationReason::kPageResumed);
   histograms_.ExpectTotalCount(
       "Memory.RunningOrSelfCompact.Renderer.Cancellation.Reason", 1);
 
@@ -1181,8 +1177,7 @@
   task_environment_.FastForwardBy(base::Seconds(1));
 
   PreFreezeBackgroundMemoryTrimmer::MaybeCancelCompaction(
-      PreFreezeBackgroundMemoryTrimmer::CompactCancellationReason::
-          kPageResumed);
+      SelfCompactionManager::CompactCancellationReason::kPageResumed);
   EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 1u);
 
   task_environment_.FastForwardBy(
diff --git a/base/android/self_compaction_manager.h b/base/android/self_compaction_manager.h
new file mode 100644
index 0000000..4c289081
--- /dev/null
+++ b/base/android/self_compaction_manager.h
@@ -0,0 +1,10 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_SELF_COMPACTION_MANAGER_H_
+#define BASE_ANDROID_SELF_COMPACTION_MANAGER_H_
+
+#include "base/android/pre_freeze_background_memory_trimmer.h"
+
+#endif  // BASE_ANDROID_SELF_COMPACTION_MANAGER_H_
diff --git a/base/third_party/xdg_user_dirs/README.chromium b/base/third_party/xdg_user_dirs/README.chromium
index 6edfaa4..0d58a77 100644
--- a/base/third_party/xdg_user_dirs/README.chromium
+++ b/base/third_party/xdg_user_dirs/README.chromium
@@ -1,9 +1,11 @@
 Name: xdg-user-dirs
 URL: http://www.freedesktop.org/wiki/Software/xdg-user-dirs
+Version: N/A
 Revision: 2f28f353ec3cf9288da70bab3ca963f2144808f0
 Date: 2009-02-26
 License: MIT
 License File: LICENSE
+Security Critical: yes
 Shipped: yes
 
 This directory include xdg-user-dir-lookup.c renamed as xdg_user_dir_lookup.cc
diff --git a/build/config/mac/BUILD.gn b/build/config/mac/BUILD.gn
index 66ca06b..0d5276c 100644
--- a/build/config/mac/BUILD.gn
+++ b/build/config/mac/BUILD.gn
@@ -37,6 +37,14 @@
 
   ldflags = common_mac_flags
 
+  # ld64 defaults to fixup chains on macOS 12+ when targeting arm64 and on
+  # macOS 13+ when targeting x86_64. ld.lld defaults to it on macOS 13+.
+  # It's probably safe to enable it on macOS even on intel, but for now
+  # only explicitly opt in on arm64.
+  if (current_cpu == "arm64") {
+    ldflags += [ "-Wl,-fixup_chains" ]
+  }
+
   if (save_unstripped_output) {
     ldflags += [ "-Wcrl,unstripped," + rebase_path(root_out_dir) ]
   }
diff --git a/build/config/siso/android.star b/build/config/siso/android.star
index 1eac27ac..45a906a 100644
--- a/build/config/siso/android.star
+++ b/build/config/siso/android.star
@@ -159,7 +159,9 @@
             "remote": remote_run_static_analysis,
             "platform_ref": "large",
             "canonicalize_dir": True,
-            "timeout": "2m",
+            # obj/chrome/android/chrome_java__errorprone.stamp step takes too
+            # long.
+            "timeout": "6m",
         },
         {
             "name": "android/compile_kt",
@@ -243,6 +245,16 @@
             "timeout": "10m",
         },
         {
+            "name": "android/proguard/local",
+            "command_prefix": "python3 ../../build/android/gyp/proguard.py",
+            "action_outs": [
+                # http://crbug.com/396004680#comment15: It slows down CQ build.
+                # It's better to run it locally.
+                "./obj/chrome/test/android_browsertests__apk/android_browsertests__apk.r8dex.jar",
+            ],
+            "remote": False,
+        },
+        {
             "name": "android/proguard",
             "command_prefix": "python3 ../../build/android/gyp/proguard.py",
             "handler": "android_proguard",
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index dd79298..0794121 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -1083,16 +1083,17 @@
       // The transform node has the realized scroll offset and snap amount,
       // and should be used for rendering.
       const auto* scroll_node = scroll_tree.FindNodeFromElementId(element_id);
-      CHECK(scroll_node);
-      if (const auto* transform =
-              transform_tree.Node(scroll_node->transform_id)) {
+      const auto* transform =
+          scroll_node ? transform_tree.Node(scroll_node->transform_id)
+                      : nullptr;
+      if (transform) {
         map[element_id] = gfx::PointAtOffsetFromOrigin(
             -transform->to_parent.To2dTranslation());
       } else {
-        // Use the current scroll offset if the scroll node doesn't have a
-        // transform node. It doesn't matter because such a scroller is
-        // invisible. TODO(crbug.com/419921722): Investigate the case and
-        // add a test case.
+        // Use the current scroll offset if the scroll node doesn't exist or
+        // doesn't have a transform node. It doesn't matter because such a
+        // scroller is invisible. TODO(crbug.com/419921722): Investigate the
+        // case and add a test case.
         map[element_id] = scroll_tree.current_scroll_offset(element_id);
       }
     }
diff --git a/chrome/VERSION b/chrome/VERSION
index 9d6e947..24ce670 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=139
 MINOR=0
-BUILD=7205
+BUILD=7206
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 53e1d8a..9d2662b 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -2683,11 +2683,13 @@
   }
 
   # Options shared by all script test targets that call `run_wpt_tests.py`.
+  # TODO(crbug.com/419890016): Consolidate the common options.
   _common_web_test_options = [
     "--no-show-results",
     "--zero-tests-executed-ok",
     "--build-directory",
     "@WrappedPath(.)",
+    "--verbose",
   ]
   if (is_debug) {
     _common_web_test_options += [ "--debug" ]
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index f0bffc5a..c2f3b36 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -337,7 +337,6 @@
   "java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinator.java",
   "java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabLoadTracker.java",
   "java/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripIphController.java",
-  "java/src/org/chromium/chrome/browser/compositor/overlays/strip/TooltipManager.java",
   "java/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/ExternalViewDragDropReorderStrategy.java",
   "java/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/GroupReorderStrategy.java",
   "java/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/ReorderDelegate.java",
diff --git a/chrome/android/features/tab_ui/BUILD.gn b/chrome/android/features/tab_ui/BUILD.gn
index 245c04e..0237bb0 100644
--- a/chrome/android/features/tab_ui/BUILD.gn
+++ b/chrome/android/features/tab_ui/BUILD.gn
@@ -67,7 +67,6 @@
     "java/res/drawable/tab_strip_item_notification_bubble.xml",
     "java/res/drawable/tab_strip_selected_ring.xml",
     "java/res/drawable/tab_strip_selected_ring_incognito.xml",
-    "java/res/drawable/tab_strip_tooltip_background.xml",
     "java/res/drawable/tablet_tab_switcher_empty_state_illustration.xml",
     "java/res/drawable/ungroup_bar_background.xml",
     "java/res/layout/archived_tabs_auto_delete_promo.xml",
@@ -108,7 +107,6 @@
     "java/res/layout/tab_list_editor_toolbar.xml",
     "java/res/layout/tab_list_recycler_view_layout.xml",
     "java/res/layout/tab_strip_item.xml",
-    "java/res/layout/tab_strip_tooltip_holder.xml",
     "java/res/layout/toolbar_back_button.xml",
     "java/res/layout/toolbar_new_tab_and_menu_button.xml",
     "java/res/values-night/colors.xml",
diff --git a/chrome/android/features/tab_ui/java/res/drawable/tab_strip_tooltip_background.xml b/chrome/android/features/tab_ui/java/res/drawable/tab_strip_tooltip_background.xml
deleted file mode 100644
index 4dfc64e..0000000
--- a/chrome/android/features/tab_ui/java/res/drawable/tab_strip_tooltip_background.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright 2025 The Chromium Authors
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<shape
-    xmlns:android="http://schemas.android.com/apk/res/android">
-    <corners android:radius="@dimen/tab_strip_tooltip_corner_radius"/>
-    <solid android:color="@macro/default_bg_color_inverse"/>
-</shape>
diff --git a/chrome/android/features/tab_ui/java/res/layout/tab_strip_tooltip_holder.xml b/chrome/android/features/tab_ui/java/res/layout/tab_strip_tooltip_holder.xml
deleted file mode 100644
index 850479bc..0000000
--- a/chrome/android/features/tab_ui/java/res/layout/tab_strip_tooltip_holder.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright 2025 The Chromium Authors
-Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.
--->
-
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/tab_strip_tooltip_holder"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:visibility="gone" >
-
-    <TextView
-        android:id="@+id/tooltip_label"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_margin="@dimen/tab_strip_tooltip_margin"
-        android:paddingHorizontal="@dimen/tab_strip_tooltip_label_horizontal_padding"
-        android:paddingVertical="@dimen/tab_strip_tooltip_label_vertical_padding"
-        android:textAppearance="@style/TextAppearance.TextSmall.Primary.OnAccent1"
-        android:background="@drawable/tab_strip_tooltip_background" />
-</FrameLayout>
diff --git a/chrome/android/features/tab_ui/java/res/values/dimens.xml b/chrome/android/features/tab_ui/java/res/values/dimens.xml
index b9fd2588..9738c7c 100644
--- a/chrome/android/features/tab_ui/java/res/values/dimens.xml
+++ b/chrome/android/features/tab_ui/java/res/values/dimens.xml
@@ -139,11 +139,6 @@
     <dimen name="message_card_close_button_size">24dp</dimen>
     <dimen name="message_card_description_vertical_margin">14dp</dimen>
 
-    <!-- Dimens for tab strip tooltip. -->
-    <dimen name="tab_strip_tooltip_margin">10dp</dimen>
-    <dimen name="tab_strip_tooltip_label_horizontal_padding">8dp</dimen>
-    <dimen name="tab_strip_tooltip_label_vertical_padding">4dp</dimen>
-    <dimen name="tab_strip_tooltip_corner_radius">4dp</dimen>
     <dimen name="tab_strip_shared_image_tiles_size">26dp</dimen>
 
     <!-- Dimens for tab group list bottom sheet. -->
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPane.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPane.java
index 1db0b7b..6f2c6c80 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPane.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IncognitoTabSwitcherPane.java
@@ -39,7 +39,6 @@
 import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeController;
 import org.chromium.chrome.browser.user_education.UserEducationHelper;
 import org.chromium.chrome.tab_ui.R;
-import org.chromium.components.omnibox.OmniboxFeatures;
 import org.chromium.components.sensitive_content.SensitiveContentFeatures;
 
 import java.lang.annotation.Retention;
@@ -101,9 +100,7 @@
 
                     setNewTabButtonEnabledState(/* enabled= */ true);
 
-                    if (OmniboxFeatures.sAndroidHubSearch.isEnabled()) {
-                        mHubSearchEnabledStateSupplier.set(true);
-                    }
+                    mHubSearchEnabledStateSupplier.set(true);
                 }
 
                 @Override
@@ -288,7 +285,7 @@
             coordinator.resetWithListOfTabs(null);
             cancelWaitForTabStateInitializedTimer();
 
-            if (OmniboxFeatures.sAndroidHubSearch.isEnabled() && incognitoReauthShowing) {
+            if (incognitoReauthShowing) {
                 mHubSearchEnabledStateSupplier.set(false);
             }
         } else {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabArchiveSettingsFragment.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabArchiveSettingsFragment.java
index 541fb05..e515f67 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabArchiveSettingsFragment.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabArchiveSettingsFragment.java
@@ -100,7 +100,8 @@
         enableArchiveDuplicateTabsSwitch.setTitle(
                 getString(R.string.archive_settings_archive_duplicate_tabs_title));
         enableArchiveDuplicateTabsSwitch.setEnabled(
-                ChromeFeatureList.sAndroidTabDeclutterArchiveDuplicateTabs.isEnabled());
+                ChromeFeatureList.sAndroidTabDeclutterArchiveDuplicateTabs.isEnabled()
+                        && mArchiveSettings.getArchiveEnabled());
         enableArchiveDuplicateTabsSwitch.setChecked(
                 mArchiveSettings.isArchiveDuplicateTabsEnabled());
         enableArchiveDuplicateTabsSwitch.setOnPreferenceChangeListener(
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabArchiveSettingsFragmentUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabArchiveSettingsFragmentUnitTest.java
index 78594f8..2f10ed3 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabArchiveSettingsFragmentUnitTest.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabArchiveSettingsFragmentUnitTest.java
@@ -22,6 +22,8 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
+import org.chromium.base.task.PostTask;
+import org.chromium.base.task.TaskTraits;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.HistogramWatcher;
 import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
@@ -147,8 +149,21 @@
                 HistogramWatcher.newSingleRecordWatcher(
                         "Tabs.ArchiveSettings.ArchiveDuplicateTabsEnabled", true);
         enableArchiveDuplicateTabs.onClick();
+        histogramWatcher.assertExpected();
         assertTrue(enableArchiveDuplicateTabs.isEnabled());
         assertTrue(mArchiveSettings.isArchiveDuplicateTabsEnabled());
+
+        // Click "Never" radio button to disable archive. The archive duplicate tabs
+        // preference should be disabled.
+        radioButton = archiveTimeDeltaPreference.getRadioButtonForTesting(0);
+        radioButton.onClick(radioButton);
+        // PostTask to ensure the UI is updated after the preference change.
+        PostTask.postTask(
+                TaskTraits.UI_DEFAULT,
+                () -> {
+                    assertFalse(enableArchiveDuplicateTabs.isEnabled());
+                    assertFalse(enableArchiveDuplicateTabs.isChecked());
+                });
     }
 
     @Test
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneBase.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneBase.java
index fa50fc8..9e2ef9b 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneBase.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneBase.java
@@ -64,7 +64,6 @@
 import org.chromium.components.browser_ui.styles.ChromeColors;
 import org.chromium.components.browser_ui.widget.MenuOrKeyboardActionController.MenuOrKeyboardActionHandler;
 import org.chromium.components.feature_engagement.Tracker;
-import org.chromium.components.omnibox.OmniboxFeatures;
 import org.chromium.ui.base.DeviceFormFactor;
 
 import java.util.List;
@@ -142,16 +141,14 @@
                 @Override
                 public void beforeStart() {
                     mIsAnimatingSupplier.set(true);
-                    if (OmniboxFeatures.sAndroidHubSearch.isEnabled()
-                            && mPaneHubController != null) {
+                    if (mPaneHubController != null) {
                         mPaneHubController.setSearchBoxBackgroundProperties(/* shouldShow= */ true);
                     }
                 }
 
                 @Override
                 public void afterEnd() {
-                    if (OmniboxFeatures.sAndroidHubSearch.isEnabled()
-                            && mPaneHubController != null) {
+                    if (mPaneHubController != null) {
                         mPaneHubController.setSearchBoxBackgroundProperties(
                                 /* shouldShow= */ false);
                     }
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabUiFeatureUtilitiesUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabUiFeatureUtilitiesUnitTest.java
index fa55ac48..bdbf07a 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabUiFeatureUtilitiesUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabUiFeatureUtilitiesUnitTest.java
@@ -23,7 +23,9 @@
 import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.chrome.browser.device.DeviceClassManager;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
+import org.chromium.ui.util.XrUtils;
 
 /** Unit Tests for {@link TabUiFeatureUtilities}. */
 @RunWith(BaseRobolectricTestRunner.class)
@@ -80,4 +82,19 @@
 
         assertFalse(TabUiFeatureUtilities.shouldUseListMode());
     }
+
+    @Test
+    @CommandLineFlags.Add({ChromeSwitches.DISABLE_FULLSCREEN})
+    public void testDisableFullScreen_XrDeviceWithFlag_isTrue() {
+        XrUtils.setXrDeviceForTesting(true);
+
+        assertFalse(DeviceClassManager.enableFullscreen());
+    }
+
+    @Test
+    public void testDisableFullScreen_XrDeviceWithoutFlag_isTrue() {
+        XrUtils.setXrDeviceForTesting(true);
+
+        assertFalse(DeviceClassManager.enableFullscreen());
+    }
 }
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/HasContentListener.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/HasContentListener.java
index d317622..cd6d682 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/HasContentListener.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/HasContentListener.java
@@ -4,7 +4,10 @@
 
 package org.chromium.chrome.browser.feed;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Interface to listen to the hasContent events from FeedSurfaceMediator. */
+@NullMarked
 public interface HasContentListener {
     /** Called when the has content state changes. */
     void hasContentChanged(@StreamKind int kind, boolean hasContent);
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/shared/ui/MaterialSpinnerView.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/shared/ui/MaterialSpinnerView.java
index be9d1b2..596e28a 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/shared/ui/MaterialSpinnerView.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/shared/ui/MaterialSpinnerView.java
@@ -8,14 +8,16 @@
 import android.util.AttributeSet;
 import android.view.View;
 
-import androidx.annotation.Nullable;
 import androidx.appcompat.widget.AppCompatImageView;
 import androidx.swiperefreshlayout.widget.CircularProgressDrawable;
 
 import org.chromium.base.TraceEvent;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.components.browser_ui.styles.SemanticColorUtils;
 
 /** View that shows a Material themed spinner. */
+@NullMarked
 public class MaterialSpinnerView extends AppCompatImageView {
     private final CircularProgressDrawable mSpinner;
 
diff --git a/chrome/android/java/res_app/layout/main.xml b/chrome/android/java/res_app/layout/main.xml
index 625f8b0..629c385 100644
--- a/chrome/android/java/res_app/layout/main.xml
+++ b/chrome/android/java/res_app/layout/main.xml
@@ -159,13 +159,6 @@
             android:inflatedId="@+id/tab_hover_card_holder"
             android:layout="@layout/tab_hover_card_holder" />
 
-        <ViewStub
-            android:id="@+id/tab_strip_tooltip_holder_stub"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:inflatedId="@+id/tab_strip_tooltip_holder"
-            android:layout="@layout/tab_strip_tooltip_holder" />
-
         <org.chromium.components.messages.MessageContainer
             android:id="@+id/message_container"
             android:layout_width="match_parent"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index d8ac9f6b..9a7c23c5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -897,7 +897,6 @@
             CompositorViewHolder compositorViewHolder = getCompositorViewHolderSupplier().get();
 
             ViewStub tabHoverCardViewStub = findViewById(R.id.tab_hover_card_holder_stub);
-            ViewStub tabStripTooltipViewStub = findViewById(R.id.tab_strip_tooltip_holder_stub);
             View toolbarContainerView = findViewById(R.id.toolbar_container);
             mDragDropDelegate = new DragAndDropDelegateImpl();
             mDragDropDelegate.setDragAndDropBrowserDelegate(
@@ -927,7 +926,6 @@
                             mDragDropDelegate,
                             toolbarContainerView,
                             tabHoverCardViewStub,
-                            tabStripTooltipViewStub,
                             getWindowAndroid(),
                             getToolbarManager(),
                             mRootUiCoordinator.getDesktopWindowStateManager(),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
index 78a8cbd0..41755a5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
@@ -49,6 +49,7 @@
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.gsa.GSAUtils;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator;
+import org.chromium.chrome.browser.pdf.PdfUtils;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.profiles.ProfileManager;
 import org.chromium.chrome.browser.renderer_host.ChromeNavigationUiData;
@@ -1015,7 +1016,8 @@
                 String lowerCaseUrl = url.toLowerCase(Locale.US);
                 if (ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL.equals(lowerCaseUrl)
                         || ContentUrlConstants.ABOUT_BLANK_URL.equals(lowerCaseUrl)
-                        || UrlConstants.CHROME_DINO_URL.equals(lowerCaseUrl)) {
+                        || UrlConstants.CHROME_DINO_URL.equals(lowerCaseUrl)
+                        || lowerCaseUrl.startsWith(UrlConstants.PDF_URL)) {
                     return false;
                 }
 
@@ -1157,6 +1159,12 @@
         if (isGoogleChromeScheme(url)) {
             url = ExternalNavigationHandler.getUrlFromSelfSchemeUrl(GOOGLECHROME_SCHEME, url);
         }
+        // To display a PDF in Chrome, the content URI must be encoded.
+        String encodedPdfUrl =
+                PdfUtils.getEncodedContentUri(url, ContextUtils.getApplicationContext());
+        if (!TextUtils.isEmpty(encodedPdfUrl)) {
+            url = encodedPdfUrl;
+        }
         return url;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatService.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatService.java
index a43a79e..ed81a78 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatService.java
@@ -71,7 +71,7 @@
     }
 
     @Override
-    public IBinder onBind(Intent intent) {
+    public @Nullable IBinder onBind(Intent intent) {
         return mImpl.onBind(intent);
     }
 
@@ -117,6 +117,6 @@
             return mService.superOnUnbind(intent);
         }
 
-        public abstract IBinder onBind(Intent intent);
+        public abstract @Nullable IBinder onBind(Intent intent);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
index 621558f..7a43f69 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
@@ -73,7 +73,6 @@
      *     tab drag and drop.
      * @param toolbarContainerView View passed to StripLayoutHelper to support tab drag and drop.
      * @param tabHoverCardViewStub The ViewStub representing the strip tab hover card.
-     * @param tabStripTooltipViewStub The ViewStub representing the tooltip for NTB or MSB.
      * @param toolbarManager The ToolbarManager instance.
      * @param desktopWindowStateManager The DesktopWindowStateManager for the app header.
      * @param actionConfirmationManager The {@link ActionConfirmationManager} for group actions.
@@ -96,7 +95,6 @@
             DragAndDropDelegate dragAndDropDelegate,
             View toolbarContainerView,
             @NonNull ViewStub tabHoverCardViewStub,
-            @NonNull ViewStub tabStripTooltipViewStub,
             @NonNull WindowAndroid windowAndroid,
             @NonNull ToolbarManager toolbarManager,
             @Nullable DesktopWindowStateManager desktopWindowStateManager,
@@ -125,7 +123,6 @@
                         dragAndDropDelegate,
                         toolbarContainerView,
                         tabHoverCardViewStub,
-                        tabStripTooltipViewStub,
                         tabContentManagerSupplier,
                         browserControlsStateProvider,
                         windowAndroid,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/CompositorButton.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/CompositorButton.java
index 4b4b41c..1938f0d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/CompositorButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/CompositorButton.java
@@ -12,7 +12,6 @@
 import androidx.annotation.Nullable;
 
 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutView;
-import org.chromium.chrome.browser.compositor.overlays.strip.TooltipManager;
 import org.chromium.ui.util.MotionEventUtils;
 
 import java.lang.annotation.Retention;
@@ -47,6 +46,10 @@
         int TAB_CLOSE = 2;
     }
 
+    public interface TooltipHandler {
+        void setTooltipText(String text);
+    }
+
     protected int mResource;
     protected int mBackgroundResource;
 
@@ -60,7 +63,7 @@
     private boolean mIsHovered;
     private String mAccessibilityDescriptionIncognito = "";
 
-    @Nullable private TooltipManager mTooltipManager;
+    private final TooltipHandler mTooltipHandler;
 
     // @StripLayoutView the button was embedded in. Null if it's not a child view.
     @Nullable private final StripLayoutView mParentView;
@@ -83,6 +86,7 @@
             StripLayoutView parentView,
             float width,
             float height,
+            TooltipHandler tooltipHandler,
             StripLayoutViewOnClickHandler clickHandler,
             StripLayoutViewOnKeyboardFocusHandler keyboardFocusHandler,
             float clickSlopDp) {
@@ -93,6 +97,7 @@
         mOpacity = 1.f;
         mIsPressed = false;
         mParentView = parentView;
+        mTooltipHandler = tooltipHandler;
         setVisible(true);
 
         mClickSlop = clickSlopDp;
@@ -282,13 +287,13 @@
     }
 
     /**
-     * Set whether button is hovered on and notify the tooltip manager if the hover state changed.
+     * Set whether button is hovered on and notify the tooltip handler if the hover state changed.
      *
      * @param isHovered Whether the button is hovered on.
      */
     public void setHovered(boolean isHovered) {
-        if (mTooltipManager != null && mIsHovered != isHovered) {
-            mTooltipManager.setHovered(this, isHovered);
+        if (mTooltipHandler != null && mIsHovered != isHovered) {
+            mTooltipHandler.setTooltipText(isHovered ? getAccessibilityDescription() : "");
         }
         mIsHovered = isHovered;
     }
@@ -330,13 +335,4 @@
     public boolean getShouldApplyHoverBackground() {
         return isHovered() || isPressedFromMouse();
     }
-
-    /**
-     * @param tooltipManager The {@link
-     *     org.chromium.chrome.browser.compositor.overlays.strip.TooltipManager} responsible for the
-     *     tooltip associated with this button.
-     */
-    public void setTooltipManager(TooltipManager tooltipManager) {
-        mTooltipManager = tooltipManager;
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/TintedCompositorButton.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/TintedCompositorButton.java
index 5b600d86..0cab01ef 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/TintedCompositorButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/TintedCompositorButton.java
@@ -38,6 +38,7 @@
             StripLayoutView parentView,
             float width,
             float height,
+            TooltipHandler tooltipHandler,
             StripLayoutViewOnClickHandler clickHandler,
             StripLayoutViewOnKeyboardFocusHandler keyboardFocusHandler,
             @DrawableRes int resource,
@@ -48,6 +49,7 @@
                 parentView,
                 width,
                 height,
+                tooltipHandler,
                 clickHandler,
                 keyboardFocusHandler,
                 clickSlopDp);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/NewBackgroundTabAnimationHostView.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/NewBackgroundTabAnimationHostView.java
index d3833dc..e033c64a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/NewBackgroundTabAnimationHostView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/NewBackgroundTabAnimationHostView.java
@@ -13,7 +13,6 @@
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.View;
-import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
@@ -21,8 +20,6 @@
 import androidx.annotation.IntDef;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
-import org.chromium.chrome.browser.hub.NewTabAnimationUtils.NewTabAnim;
 import org.chromium.chrome.browser.theme.ThemeUtils;
 import org.chromium.chrome.browser.toolbar.top.ToggleTabStackButton;
 import org.chromium.chrome.browser.ui.theme.BrandedColorScheme;
@@ -92,31 +89,17 @@
         target[0] -= Math.round(mLinkIcon.getWidth() / 2f);
         target[1] -= Math.round(mLinkIcon.getHeight() / 2f);
 
-        // TODO(crbug.com/419065710): Clean up versions.
-        @NewTabAnim int version = ChromeFeatureList.sShowNewTabAnimationsVersion.getValue();
-
         AnimatorSet transitionAnimator = getTransitionAnimator();
-        ObjectAnimator pathAnimator =
-                getPathArcAnimator(originX, originY, target[0], target[1], version);
+        ObjectAnimator pathAnimator = getPathArcAnimator(originX, originY, target[0], target[1]);
         AnimatorSet backgroundAnimation = new AnimatorSet();
         AnimatorSet fakeTabSwitcherAnimator;
 
         if (mAnimationType == AnimationType.DEFAULT) {
             fakeTabSwitcherAnimator =
                     mFakeTabSwitcherButton.getShrinkAnimator(/* incrementCount= */ true);
+            fakeTabSwitcherAnimator.setStartDelay(SHRINK_DELAY_DURATION_MS);
+            transitionAnimator.setStartDelay(SHRINK_DELAY_DURATION_MS);
 
-            if (version == NewTabAnim.BOUNCE
-                    || version == NewTabAnim.BOUNCE_DECELERATE_WITH_DELAY) {
-                fakeTabSwitcherAnimator.setInterpolator(
-                        Interpolators.NEW_BACKGROUND_TAB_ANIMATION_BOUNCE_INTERPOLATOR);
-                fakeTabSwitcherAnimator.setStartDelay(SHRINK_DELAY_DURATION_MS);
-                transitionAnimator.setStartDelay(SHRINK_DELAY_DURATION_MS);
-            } else if (version == NewTabAnim.BOUNCE_DECELERATE) {
-                fakeTabSwitcherAnimator.setInterpolator(
-                        Interpolators.NEW_BACKGROUND_TAB_ANIMATION_BOUNCE_INTERPOLATOR);
-            } else {
-                fakeTabSwitcherAnimator.setInterpolator(Interpolators.STANDARD_INTERPOLATOR);
-            }
             backgroundAnimation
                     .play(transitionAnimator)
                     .with(fakeTabSwitcherAnimator)
@@ -208,26 +191,16 @@
      * @param originY y-coordinate for the start point.
      * @param finalX x-coordinate for the end point.
      * @param finalY y-coordinate for the end point.
-     * @param version The {@link NewTabAnim} animation version.
      */
     private ObjectAnimator getPathArcAnimator(
-            float originX, float originY, float finalX, float finalY, @NewTabAnim int version) {
+            float originX, float originY, float finalX, float finalY) {
         boolean isClockwise = mIsTopToolbar ? (originX >= finalX) : (originX <= finalX);
 
         ObjectAnimator animator =
                 ViewCurvedMotionAnimatorFactory.build(
                         mLinkIcon, originX, originY, finalX, finalY, isClockwise);
         animator.setDuration(PATH_ARC_DURATION_MS);
-
-        Interpolator pathInterpolator =
-                switch (version) {
-                    case NewTabAnim.M137 -> Interpolators
-                            .NEW_BACKGROUND_TAB_ANIMATION_PATH_INTERPOLATOR;
-                    case NewTabAnim.BOUNCE -> Interpolators
-                            .NEW_BACKGROUND_TAB_ANIMATION_SECOND_PATH_INTERPOLATOR;
-                    default -> Interpolators.EMPHASIZED_DECELERATE;
-                };
-        animator.setInterpolator(pathInterpolator);
+        animator.setInterpolator(Interpolators.EMPHASIZED_DECELERATE);
 
         animator.addListener(
                 new AnimatorListenerAdapter() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/NewBackgroundTabFakeTabSwitcherButton.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/NewBackgroundTabFakeTabSwitcherButton.java
index 02b98f4..787be518 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/NewBackgroundTabFakeTabSwitcherButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/NewBackgroundTabFakeTabSwitcherButton.java
@@ -132,6 +132,7 @@
         AnimatorSet animatorSet = new AnimatorSet();
         animatorSet.playTogether(scaleXAnimator, scaleYAnimator);
         animatorSet.setDuration(SHRINK_DURATION_MS);
+        animatorSet.setInterpolator(Interpolators.NEW_BACKGROUND_TAB_ANIMATION_BOUNCE_INTERPOLATOR);
 
         animatorSet.addListener(
                 new AnimatorListenerAdapter() {
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 b01b1e0..42f1fd9 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
@@ -619,6 +619,9 @@
                         null,
                         NEW_TAB_BUTTON_BACKGROUND_WIDTH_DP,
                         NEW_TAB_BUTTON_BACKGROUND_HEIGHT_DP,
+                        (text) -> {
+                            mToolbarContainerView.setTooltipText(text);
+                        },
                         /* clickHandler= */ this,
                         /* keyboardFocusHandler= */ this,
                         R.drawable.ic_new_tab_button,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
index 4ffedecb..3477b1c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
@@ -21,7 +21,6 @@
 import android.view.View.OnDragListener;
 import android.view.ViewStub;
 import android.view.animation.Interpolator;
-import android.widget.FrameLayout;
 
 import androidx.annotation.ColorInt;
 import androidx.annotation.DrawableRes;
@@ -226,8 +225,6 @@
     private final TabSwitcherLayoutObserver mTabSwitcherLayoutObserver;
     private final View mToolbarControlContainer;
     private final ViewStub mTabHoverCardViewStub;
-    @Nullable private TooltipManager mTooltipManager;
-    private final ViewStub mTabStripTooltipViewStub;
     private float mModelSelectorWidth;
     private float mLastVisibleViewportOffsetY;
 
@@ -340,11 +337,6 @@
                 mTabHoverCardViewStub.inflate();
             }
 
-            // Inflate the tab strip tooltip ViewStub if not already inflated.
-            if (mTabStripTooltipViewStub.getParent() != null) {
-                mTabStripTooltipViewStub.inflate();
-            }
-
             getActiveStripLayoutHelper().onHoverEnter(x, y);
         }
 
@@ -414,7 +406,6 @@
      *     drop.
      * @param toolbarContainerView View passed to TabDragSource for drag and drop.
      * @param tabHoverCardViewStub The ViewStub representing the strip tab hover card.
-     * @param tabStripTooltipViewStub The ViewStub representing the tooltip for tab strip buttons.
      * @param tabContentManagerSupplier Supplier of the TabContentManager instance.
      * @param browserControlsStateProvider BrowserControlsStateProvider for drag drop.
      * @param toolbarManager The ToolbarManager instance.
@@ -436,7 +427,6 @@
             DragAndDropDelegate dragDropDelegate,
             View toolbarContainerView,
             @NonNull ViewStub tabHoverCardViewStub,
-            @NonNull ViewStub tabStripTooltipViewStub,
             ObservableSupplier<TabContentManager> tabContentManagerSupplier,
             @NonNull BrowserControlsStateProvider browserControlsStateProvider,
             @NonNull WindowAndroid windowAndroid,
@@ -497,7 +487,6 @@
         mStripEndPadding = res.getDimension(R.dimen.button_end_padding) / mDensity;
 
         mTabHoverCardViewStub = tabHoverCardViewStub;
-        mTabStripTooltipViewStub = tabStripTooltipViewStub;
 
         if (MultiWindowUtils.isMultiInstanceApi31Enabled()) {
             mTabDragSource =
@@ -563,16 +552,6 @@
                     mIncognitoHelper.setTabHoverCardView(hoverCardView);
                 });
 
-        tabStripTooltipViewStub.setOnInflateListener(
-                (viewStub, view) -> {
-                    mTooltipManager = new TooltipManager((FrameLayout) view, () -> mTopPadding);
-                    mNormalHelper.getNewTabButton().setTooltipManager(mTooltipManager);
-                    mIncognitoHelper.getNewTabButton().setTooltipManager(mTooltipManager);
-                    if (mModelSelectorButton != null) {
-                        mModelSelectorButton.setTooltipManager(mTooltipManager);
-                    }
-                });
-
         if (tabModelStartupInfoSupplier != null) {
             if (tabModelStartupInfoSupplier.hasValue()) {
                 setTabModelStartupInfo(tabModelStartupInfoSupplier.get());
@@ -621,6 +600,9 @@
                         null,
                         MODEL_SELECTOR_BUTTON_BACKGROUND_WIDTH_DP,
                         MODEL_SELECTOR_BUTTON_BACKGROUND_HEIGHT_DP,
+                        (tooltipText) -> {
+                            mToolbarControlContainer.setTooltipText(tooltipText);
+                        },
                         selectorClickHandler,
                         keyboardFocusHandler,
                         R.drawable.ic_incognito,
@@ -692,9 +674,6 @@
         mModelSelectorButton.setAccessibilityDescription(
                 context.getString(R.string.accessibility_tabstrip_btn_incognito_toggle_standard),
                 context.getString(R.string.accessibility_tabstrip_btn_incognito_toggle_incognito));
-        if (mTooltipManager != null) {
-            mModelSelectorButton.setTooltipManager(mTooltipManager);
-        }
     }
 
     /** Cleans up internal state. An instance should not be used after this method is called. */
@@ -1623,14 +1602,6 @@
         return mTabHoverCardViewStub;
     }
 
-    ViewStub getTooltipViewStubForTesting() {
-        return mTabStripTooltipViewStub;
-    }
-
-    TooltipManager getTooltipManagerForTesting() {
-        return mTooltipManager;
-    }
-
     public TabDragSource getTabDragSourceForTesting() {
         return mTabDragSource;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
index 5e57c39..f820733 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
@@ -204,6 +204,7 @@
                         this,
                         /* width= */ 0,
                         /* height= */ 0,
+                        /* tooltipHandler= */ null,
                         clickHandler,
                         keyboardFocusHandler,
                         R.drawable.btn_tab_close_normal,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TooltipManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TooltipManager.java
deleted file mode 100644
index 97ef56e..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/TooltipManager.java
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2025 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.compositor.overlays.strip;
-
-import android.annotation.SuppressLint;
-import android.os.Handler;
-import android.os.Message;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import org.chromium.base.MathUtils;
-import org.chromium.base.supplier.Supplier;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.compositor.layouts.components.CompositorButton;
-
-/** Manages the tooltip that is shown when a CompositorButton is hovered. */
-public class TooltipManager {
-    private final TooltipEventHandler mHandler = new TooltipEventHandler();
-    private CompositorButton mCurrentButton;
-    private final FrameLayout mTooltipView;
-    private final Supplier<Float> mTopPaddingSupplier; // in dp units
-
-    private static final int MESSAGE_SHOW_TOOLTIP = 1;
-    private static final int TOOLTIP_DELAY_MS = 1000;
-
-    public TooltipManager(FrameLayout tooltipView, Supplier<Float> topPaddingSupplierDp) {
-        mTooltipView = tooltipView;
-        mTopPaddingSupplier = topPaddingSupplierDp;
-    }
-
-    public void setHovered(CompositorButton button, boolean isHovered) {
-        if (isHovered && mCurrentButton != button) {
-            hideImmediately();
-            showWithDelayFor(button);
-        } else if (!isHovered && mCurrentButton == button) {
-            hideImmediately();
-        }
-    }
-
-    private void clearPendingMessages() {
-        mHandler.removeMessages(MESSAGE_SHOW_TOOLTIP);
-    }
-
-    private void showWithDelayFor(CompositorButton targetButton) {
-        mCurrentButton = targetButton;
-        clearPendingMessages();
-
-        Message message = mHandler.obtainMessage(MESSAGE_SHOW_TOOLTIP, targetButton);
-        mHandler.sendMessageDelayed(message, TOOLTIP_DELAY_MS);
-    }
-
-    void showImmediatelyFor(CompositorButton targetButton) {
-        mCurrentButton = targetButton;
-
-        ((TextView) mTooltipView.findViewById(R.id.tooltip_label))
-                .setText(targetButton.getAccessibilityDescription());
-
-        mTooltipView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
-        float tooltipWidthPx = mTooltipView.getMeasuredWidth();
-        mTooltipView.setX(calculateTooltipXPx(targetButton, tooltipWidthPx));
-        mTooltipView.setY(calculateTooltipYPx(targetButton));
-
-        mTooltipView.setVisibility(View.VISIBLE);
-    }
-
-    void hideImmediately() {
-        mCurrentButton = null;
-        clearPendingMessages();
-        mTooltipView.setVisibility(View.GONE);
-    }
-
-    private float calculateTooltipXPx(CompositorButton targetButton, float tooltipWidthPx) {
-        float idealXCenterDp = targetButton.getDrawX() + targetButton.getWidth() / 2f;
-        float idealXCenterPx = idealXCenterDp * getDisplayDensity();
-        float idealXLeftPx = idealXCenterPx - tooltipWidthPx / 2f;
-        float safeXLeftPx = MathUtils.clamp(idealXLeftPx, 0, getWindowWidthPx() - tooltipWidthPx);
-        return safeXLeftPx;
-    }
-
-    private float calculateTooltipYPx(CompositorButton targetButton) {
-        float yDp = mTopPaddingSupplier.get() + targetButton.getDrawY() + targetButton.getHeight();
-        float yPx = yDp * getDisplayDensity();
-        return yPx;
-    }
-
-    private float getWindowWidthPx() {
-        return mTooltipView.getContext().getResources().getDisplayMetrics().widthPixels;
-    }
-
-    private float getDisplayDensity() {
-        return mTooltipView.getContext().getResources().getDisplayMetrics().density;
-    }
-
-    protected FrameLayout getTooltipViewForTesting() {
-        return mTooltipView;
-    }
-
-    @SuppressLint("HandlerLeak")
-    private class TooltipEventHandler extends Handler {
-        @Override
-        public void handleMessage(Message m) {
-            if (m.what != MESSAGE_SHOW_TOOLTIP) {
-                assert false : "TooltipEventHandler got unknown message " + m.what;
-            }
-            showImmediatelyFor((CompositorButton) m.obj);
-        }
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
index c228bf1c..5ab6fdd1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
@@ -26,6 +26,7 @@
 import org.chromium.base.SysUtils;
 import org.chromium.base.UserData;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.IntentHandler;
@@ -362,6 +363,7 @@
         new UkmRecorder(mTab.getWebContents(), "DomDistiller.Android.ReaderModeShown")
                 .addBooleanMetric("Shown")
                 .record();
+        RecordUserAction.record("DomDistiller.Android.OnStartedReaderMode");
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/FileAccessPermissionHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/download/FileAccessPermissionHelper.java
index 9021e591..2131e84 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/FileAccessPermissionHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/FileAccessPermissionHelper.java
@@ -10,9 +10,9 @@
 import android.os.Build;
 import android.util.Pair;
 
-import androidx.annotation.NonNull;
-
 import org.chromium.base.Callback;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.components.permissions.AndroidPermissionRequester;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.modaldialog.DialogDismissalCause;
@@ -24,9 +24,10 @@
 import java.util.function.Consumer;
 
 /**
- * Handles file access permission requests.
- * TODO(shaktisahu): Move this to a generic location, preferably ui/android.
+ * Handles file access permission requests. TODO(shaktisahu): Move this to a generic location,
+ * preferably ui/android.
  */
+@NullMarked
 public class FileAccessPermissionHelper {
     /**
      * Requests the storage permission from Java.
@@ -35,7 +36,7 @@
      * @param callback Callback to notify if the permission is granted or not.
      */
     public static void requestFileAccessPermission(
-            @NonNull WindowAndroid windowAndroid, final Callback<Boolean> callback) {
+            WindowAndroid windowAndroid, final Callback<Boolean> callback) {
         requestFileAccessPermissionHelper(
                 windowAndroid,
                 result -> {
@@ -54,7 +55,7 @@
     }
 
     static void requestFileAccessPermissionHelper(
-            @NonNull WindowAndroid windowAndroid, final Callback<Pair<Boolean, String>> callback) {
+            WindowAndroid windowAndroid, final Callback<Pair<Boolean, String>> callback) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
                 || windowAndroid.hasPermission(permission.WRITE_EXTERNAL_STORAGE)) {
             callback.onResult(Pair.create(true, null));
@@ -80,7 +81,7 @@
             return;
         }
 
-        Consumer<PropertyModel> requestPermissions =
+        Consumer<@Nullable PropertyModel> requestPermissions =
                 (model) -> {
                     PermissionCallback permissionCallback =
                             (permissions, grantResults) -> {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/OfflineContentAvailabilityStatusProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/download/OfflineContentAvailabilityStatusProvider.java
index 429be05..626549e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/OfflineContentAvailabilityStatusProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/OfflineContentAvailabilityStatusProvider.java
@@ -6,6 +6,8 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.download.items.OfflineContentAggregatorFactory;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
@@ -23,8 +25,9 @@
  * used to decide whether or not users should see messages in the UI about offline content
  * availability in Chrome.
  */
+@NullMarked
 public class OfflineContentAvailabilityStatusProvider implements OfflineContentProvider.Observer {
-    private static OfflineContentAvailabilityStatusProvider sInstance;
+    private static @Nullable OfflineContentAvailabilityStatusProvider sInstance;
 
     // Keeps track of suggested content.
     private final Set<ContentId> mSuggestedItems = new HashSet<>();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayout.java
index ad63a1a..ef5b368 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayout.java
@@ -61,7 +61,6 @@
 import org.chromium.components.browser_ui.desktop_windowing.AppHeaderState;
 import org.chromium.components.browser_ui.desktop_windowing.DesktopWindowStateManager;
 import org.chromium.components.browser_ui.desktop_windowing.DesktopWindowStateManager.AppHeaderObserver;
-import org.chromium.components.omnibox.OmniboxFeatures;
 import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.base.LocalizationUtils;
 import org.chromium.ui.resources.ResourceManager;
@@ -753,7 +752,7 @@
         if (mTabModelSelector.isIncognitoBrandedModelSelected() != newIsIncognito) {
             // Start from above the toolbar when switching models.
             finalRect.top = containerViewRect.top;
-        } else if (OmniboxFeatures.sAndroidHubSearch.isEnabled()) {
+        } else {
             // Account for the hub's search box container height.
             int searchBoxHeight =
                     HubUtils.getSearchBoxHeight(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayoutUnitTest.java b/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayoutUnitTest.java
index 68c03ec..f2c2955 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayoutUnitTest.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/hub/HubLayoutUnitTest.java
@@ -68,8 +68,6 @@
 import org.chromium.base.supplier.Supplier;
 import org.chromium.base.supplier.SyncOneshotSupplierImpl;
 import org.chromium.base.test.BaseRobolectricTestRule;
-import org.chromium.base.test.util.Features.DisableFeatures;
-import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.base.test.util.UserActionTester;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
@@ -93,7 +91,6 @@
 import org.chromium.chrome.browser.tab_ui.TabContentManager;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.components.browser_ui.desktop_windowing.DesktopWindowStateManager;
-import org.chromium.components.omnibox.OmniboxFeatureList;
 import org.chromium.ui.base.TestActivity;
 import org.chromium.ui.resources.ResourceManager;
 import org.chromium.ui.util.XrUtils;
@@ -640,41 +637,6 @@
     }
 
     @Test
-    @DisableFeatures(OmniboxFeatureList.ANDROID_HUB_SEARCH)
-    public void testFinalRect_SameModel() {
-        setupFinalRectMocks(/* modelIsIncognito= */ false);
-        Rect expectedRect = new Rect(0, 10, 90, 110);
-        Rect actualRect = new Rect();
-
-        mHubLayout.getFinalRectForNewTabAnimation(
-                mHubContainerViewMock, /* newIsIncognito= */ false, actualRect);
-        assertEquals(expectedRect, actualRect);
-
-        when(mTabModelSelector.isIncognitoBrandedModelSelected()).thenReturn(true);
-        mHubLayout.getFinalRectForNewTabAnimation(
-                mHubContainerViewMock, /* newIsIncognito= */ true, actualRect);
-        assertEquals(expectedRect, actualRect);
-    }
-
-    @Test
-    @DisableFeatures(OmniboxFeatureList.ANDROID_HUB_SEARCH)
-    public void testFinalRect_SwitchingModel() {
-        setupFinalRectMocks(/* modelIsIncognito= */ false);
-        Rect expectedRect = new Rect(0, 0, 90, 110);
-        Rect actualRect = new Rect();
-
-        mHubLayout.getFinalRectForNewTabAnimation(
-                mHubContainerViewMock, /* newIsIncognito= */ true, actualRect);
-        assertEquals(expectedRect, actualRect);
-
-        when(mTabModelSelector.isIncognitoBrandedModelSelected()).thenReturn(true);
-        mHubLayout.getFinalRectForNewTabAnimation(
-                mHubContainerViewMock, /* newIsIncognito= */ false, actualRect);
-        assertEquals(expectedRect, actualRect);
-    }
-
-    @Test
-    @EnableFeatures(OmniboxFeatureList.ANDROID_HUB_SEARCH)
     public void testFinalRectWithHubSearch_SwitchingModel() {
         setupFinalRectMocks(/* modelIsIncognito= */ false);
         Rect expectedRect = new Rect(0, 0, 90, 110);
@@ -691,7 +653,6 @@
     }
 
     @Test
-    @EnableFeatures(OmniboxFeatureList.ANDROID_HUB_SEARCH)
     public void testFinalRectWithHubSearch_SameModel() {
         setupFinalRectMocks(/* modelIsIncognito= */ false);
         Rect spyRect = spy(new Rect());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/hub/NewTabAnimationUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/hub/NewTabAnimationUtils.java
index eae5cd3..6965e4c9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/hub/NewTabAnimationUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/hub/NewTabAnimationUtils.java
@@ -42,28 +42,6 @@
         int CENTER = 4;
     }
 
-    /**
-     * Version for the new background tab animation.
-     *
-     * <p>These numbers match with the "version" feature param for ShowNewTabAnimations.
-     */
-    @IntDef({
-        NewTabAnim.M137,
-        NewTabAnim.BOUNCE,
-        NewTabAnim.DECELERATE,
-        NewTabAnim.BOUNCE_DECELERATE,
-        NewTabAnim.BOUNCE_DECELERATE_WITH_DELAY
-    })
-    @Target(ElementType.TYPE_USE)
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface NewTabAnim {
-        int M137 = 0;
-        int BOUNCE = 1;
-        int DECELERATE = 2;
-        int BOUNCE_DECELERATE = 3;
-        int BOUNCE_DECELERATE_WITH_DELAY = 4;
-    }
-
     private static final float INITIAL_SCALE = 0.2f;
     private static final float FINAL_SCALE = 1.1f;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoProfileDestroyer.java b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoProfileDestroyer.java
index 665005b..cbb7590 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoProfileDestroyer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoProfileDestroyer.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.incognito;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.profiles.ProfileManager;
 import org.chromium.chrome.browser.tabmodel.IncognitoTabHostUtils;
@@ -13,8 +14,9 @@
 /**
  * Destroys incognito {@link Profile}s when the last incognito tab is destroyed.
  *
- * Reacts to the presence or absence of incognito tabs.
+ * <p>Reacts to the presence or absence of incognito tabs.
  */
+@NullMarked
 public class IncognitoProfileDestroyer implements IncognitoTabModelObserver {
     private final TabModelSelector mTabModelSelector;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoSnapshotController.java b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoSnapshotController.java
index f3ef1c6..a2e88ab4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoSnapshotController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoSnapshotController.java
@@ -9,20 +9,20 @@
 import android.view.Window;
 import android.view.WindowManager;
 
-import androidx.annotation.NonNull;
-
 import org.chromium.base.supplier.Supplier;
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 
 /**
  * An abstract base class to provide common functionalities related to allowing/blocking snapshot
  * for Incognito tabs across {@link ChromeTabbedActivity} and {@link CustomTabActivity}.
  */
+@NullMarked
 public abstract class IncognitoSnapshotController {
 
-    private final @NonNull Activity mActivity;
-    private final @NonNull Window mWindow;
-    private final @NonNull Supplier<Boolean> mIsShowingIncognitoSupplier;
+    private final Activity mActivity;
+    private final Window mWindow;
+    private final Supplier<Boolean> mIsShowingIncognitoSupplier;
 
     /**
      * @param activity The {@link Activity} on which the snapshot capability needs to be controlled.
@@ -30,7 +30,7 @@
      *     showing Incognito or not currently.
      */
     protected IncognitoSnapshotController(
-            @NonNull Activity activity, @NonNull Supplier<Boolean> isShowingIncognitoSupplier) {
+            Activity activity, Supplier<Boolean> isShowingIncognitoSupplier) {
         mActivity = activity;
         mWindow = activity.getWindow();
         mIsShowingIncognitoSupplier = isShowingIncognitoSupplier;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillSaveCardInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillSaveCardInfoBar.java
index d567a32..e638515 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillSaveCardInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillSaveCardInfoBar.java
@@ -15,11 +15,11 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import androidx.annotation.Nullable;
-
 import org.jni_zero.CalledByNative;
 import org.jni_zero.NativeMethods;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.components.autofill.payments.CardDetail;
 import org.chromium.components.autofill.payments.LegalMessageLine;
@@ -34,6 +34,7 @@
 import java.util.List;
 
 /** An infobar for saving credit card information. */
+@NullMarked
 public class AutofillSaveCardInfoBar extends ConfirmInfoBar {
 
     private final @Nullable String mAccountFooterEmail;
@@ -42,7 +43,7 @@
     private final List<CardDetail> mCardDetails = new ArrayList<>();
     private int mIconDrawableId = -1;
     private final String mTitleText;
-    private String mDescriptionText;
+    private @Nullable String mDescriptionText;
     private final boolean mIsGooglePayBrandingEnabled;
     private final LinkedList<LegalMessageLine> mLegalMessageLines =
             new LinkedList<LegalMessageLine>();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainerView.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainerView.java
index 169e9e64..b929804 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainerView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainerView.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.infobar;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
@@ -12,11 +14,11 @@
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsUtils;
 import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeController;
@@ -32,6 +34,7 @@
 import org.chromium.ui.display.DisplayUtil;
 
 /** The {@link View} for the {@link InfoBarContainer}. */
+@NullMarked
 public class InfoBarContainerView extends SwipableOverlayView
         implements BrowserControlsStateProvider.Observer, InsetObserver.WindowInsetObserver {
     /** Observes container view changes. */
@@ -55,15 +58,15 @@
     /** Whether or not the InfoBarContainer is allowed to hide when the user scrolls. */
     private static boolean sIsAllowedToAutoHide = true;
 
-    private final BrowserControlsStateProvider mBrowserControlsStateProvider;
+    private final @Nullable BrowserControlsStateProvider mBrowserControlsStateProvider;
     private final ContainerViewObserver mContainerViewObserver;
     private final InfoBarContainerLayout mLayout;
 
     /** Parent view that contains the InfoBarContainerLayout. */
-    private ViewGroup mParentView;
+    private @Nullable ViewGroup mParentView;
 
     /** Animation used to snap the container to the nearest state if scroll direction changes. */
-    private Animator mScrollDirectionChangeAnimation;
+    private @Nullable Animator mScrollDirectionChangeAnimation;
 
     /** Whether or not the current scroll is downward. */
     private boolean mIsScrollingDownward;
@@ -71,8 +74,8 @@
     /** Tracks the previous event's scroll offset to determine if a scroll is up or down. */
     private int mLastScrollOffsetY;
 
-    @Nullable private final ObservableSupplier<EdgeToEdgeController> mEdgeToEdgeSupplier;
-    @Nullable private EdgeToEdgePadAdjuster mEdgeToEdgePadAdjuster;
+    private final @Nullable ObservableSupplier<EdgeToEdgeController> mEdgeToEdgeSupplier;
+    private @Nullable EdgeToEdgePadAdjuster mEdgeToEdgePadAdjuster;
 
     /**
      * @param context The {@link Context} that this view is attached to.
@@ -85,8 +88,8 @@
      */
     @Deprecated
     InfoBarContainerView(
-            @NonNull Context context,
-            @NonNull ContainerViewObserver containerViewObserver,
+            Context context,
+            ContainerViewObserver containerViewObserver,
             @Nullable BrowserControlsStateProvider browserControlsStateProvider,
             boolean isTablet) {
         this(context, containerViewObserver, browserControlsStateProvider, null, isTablet);
@@ -103,8 +106,8 @@
      * @param isTablet Whether this view is displayed on tablet or not.
      */
     InfoBarContainerView(
-            @NonNull Context context,
-            @NonNull ContainerViewObserver containerViewObserver,
+            Context context,
+            ContainerViewObserver containerViewObserver,
             @Nullable BrowserControlsStateProvider browserControlsStateProvider,
             @Nullable ObservableSupplier<EdgeToEdgeController> edgeToEdgeSupplier,
             boolean isTablet) {
@@ -134,7 +137,8 @@
                             }
 
                             @Override
-                            public void notifyAllAnimationsFinished(InfoBarUiItem frontInfoBar) {
+                            public void notifyAllAnimationsFinished(
+                                    @Nullable InfoBarUiItem frontInfoBar) {
                                 mContainerViewObserver.notifyAllAnimationsFinished(frontInfoBar);
                             }
                         });
@@ -172,6 +176,7 @@
 
     @Override
     protected boolean shouldConsumeScroll(int scrollOffsetY, int scrollExtentY) {
+        assumeNonNull(mBrowserControlsStateProvider);
         if (mBrowserControlsStateProvider.getBottomControlsHeight() <= 0) return true;
 
         boolean isScrollingDownward = scrollOffsetY > mLastScrollOffsetY;
@@ -235,7 +240,7 @@
                 getTotalHeight()
                         * 1.0f
                         * Math.abs(topOffset)
-                        / mBrowserControlsStateProvider.getTopControlsHeight());
+                        / assumeNonNull(mBrowserControlsStateProvider).getTopControlsHeight());
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/KnownInterceptionDisclosureInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/KnownInterceptionDisclosureInfoBar.java
index 76372018..6ef94c8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/KnownInterceptionDisclosureInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/KnownInterceptionDisclosureInfoBar.java
@@ -10,13 +10,15 @@
 
 import org.jni_zero.CalledByNative;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.components.infobars.ConfirmInfoBar;
 import org.chromium.components.infobars.InfoBarLayout;
 
 /**
- * An infobar to disclose known monitoring to the user. This is a thin veneer over
- * standard ConfirmInfoBar to provide a description as well as a title.
+ * An infobar to disclose known monitoring to the user. This is a thin veneer over standard
+ * ConfirmInfoBar to provide a description as well as a title.
  */
+@NullMarked
 public class KnownInterceptionDisclosureInfoBar extends ConfirmInfoBar {
     private final String mDescription;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/PasswordInfoBarUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/PasswordInfoBarUtils.java
index 19560bb..e81f39df 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/PasswordInfoBarUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/PasswordInfoBarUtils.java
@@ -10,10 +10,12 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.R;
 import org.chromium.components.browser_ui.widget.RoundedCornerImageView;
 
 /** Provides helper methods for Android Infobars. */
+@NullMarked
 class PasswordInfoBarUtils {
     private PasswordInfoBarUtils() {}
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/PermissionInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/PermissionInfoBar.java
index 43fb1a4..b77cd50 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/PermissionInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/PermissionInfoBar.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.infobar;
 
+import static org.chromium.build.NullUtil.assertNonNull;
+
 import android.os.Bundle;
 import android.text.SpannableString;
 import android.text.SpannableStringBuilder;
@@ -11,6 +13,7 @@
 
 import org.jni_zero.CalledByNative;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.settings.SettingsNavigationFactory;
 import org.chromium.components.browser_ui.settings.SettingsNavigation;
@@ -24,6 +27,7 @@
 import org.chromium.ui.text.ChromeClickableSpan;
 
 /** An infobar used for prompting the user to grant a web API permission. */
+@NullMarked
 public class PermissionInfoBar extends ConfirmInfoBar
         implements AndroidPermissionRequester.RequestDelegate {
     /** The window which this infobar will be displayed upon. */
@@ -179,7 +183,7 @@
         SettingsNavigation settingsNavigation =
                 SettingsNavigationFactory.createSettingsNavigation();
         settingsNavigation.startSettings(
-                getContext(), SingleCategorySettings.class, fragmentArguments);
+                assertNonNull(getContext()), SingleCategorySettings.class, fragmentArguments);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/SubPanelListener.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/SubPanelListener.java
index d792fcb..7a65b946 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/SubPanelListener.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/SubPanelListener.java
@@ -3,7 +3,10 @@
 // found in the LICENSE file.
 package org.chromium.chrome.browser.infobar;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** A listener to interact with the different subpanels of the translate infobar. */
+@NullMarked
 public interface SubPanelListener {
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ActivityLifecycleDispatcherImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ActivityLifecycleDispatcherImpl.java
index 492a9aa9..6852e01 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ActivityLifecycleDispatcherImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ActivityLifecycleDispatcherImpl.java
@@ -9,9 +9,9 @@
 import android.content.res.Configuration;
 import android.os.Bundle;
 
-import androidx.annotation.Nullable;
-
 import org.chromium.base.ObserverList;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.lifecycle.ActivityResultWithNativeObserver;
 import org.chromium.chrome.browser.lifecycle.ConfigurationChangedObserver;
@@ -31,8 +31,9 @@
  * Dispatches lifecycle events of activities extending {@link AsyncInitializationActivity} to
  * registered observers.
  *
- * All observers will be automatically cleared when the backing activity is destroyed.
+ * <p>All observers will be automatically cleared when the backing activity is destroyed.
  */
+@NullMarked
 public class ActivityLifecycleDispatcherImpl implements ActivityLifecycleDispatcher {
     private final ObserverList<InflationObserver> mInflationObservers = new ObserverList<>();
     private final ObserverList<NativeInitObserver> mNativeInitObservers = new ObserverList<>();
@@ -61,7 +62,7 @@
     private boolean mIsNativeInitialized;
     private boolean mDestroyed;
 
-    public ActivityLifecycleDispatcherImpl(Activity activity) {
+    public ActivityLifecycleDispatcherImpl(@Nullable Activity activity) {
         mActivity = activity;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ActivityProfileProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ActivityProfileProvider.java
index 8220c9ba..67304d1c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ActivityProfileProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ActivityProfileProvider.java
@@ -4,10 +4,9 @@
 
 package org.chromium.chrome.browser.init;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
 import org.chromium.base.supplier.OneshotSupplierImpl;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.lifecycle.DestroyObserver;
 import org.chromium.chrome.browser.profiles.OtrProfileId;
@@ -16,9 +15,10 @@
 import org.chromium.chrome.browser.profiles.ProfileProvider;
 
 /** Handles initializing an Activity appropriate ProfileProvider. */
+@NullMarked
 public class ActivityProfileProvider extends OneshotSupplierImpl<ProfileProvider>
         implements ProfileManager.Observer, DestroyObserver {
-    private OtrProfileId mOtrProfileId;
+    private @Nullable OtrProfileId mOtrProfileId;
     private boolean mHasCreatedOtrProfileId;
 
     /**
@@ -26,7 +26,7 @@
      *
      * @param lifecycleDispatcher Provides lifecycle events for the host activity.
      */
-    public ActivityProfileProvider(@NonNull ActivityLifecycleDispatcher lifecycleDispatcher) {
+    public ActivityProfileProvider(ActivityLifecycleDispatcher lifecycleDispatcher) {
         lifecycleDispatcher.register(this);
 
         if (ProfileManager.isInitialized()) {
@@ -49,15 +49,14 @@
     private void onProfileManagerReady() {
         set(
                 new ProfileProvider() {
-                    @NonNull
+
                     @Override
                     public Profile getOriginalProfile() {
                         return ProfileManager.getLastUsedRegularProfile();
                     }
 
-                    @Nullable
                     @Override
-                    public Profile getOffTheRecordProfile(boolean createIfNeeded) {
+                    public @Nullable Profile getOffTheRecordProfile(boolean createIfNeeded) {
                         Profile originalProfile = getOriginalProfile();
                         OtrProfileId otrProfileId = getOrCreateOtrProfileId();
                         return otrProfileId == null
@@ -77,8 +76,7 @@
                 });
     }
 
-    @Nullable
-    private OtrProfileId getOrCreateOtrProfileId() {
+    private @Nullable OtrProfileId getOrCreateOtrProfileId() {
         if (!mHasCreatedOtrProfileId) {
             mOtrProfileId = createOffTheRecordProfileId();
             mHasCreatedOtrProfileId = true;
@@ -90,8 +88,7 @@
      * Create the OtrProfileId that should be used for the incognito profile of this provider. If
      * null, the default OffTheRecord profile will be used.
      */
-    @Nullable
-    protected OtrProfileId createOffTheRecordProfileId() {
+    protected @Nullable OtrProfileId createOffTheRecordProfileId() {
         return null;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/BrowserParts.java b/chrome/android/java/src/org/chromium/chrome/browser/init/BrowserParts.java
index b1d4f647..e351342 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/BrowserParts.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/BrowserParts.java
@@ -4,14 +4,16 @@
 
 package org.chromium.chrome.browser.init;
 
-import androidx.annotation.Nullable;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * Interface that any {@link AsyncInitializationActivity} can use to interact with this delegate
- * during start up. Functions called by
- * {@link ChromeBrowserInitializer#handlePreNativeStartupAndLoadLibraries(BrowserParts)} are called
- * in the order they are listed.
+ * during start up. Functions called by {@link
+ * ChromeBrowserInitializer#handlePreNativeStartupAndLoadLibraries(BrowserParts)} are called in the
+ * order they are listed.
  */
+@NullMarked
 public interface BrowserParts {
     /**
      * Called during {@link
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeActivityNativeDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeActivityNativeDelegate.java
index 5f8e780..964e29d8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeActivityNativeDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeActivityNativeDelegate.java
@@ -6,7 +6,8 @@
 
 import android.content.Intent;
 
-import androidx.annotation.Nullable;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 /**
  * An activity level delegate to handle native initialization and activity lifecycle related tasks
@@ -15,6 +16,7 @@
  * have not been loaded yet, the calls in ChromeActivityNativeDelegate will be in the right order
  * among themselves, but can be deferred and out of sync wrt to Activity calls.
  */
+@NullMarked
 public interface ChromeActivityNativeDelegate {
     /**
      * Carry out native initialization related tasks and any other java tasks that can be done async
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/MinimalBrowserStartupUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/init/MinimalBrowserStartupUtils.java
index aff3054e..a81d1dba 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/MinimalBrowserStartupUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/MinimalBrowserStartupUtils.java
@@ -4,7 +4,10 @@
 
 package org.chromium.chrome.browser.init;
 
+import org.chromium.build.annotations.NullMarked;
+
 /** Helper class for features that can be run in the minimal browser mode. */
+@NullMarked
 public class MinimalBrowserStartupUtils {
     public static final String TASK_TAG = "Servicification Startup Task";
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureDevicesDispatcherAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureDevicesDispatcherAndroid.java
index 52373c9e..f8331bf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureDevicesDispatcherAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureDevicesDispatcherAndroid.java
@@ -6,12 +6,14 @@
 
 import org.jni_zero.NativeMethods;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.content_public.browser.WebContents;
 
 /**
  * Java access point for MediaCaptureDevicesDispatcher, allowing for querying and manipulation of
  * media capture state.
  */
+@NullMarked
 public class MediaCaptureDevicesDispatcherAndroid {
     public static boolean isCapturingAudio(WebContents webContents) {
         if (webContents == null) return false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPicture.java b/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPicture.java
index 9e96fe1..9ee5a659 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPicture.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPicture.java
@@ -10,11 +10,13 @@
 import android.os.Build;
 
 import org.chromium.base.TraceEvent;
+import org.chromium.build.annotations.NullMarked;
 
 /**
  * Utility for determining if Picture-in-Picture is available and whether the user has disabled
  * Picture-in-Picture for Chrome using the system's per-application settings.
  */
+@NullMarked
 public abstract class PictureInPicture {
     private PictureInPicture() {}
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/ChromeMediaNotificationControllerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/ChromeMediaNotificationControllerDelegate.java
index 9ae8f7a0..1781ad2d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/ChromeMediaNotificationControllerDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/ChromeMediaNotificationControllerDelegate.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.media.ui;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.app.Service;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -14,12 +16,13 @@
 import android.support.v4.media.session.MediaSessionCompat;
 import android.util.SparseArray;
 
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.mediarouter.media.MediaRouter;
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.base.SplitCompatService;
 import org.chromium.chrome.browser.notifications.NotificationConstants;
@@ -34,6 +37,7 @@
 import org.chromium.components.browser_ui.notifications.NotificationWrapperBuilder;
 
 /** A class that provides Chrome-specific behavior to {@link MediaNotificationController}. */
+@NullMarked
 class ChromeMediaNotificationControllerDelegate implements MediaNotificationController.Delegate {
     private final int mNotificationId;
 
@@ -86,7 +90,7 @@
         }
 
         @Override
-        public IBinder onBind(Intent intent) {
+        public @Nullable IBinder onBind(Intent intent) {
             return null;
         }
 
@@ -99,7 +103,7 @@
         }
 
         @Override
-        public int onStartCommand(Intent intent, int flags, int startId) {
+        public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
             if (!processIntent(intent)) {
                 // The service has been started with startForegroundService() but the
                 // notification hasn't been shown. On O it will lead to the app crash.
@@ -122,7 +126,7 @@
         }
 
         @VisibleForTesting
-        boolean processIntent(Intent intent) {
+        boolean processIntent(@Nullable Intent intent) {
             MediaNotificationController controller = getController();
             if (controller == null) return false;
 
@@ -224,8 +228,9 @@
     }
 
     @Override
-    public Intent createServiceIntent() {
-        Class<?> serviceClass = sMapNotificationIdToOptions.get(mNotificationId).serviceClass;
+    public @Nullable Intent createServiceIntent() {
+        Class<?> serviceClass =
+                assumeNonNull(sMapNotificationIdToOptions.get(mNotificationId)).serviceClass;
         return (serviceClass != null) ? new Intent(getContext(), serviceClass) : null;
     }
 
@@ -236,7 +241,8 @@
 
     @Override
     public String getNotificationGroupName() {
-        String groupName = sMapNotificationIdToOptions.get(mNotificationId).groupName;
+        String groupName =
+                assumeNonNull(sMapNotificationIdToOptions.get(mNotificationId)).groupName;
 
         assert groupName != null;
         return groupName;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
index 33ab778..e436073 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
@@ -79,7 +79,6 @@
 import org.chromium.components.browser_ui.edge_to_edge.EdgeToEdgeSystemBarColorHelper;
 import org.chromium.components.browser_ui.modaldialog.AppModalPresenter;
 import org.chromium.components.metrics.OmniboxEventProtos.OmniboxEventProto.PageClassification;
-import org.chromium.components.omnibox.OmniboxFeatures;
 import org.chromium.ui.base.ActivityKeyboardVisibilityDelegate;
 import org.chromium.ui.base.ActivityWindowAndroid;
 import org.chromium.ui.modaldialog.ModalDialogManager;
@@ -410,9 +409,7 @@
 
         mSearchBoxDataProvider.setCurrentUrl(SearchActivityUtils.getIntentUrl(intent));
 
-        if (OmniboxFeatures.sAndroidHubSearch.isEnabled()) {
-            setColorScheme(mSearchBoxDataProvider.isIncognitoBranded());
-        }
+        setColorScheme(mSearchBoxDataProvider.isIncognitoBranded());
 
         switch (mIntentOrigin) {
             case IntentOrigin.CUSTOM_TAB:
@@ -518,7 +515,7 @@
     private void finishNativeInitializationWithProfile(Profile profile) {
         refinePageClassWithProfile(profile);
 
-        if (OmniboxFeatures.sAndroidHubSearch.isEnabled() && mIntentOrigin == IntentOrigin.HUB) {
+        if (mIntentOrigin == IntentOrigin.HUB) {
             setHubSearchBoxUrlBarElements();
         }
 
@@ -668,8 +665,7 @@
             intent.putExtra(SearchWidgetProvider.EXTRA_FROM_SEARCH_WIDGET, true);
         }
 
-        if (OmniboxFeatures.sAndroidHubSearch.isEnabled()
-                && mSearchBoxDataProvider.isIncognitoBranded()) {
+        if (mSearchBoxDataProvider.isIncognitoBranded()) {
             intent.putExtra(Browser.EXTRA_APPLICATION_ID, getApplicationContext().getPackageName());
             intent.putExtra(IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB, true);
             IntentUtils.addTrustedIntentExtras(intent);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserver.java
index 3c92308..7cd67d8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserver.java
@@ -552,7 +552,7 @@
     @Override
     public void onSheetContentChanged(BottomSheetContent newContent) {
         if (newContent != null) {
-            mBottomSheetColor = newContent.getBackgroundColor();
+            mBottomSheetColor = mBottomSheetController.getSheetBackgroundColor();
         }
         updateBottomAttachedColor();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 6060443..224f7da 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -1718,7 +1718,8 @@
                             mWindowAndroid.getInsetObserver(),
                             controlContainerTranslationSupplier,
                             controlContainerHeightSupplier,
-                            keyboardAccessoryStateSupplier.getIsSheetShowingSupplier());
+                            keyboardAccessoryStateSupplier.getIsSheetShowingSupplier(),
+                            this::isUrlBarFocused);
         }
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java
index e08fa4d..d99ebb8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java
@@ -7,7 +7,6 @@
 import android.content.pm.ActivityInfo;
 import android.view.MotionEvent;
 import android.view.View;
-import android.widget.FrameLayout;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -1227,115 +1226,6 @@
                 });
     }
 
-    /** Tests hover enter/move/exit events associated with the tab strip buttons. */
-    @Test
-    @LargeTest
-    @Feature({"TabStrip"})
-    @Restriction(DeviceFormFactor.TABLET)
-    public void testHoverOnTabStripButtons() throws Exception {
-        StripLayoutHelperManager stripLayoutHelperManager =
-                TabStripUtils.getStripLayoutHelperManager(mActivityTestRule.getActivity());
-
-        // Select NTB.
-        CompositorButton newTabButton = stripLayoutHelperManager.getNewTabButton();
-        Assert.assertNotNull(
-                "Tooltip ViewStub should not be inflated before first hover event.",
-                stripLayoutHelperManager.getTooltipViewStubForTesting().getParent());
-
-        // Simulate a hover into NTB.
-        float xEnter = newTabButton.getDrawX() + newTabButton.getWidth() / 2;
-        float yEnter = newTabButton.getDrawY() + newTabButton.getHeight() / 2;
-        ThreadUtils.runOnUiThreadBlocking(
-                () ->
-                        stripLayoutHelperManager.simulateHoverEventForTesting(
-                                MotionEvent.ACTION_HOVER_ENTER, xEnter, yEnter));
-
-        // Verify that the tooltip is visible as expected.
-        FrameLayout tooltipView =
-                stripLayoutHelperManager.getTooltipManagerForTesting().getTooltipViewForTesting();
-        Assert.assertNotNull("Tooltip view should be set.", tooltipView);
-        CriteriaHelper.pollInstrumentationThread(
-                () -> {
-                    Criteria.checkThat(
-                            "Tooltip should be visible.",
-                            tooltipView.getVisibility(),
-                            Matchers.is(View.VISIBLE));
-                });
-
-        // Enter incognito mode.
-        mActivityTestRule.newIncognitoTabFromMenu();
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
-        // Select MSB.
-        CompositorButton modelSelectorButton = stripLayoutHelperManager.getModelSelectorButton();
-        Assert.assertNotNull(
-                "The modelSelectorButton should be set in StripLayoutHelperManager instance",
-                modelSelectorButton);
-
-        // Simulate a subsequent hover into the MSB.
-        float xMove = modelSelectorButton.getDrawX() + modelSelectorButton.getWidth() / 3;
-        float yMove = modelSelectorButton.getDrawY() + modelSelectorButton.getHeight() / 3;
-        ThreadUtils.runOnUiThreadBlocking(
-                () ->
-                        stripLayoutHelperManager.simulateHoverEventForTesting(
-                                MotionEvent.ACTION_HOVER_MOVE, xMove, yMove));
-        Assert.assertNotNull("Tooltip view should be set.", tooltipView);
-        CriteriaHelper.pollInstrumentationThread(
-                () -> {
-                    Criteria.checkThat(
-                            "Tooltip should be visible.",
-                            tooltipView.getVisibility(),
-                            Matchers.is(View.VISIBLE));
-                });
-
-        // Simulate a subsequent hover outside the MSB.
-        float xExit = xMove + modelSelectorButton.getWidth();
-        float yExit = yMove + modelSelectorButton.getHeight();
-        ThreadUtils.runOnUiThreadBlocking(
-                () ->
-                        stripLayoutHelperManager.simulateHoverEventForTesting(
-                                MotionEvent.ACTION_HOVER_EXIT, xExit, yExit));
-        Assert.assertNotNull("Tooltip view should be set.", tooltipView);
-        CriteriaHelper.pollInstrumentationThread(
-                () -> {
-                    Criteria.checkThat(
-                            "Tooltip should be gone.",
-                            tooltipView.getVisibility(),
-                            Matchers.is(View.GONE));
-                });
-
-        // Exit incognito mode.
-        clickIncognitoToggleButton();
-
-        // Simulate a subsequent hover into the MSB outside of incognito mode.
-        ThreadUtils.runOnUiThreadBlocking(
-                () ->
-                        stripLayoutHelperManager.simulateHoverEventForTesting(
-                                MotionEvent.ACTION_HOVER_MOVE, xMove, yMove));
-        Assert.assertNotNull("Tooltip view should be set.", tooltipView);
-        CriteriaHelper.pollInstrumentationThread(
-                () -> {
-                    Criteria.checkThat(
-                            "Tooltip should be visible.",
-                            tooltipView.getVisibility(),
-                            Matchers.is(View.VISIBLE));
-                });
-
-        // Simulate the final hover outside the MSB.
-        ThreadUtils.runOnUiThreadBlocking(
-                () ->
-                        stripLayoutHelperManager.simulateHoverEventForTesting(
-                                MotionEvent.ACTION_HOVER_EXIT, xExit, yExit));
-        Assert.assertNotNull("Tooltip view should be set.", tooltipView);
-        CriteriaHelper.pollInstrumentationThread(
-                () -> {
-                    Criteria.checkThat(
-                            "Tooltip should be gone.",
-                            tooltipView.getVisibility(),
-                            Matchers.is(View.GONE));
-                });
-    }
-
     /** Simulates a click to the incognito toggle button. */
     protected void clickIncognitoToggleButton() {
         final CallbackHelper tabModelSelectedCallback = new CallbackHelper();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/MostVisitedTilesPTTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/MostVisitedTilesPTTest.java
index 576cb1d..605d61e5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/MostVisitedTilesPTTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/MostVisitedTilesPTTest.java
@@ -18,7 +18,10 @@
 
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Features.DisableFeatures;
+import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.base.test.util.HistogramWatcher;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.suggestions.SiteSuggestion;
 import org.chromium.chrome.browser.util.BrowserUiUtils.ModuleTypeOnStartAndNtp;
@@ -33,7 +36,9 @@
 import org.chromium.chrome.test.util.browser.suggestions.mostvisited.FakeMostVisitedSites;
 import org.chromium.net.test.EmbeddedTestServerRule;
 
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /** Tests the Most Visited Tiles in the NTP. */
 @RunWith(ChromeJUnit4ClassRunner.class)
@@ -63,19 +68,43 @@
 
     @Test
     @MediumTest
-    public void test010_ClickFirstMVT() {
+    @DisableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION})
+    public void test010_ClickFirstMVT_DisableMvtCustomization() {
         doClickMVTTest(0);
     }
 
     @Test
     @MediumTest
-    public void test020_ClickLastMVT() {
+    @EnableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION})
+    public void test010_ClickFirstMVT_EnableMvtCustomization() {
+        doClickMVTTest(0);
+    }
+
+    @Test
+    @MediumTest
+    @DisableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION})
+    public void test020_ClickLastMVT_DisableMvtCustomization() {
+        doClickMVTTest(7);
+    }
+
+    @Test
+    @MediumTest
+    @EnableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION})
+    public void test020_ClickLastMVT_EnableMvtCustomization() {
         doClickMVTTest(7);
     }
 
     private void doClickMVTTest(int index) {
         RegularNewTabPageStation page = mCtaTestRule.start();
-        MvtsFacility mvts = page.focusOnMvts(sSiteSuggestions);
+
+        Set<Integer> nonTileIndices;
+        // Populate with the "Add new" button at the end.
+        nonTileIndices = new HashSet<Integer>();
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION)) {
+            nonTileIndices.add(sSiteSuggestions.size());
+        }
+
+        MvtsFacility mvts = page.focusOnMvts(sSiteSuggestions, nonTileIndices);
         WebPageStation mostVisitedPage;
         try (var histogram =
                 HistogramWatcher.newSingleRecordWatcher(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/ShowNtpAtStartupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/ShowNtpAtStartupTest.java
index 34b89bf..ad74e21 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/ShowNtpAtStartupTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/ShowNtpAtStartupTest.java
@@ -43,7 +43,6 @@
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.DoNotBatch;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.Features.DisableFeatures;
 import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.base.test.util.HistogramWatcher;
 import org.chromium.base.test.util.Restriction;
@@ -171,7 +170,6 @@
     @MediumTest
     @Feature({"StartSurface"})
     @EnableFeatures({START_SURFACE_RETURN_TIME_IMMEDIATE, ChromeFeatureList.MAGIC_STACK_ANDROID})
-    @DisableFeatures(ChromeFeatureList.TAB_RESUMPTION_MODULE_ANDROID)
     public void testSingleTabCardGoneAfterTabClosed_MagicStack() throws IOException {
         HomeSurfaceTestUtils.prepareTabStateMetadataFile(
                 new int[] {0, 1}, new String[] {TAB_URL, TAB_URL_1}, 0);
@@ -231,7 +229,6 @@
     @MediumTest
     @Feature({"StartSurface"})
     @EnableFeatures(START_SURFACE_RETURN_TIME_IMMEDIATE)
-    @DisableFeatures(ChromeFeatureList.TAB_RESUMPTION_MODULE_ANDROID)
     public void testSingleTabModule() throws IOException {
         HomeSurfaceTestUtils.prepareTabStateMetadataFile(
                 new int[] {0, 1}, new String[] {TAB_URL, TAB_URL_1}, 0);
@@ -256,7 +253,6 @@
     @MediumTest
     @Feature({"StartSurface"})
     @EnableFeatures({START_SURFACE_RETURN_TIME_IMMEDIATE, ChromeFeatureList.MAGIC_STACK_ANDROID})
-    @DisableFeatures(ChromeFeatureList.TAB_RESUMPTION_MODULE_ANDROID)
     public void testSingleTabModule_MagicStack() throws IOException {
         HomeSurfaceTestUtils.prepareTabStateMetadataFile(
                 new int[] {0, 1}, new String[] {TAB_URL, TAB_URL_1}, 0);
@@ -340,7 +336,6 @@
     @MediumTest
     @Feature({"StartSurface"})
     @EnableFeatures({START_SURFACE_RETURN_TIME_IMMEDIATE, ChromeFeatureList.MAGIC_STACK_ANDROID})
-    @DisableFeatures(ChromeFeatureList.TAB_RESUMPTION_MODULE_ANDROID)
     public void testClickSingleTabCardCloseNtpHomeSurface() throws IOException {
         HomeSurfaceTestUtils.prepareTabStateMetadataFile(new int[] {0}, new String[] {TAB_URL}, 0);
         mActivityTestRule.startFromLauncher();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesLayoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesLayoutTest.java
index c023d5d..de15b557 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesLayoutTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedTilesLayoutTest.java
@@ -45,7 +45,10 @@
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.Features.DisableFeatures;
+import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.chrome.browser.app.ChromeActivity;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.night_mode.ChromeNightModeTestUtils;
@@ -144,19 +147,56 @@
     @MediumTest
     @Feature({"NewTabPage", "RenderTest"})
     @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
-    public void testTilesLayoutAppearance(boolean nightModeEnabled) throws Exception {
-        NewTabPage ntp = setUpFakeDataToShowOnNtp(FAKE_MOST_VISITED_URLS.length);
-        mRenderTestRule.render(getTilesLayout(ntp), "ntp_tile_layout");
+    @DisableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION})
+    public void testTilesLayoutAppearance_DisableMvtCustomization(boolean nightModeEnabled)
+            throws Exception {
+        doTilesLayoutAppearanceTest(nightModeEnabled, "");
     }
 
     @Test
     @MediumTest
     @Feature({"NewTabPage", "RenderTest"})
+    @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
+    @EnableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION})
+    public void testTilesLayoutAppearance_EnableMvtCustomization(boolean nightModeEnabled)
+            throws Exception {
+        doTilesLayoutAppearanceTest(nightModeEnabled, "_with_add_new_button");
+    }
+
+    private void doTilesLayoutAppearanceTest(boolean nightModeEnabled, String suffix)
+            throws Exception {
+        NewTabPage ntp = setUpFakeDataToShowOnNtp(FAKE_MOST_VISITED_URLS.length);
+        mRenderTestRule.render(getTilesLayout(ntp), "ntp_tile_layout" + suffix);
+    }
+
+    @Test
+    @MediumTest
+    @Feature({"NewTabPage", "RenderTest"})
+    @DisableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION})
     @DisableIf.Build(
             message = "Both variants are flaky on Nougat emulator, see crbug.com/1450693",
             supported_abis_includes = "x86",
             sdk_is_less_than = VERSION_CODES.O)
-    public void testModernTilesLayoutAppearance_Full() throws IOException, InterruptedException {
+    public void testModernTilesLayoutAppearance_Full_DisableMvtCustomization()
+            throws IOException, InterruptedException {
+        doModernTilesLayoutAppearanceTest_Full("");
+    }
+
+    @Test
+    @MediumTest
+    @Feature({"NewTabPage", "RenderTest"})
+    @EnableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION})
+    @DisableIf.Build(
+            message = "Both variants are flaky on Nougat emulator, see crbug.com/1450693",
+            supported_abis_includes = "x86",
+            sdk_is_less_than = VERSION_CODES.O)
+    public void testModernTilesLayoutAppearance_Full_EnableMvtCustomization()
+            throws IOException, InterruptedException {
+        doModernTilesLayoutAppearanceTest_Full("_with_add_new_button");
+    }
+
+    private void doModernTilesLayoutAppearanceTest_Full(String suffix)
+            throws IOException, InterruptedException {
         View tilesLayout = renderTiles(makeSuggestions(FAKE_MOST_VISITED_URLS.length));
 
         Activity activity = mActivityTestRule.getActivity();
@@ -167,7 +207,7 @@
                             activity.getResources().getConfiguration().orientation,
                             is(ORIENTATION_PORTRAIT));
                 });
-        mRenderTestRule.render(tilesLayout, "modern_tiles_layout_full_portrait");
+        mRenderTestRule.render(tilesLayout, "modern_tiles_layout_full_portrait" + suffix);
 
         activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
         CriteriaHelper.pollUiThread(
@@ -176,7 +216,7 @@
                             activity.getResources().getConfiguration().orientation,
                             is(ORIENTATION_LANDSCAPE));
                 });
-        mRenderTestRule.render(tilesLayout, "modern_tiles_layout_full_landscape");
+        mRenderTestRule.render(tilesLayout, "modern_tiles_layout_full_landscape" + suffix);
 
         // Reset device orientation.
         ActivityTestUtils.clearActivityOrientation(activity);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGroupUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGroupUnitTest.java
index e2024a54..35036ff 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGroupUnitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGroupUnitTest.java
@@ -28,6 +28,8 @@
 import android.graphics.Bitmap.Config;
 import android.graphics.Color;
 import android.view.ContextThemeWrapper;
+import android.view.View;
+import android.widget.TextView;
 
 import androidx.test.annotation.UiThreadTest;
 import androidx.test.filters.SmallTest;
@@ -46,6 +48,8 @@
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.DisabledTest;
+import org.chromium.base.test.util.Features.DisableFeatures;
+import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.native_page.ContextMenuManager;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
@@ -326,8 +330,22 @@
     @Test
     @UiThreadTest
     @SmallTest
+    @DisableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION})
     // If this flakes again, refer to https://crbug.com/1330627, https://crbug.com/1293208.
-    public void testRenderTileView() {
+    public void testRenderTileView_DisableMvtCustomization() {
+        doRenderTileViewTest();
+    }
+
+    @Test
+    @UiThreadTest
+    @SmallTest
+    @EnableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION})
+    // If this flakes again, refer to https://crbug.com/1330627, https://crbug.com/1293208.
+    public void testRenderTileView_EnableMvtCustomization() {
+        doRenderTileViewTest();
+    }
+
+    private void doRenderTileViewTest() {
         SuggestionsUiDelegate uiDelegate = mSuggestionsUiDelegate;
         when(uiDelegate.getImageFetcher()).thenReturn(mImageFetcher);
         TileGroup tileGroup =
@@ -348,9 +366,20 @@
 
         // Render them to the layout.
         refreshData(tileGroup, layout);
-        assertThat(layout.getChildCount(), is(2));
-        assertThat(((SuggestionsTileView) layout.getChildAt(0)).getUrl().getSpec(), is(URLS[0]));
-        assertThat(((SuggestionsTileView) layout.getChildAt(1)).getUrl().getSpec(), is(URLS[1]));
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION)) {
+            assertThat(layout.getChildCount(), is(3));
+            assertThat(
+                    ((SuggestionsTileView) layout.getChildAt(0)).getUrl().getSpec(), is(URLS[0]));
+            assertThat(
+                    ((SuggestionsTileView) layout.getChildAt(1)).getUrl().getSpec(), is(URLS[1]));
+            assertTrue(isAddNewButton(layout.getChildAt(2)));
+        } else {
+            assertThat(layout.getChildCount(), is(2));
+            assertThat(
+                    ((SuggestionsTileView) layout.getChildAt(0)).getUrl().getSpec(), is(URLS[0]));
+            assertThat(
+                    ((SuggestionsTileView) layout.getChildAt(1)).getUrl().getSpec(), is(URLS[1]));
+        }
         // Rerun to test SuggestionsTileView caching.
         refreshData(tileGroup, layout);
     }
@@ -386,8 +415,22 @@
     @Test
     @UiThreadTest
     @SmallTest
+    @DisableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION})
     // If this flakes again, refer to https://crbug.com/1286755.
-    public void testRenderTileViewReplacing() {
+    public void testRenderTileViewReplacing_DisableMvtCustomization() {
+        doRenderTileViewReplacingTest();
+    }
+
+    @Test
+    @UiThreadTest
+    @SmallTest
+    @EnableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION})
+    // If this flakes again, refer to https://crbug.com/1286755.
+    public void testRenderTileViewReplacing_EnableMvtCustomization() {
+        doRenderTileViewReplacingTest();
+    }
+
+    private void doRenderTileViewReplacingTest() {
         SuggestionsUiDelegate uiDelegate = mSuggestionsUiDelegate;
         when(uiDelegate.getImageFetcher()).thenReturn(mMockImageFetcher);
         TileGroup tileGroup =
@@ -412,9 +455,16 @@
 
         // The tiles should be updated, the old ones removed.
         refreshData(tileGroup, layout);
-        assertThat(layout.getChildCount(), is(2));
-        assertThat(layout.indexOfChild(view1), is(-1));
-        assertThat(layout.indexOfChild(view2), is(-1));
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION)) {
+            assertThat(layout.getChildCount(), is(3));
+            assertThat(layout.indexOfChild(view1), is(-1));
+            assertThat(layout.indexOfChild(view2), is(-1));
+            assertTrue(isAddNewButton(layout.getChildAt(2)));
+        } else {
+            assertThat(layout.getChildCount(), is(2));
+            assertThat(layout.indexOfChild(view1), is(-1));
+            assertThat(layout.indexOfChild(view2), is(-1));
+        }
         // Rerun to test SuggestionsTileView caching.
         refreshData(tileGroup, layout);
     }
@@ -605,6 +655,13 @@
         return tileGroup;
     }
 
+    private boolean isAddNewButton(View view) {
+        View tileView = view.findViewById(R.id.tile_view_title);
+        return tileView != null
+                && (tileView instanceof TextView)
+                && ((TextView) tileView).getText().toString().equals("Add new");
+    }
+
     private static class FakeImageFetcher extends ImageFetcher {
         private final List<LargeIconCallback> mCallbackList = new ArrayList<>();
 
diff --git a/chrome/android/junit/BUILD.gn b/chrome/android/junit/BUILD.gn
index 4b71e97..5e8bd97 100644
--- a/chrome/android/junit/BUILD.gn
+++ b/chrome/android/junit/BUILD.gn
@@ -551,7 +551,6 @@
       "src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinatorUnitTest.java",
       "src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripIphControllerUnitTest.java",
       "src/org/chromium/chrome/browser/compositor/overlays/strip/TabUsageTrackerTest.java",
-      "src/org/chromium/chrome/browser/compositor/overlays/strip/TooltipManagerUnitTest.java",
       "src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/ExternalViewDragDropReorderStrategyTest.java",
       "src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/GroupReorderStrategyTest.java",
       "src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/ReorderStrategyTestBase.java",
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManagerTest.java
index f04c3ad..7b1633b 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManagerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManagerTest.java
@@ -146,7 +146,6 @@
     @Mock private Tab mSelectedTab;
     @Mock private StripLayoutTab mHoveredStripTab;
     @Mock private ViewStub mTabHoverCardViewStub;
-    @Mock private ViewStub mTooltipViewStub;
     @Mock private ObservableSupplierImpl<TabContentManager> mTabContentManagerSupplier;
     @Mock private BrowserControlsStateProvider mBrowserControlStateProvider;
     @Mock private WindowAndroid mWindowAndroid;
@@ -237,7 +236,6 @@
                         mDragDropDelegate,
                         mToolbarContainerView,
                         mTabHoverCardViewStub,
-                        mTooltipViewStub,
                         mTabContentManagerSupplier,
                         mBrowserControlStateProvider,
                         mWindowAndroid,
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 dbeb528..77f9d75 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
@@ -93,6 +93,7 @@
 import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost;
 import org.chromium.chrome.browser.compositor.layouts.components.CompositorButton;
 import org.chromium.chrome.browser.compositor.layouts.components.CompositorButton.ButtonType;
+import org.chromium.chrome.browser.compositor.layouts.components.CompositorButton.TooltipHandler;
 import org.chromium.chrome.browser.compositor.layouts.components.TintedCompositorButton;
 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutView.StripLayoutViewOnClickHandler;
 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutView.StripLayoutViewOnKeyboardFocusHandler;
@@ -185,6 +186,7 @@
     @Mock private StripTabHoverCardView mTabHoverCardView;
     @Mock private Profile mProfile;
     @Mock private StripLayoutViewOnClickHandler mClickHandler;
+    @Mock private TooltipHandler mTooltipHandler;
     @Mock private StripLayoutViewOnKeyboardFocusHandler mKeyboardFocusHandler;
     @Mock private TabDragSource mTabDragSource;
     @Mock private WindowAndroid mWindowAndroid;
@@ -1443,6 +1445,7 @@
                         tab,
                         24.f,
                         24.f,
+                        mTooltipHandler,
                         mClickHandler,
                         mKeyboardFocusHandler,
                         R.drawable.btn_tab_close_normal,
@@ -1480,6 +1483,7 @@
                         tabs[0],
                         24.f,
                         24.f,
+                        mTooltipHandler,
                         mClickHandler,
                         mKeyboardFocusHandler,
                         R.drawable.btn_tab_close_normal,
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TooltipManagerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TooltipManagerUnitTest.java
deleted file mode 100644
index cc6238e57..0000000
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TooltipManagerUnitTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2025 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.compositor.overlays.strip;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.when;
-import static org.robolectric.Robolectric.buildActivity;
-
-import android.app.Activity;
-import android.content.Context;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-import org.robolectric.annotation.Config;
-
-import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.compositor.layouts.components.CompositorButton;
-
-/** Unit tests for {@link TooltipManager}. */
-@RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, qualifiers = "w640dp-h360dp")
-public class TooltipManagerUnitTest {
-
-    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
-
-    @Mock private CompositorButton mButton;
-
-    private TooltipManager mTooltipManager;
-    private FrameLayout mTooltipView;
-    private Context mContext;
-
-    @Before
-    public void setUp() {
-        Activity activity = buildActivity(Activity.class).setup().get();
-        activity.setTheme(R.style.Theme_BrowserUI_DayNight);
-        mTooltipView =
-                (FrameLayout)
-                        activity.getLayoutInflater()
-                                .inflate(R.layout.tab_strip_tooltip_holder, null);
-        mTooltipManager = new TooltipManager(mTooltipView, () -> 0f);
-
-        mContext = mTooltipView.getContext();
-        mContext.getResources().getDisplayMetrics().density = 1f;
-    }
-
-    @Test
-    public void showAndHide() {
-        when(mButton.getAccessibilityDescription()).thenReturn("The button description");
-        when(mButton.getDrawX()).thenReturn(100f);
-        when(mButton.getDrawY()).thenReturn(100f);
-        when(mButton.getWidth()).thenReturn(100f);
-        when(mButton.getHeight()).thenReturn(100f);
-
-        mTooltipManager.showImmediatelyFor(mButton);
-        assertEquals(
-                "|mTooltipView| should be visible.", View.VISIBLE, mTooltipView.getVisibility());
-
-        mTooltipManager.hideImmediately();
-        assertEquals("|mTooltipView| should be gone.", View.GONE, mTooltipView.getVisibility());
-    }
-
-    @Test
-    public void correctText() {
-        when(mButton.getAccessibilityDescription()).thenReturn("The button description");
-        when(mButton.getDrawX()).thenReturn(100f);
-        when(mButton.getDrawY()).thenReturn(100f);
-        when(mButton.getWidth()).thenReturn(100f);
-        when(mButton.getHeight()).thenReturn(100f);
-
-        mTooltipManager.showImmediatelyFor(mButton);
-
-        assertEquals(
-                "|mTooltipView| should be visible.", View.VISIBLE, mTooltipView.getVisibility());
-        assertEquals(
-                "Tooltip text is incorrect.",
-                mButton.getAccessibilityDescription(),
-                ((TextView) mTooltipView.findViewById(R.id.tooltip_label)).getText());
-    }
-
-    private void testCorrectPosition() {
-        assertEquals(
-                "|mTooltipView| should be visible.", View.VISIBLE, mTooltipView.getVisibility());
-        assertTrue(
-                "|mTooltipView| should not cross the left window border.",
-                mTooltipView.getX() >= 0f);
-        assertTrue(
-                "|mTooltipView| should not cross the right window border.",
-                mTooltipView.getX() + mTooltipView.getWidth() <= 640f);
-        assertTrue(
-                "|mTooltipView| should not cross the top window border.",
-                mTooltipView.getY() >= 0f);
-        assertTrue(
-                "|mTooltipView| should not cross the bottom window border.",
-                mTooltipView.getY() + mTooltipView.getHeight() <= 360f);
-    }
-
-    @Test
-    public void tooltipStaysInTheWindowLeftBound() {
-        when(mButton.getAccessibilityDescription()).thenReturn("A very long button description");
-        when(mButton.getDrawX()).thenReturn(0f);
-        when(mButton.getDrawY()).thenReturn(0f);
-        when(mButton.getWidth()).thenReturn(10f);
-        when(mButton.getHeight()).thenReturn(10f);
-
-        mTooltipManager.showImmediatelyFor(mButton);
-
-        testCorrectPosition();
-    }
-
-    @Test
-    public void tooltipStaysInTheWindowRightBound() {
-        when(mButton.getAccessibilityDescription()).thenReturn("A very long button description");
-        when(mButton.getDrawX()).thenReturn(630f);
-        when(mButton.getDrawY()).thenReturn(0f);
-        when(mButton.getWidth()).thenReturn(10f);
-        when(mButton.getHeight()).thenReturn(10f);
-
-        mTooltipManager.showImmediatelyFor(mButton);
-
-        testCorrectPosition();
-    }
-}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/scene_layer/TabStripSceneLayerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/scene_layer/TabStripSceneLayerTest.java
index 958e4f0..7bb57dc6 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/scene_layer/TabStripSceneLayerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/scene_layer/TabStripSceneLayerTest.java
@@ -42,6 +42,7 @@
 import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost;
 import org.chromium.chrome.browser.compositor.layouts.components.CompositorButton;
 import org.chromium.chrome.browser.compositor.layouts.components.CompositorButton.ButtonType;
+import org.chromium.chrome.browser.compositor.layouts.components.CompositorButton.TooltipHandler;
 import org.chromium.chrome.browser.compositor.layouts.components.TintedCompositorButton;
 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutGroupTitle;
 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelperManager;
@@ -63,6 +64,7 @@
     @Mock private ResourceManager mResourceManager;
     @Mock private LayerTitleCache mLayerTitleCache;
     @Mock private SceneLayer mSceneLayer;
+    @Mock private TooltipHandler mTooltipHandler;
     @Mock private StripLayoutViewOnClickHandler mOnClickHandler;
     @Mock private StripLayoutViewOnKeyboardFocusHandler mKeyboardFocusHandler;
     @Mock private TabLoadTrackerCallback mTabLoadTrackerCallback;
@@ -109,6 +111,7 @@
                         null,
                         32.f,
                         32.f,
+                        mTooltipHandler,
                         mOnClickHandler,
                         mKeyboardFocusHandler,
                         R.drawable.ic_incognito,
@@ -120,6 +123,7 @@
                         null,
                         32.f,
                         32.f,
+                        mTooltipHandler,
                         mOnClickHandler,
                         mKeyboardFocusHandler,
                         R.drawable.ic_new_tab_button,
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedMediatorUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedMediatorUnitTest.java
index e2768139..dc96589 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedMediatorUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/tile/MostVisitedMediatorUnitTest.java
@@ -37,7 +37,10 @@
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.Features.DisableFeatures;
+import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.native_page.ContextMenuManager;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -163,7 +166,18 @@
     }
 
     @Test
-    public void testMvtContainerOnTileCountChanged() {
+    @DisableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION})
+    public void testMvtContainerOnTileCountChanged_DisableMvtCustomization() {
+        doTestMvtContainerOnTileCountChanged();
+    }
+
+    @Test
+    @EnableFeatures({ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION})
+    public void testMvtContainerOnTileCountChanged_EndableMvtCustomization() {
+        doTestMvtContainerOnTileCountChanged();
+    }
+
+    private void doTestMvtContainerOnTileCountChanged() {
         ArrayList<SiteSuggestion> array = new ArrayList<>();
         array.add(mData);
         mMostVisitedSites.setTileSuggestions(array);
@@ -171,10 +185,16 @@
 
         Assert.assertTrue(mModel.get(IS_CONTAINER_VISIBLE));
 
-        // When there's no mv tile, the mv tiles container should be hidden.
         mMostVisitedSites.setTileSuggestions(new ArrayList<>());
         mMediator.onTileCountChanged();
-        Assert.assertFalse(mModel.get(IS_CONTAINER_VISIBLE));
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.MOST_VISITED_TILES_CUSTOMIZATION)) {
+            // When there's no mv tile, the mv tiles container should show (with the "Add new"
+            // button).
+            Assert.assertTrue(mModel.get(IS_CONTAINER_VISIBLE));
+        } else {
+            // When there's no mv tile, the mv tiles container should be hidden.
+            Assert.assertFalse(mModel.get(IS_CONTAINER_VISIBLE));
+        }
 
         // When there is mv tile, the mv tiles container should be shown.
         mMostVisitedSites.setTileSuggestions(JUnitTestGURLs.HTTP_URL.getSpec());
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserverTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserverTest.java
index 56195f1..8fbcc3d 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserverTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/BottomAttachedUiObserverTest.java
@@ -98,9 +98,7 @@
     @Mock private OverlayPanelStateProvider mOverlayPanelStateProvider;
 
     @Mock private BottomSheetController mBottomSheetController;
-    @Mock private BottomSheetContent mBottomSheetContentNullBackground;
-    @Mock private BottomSheetContent mBottomSheetContentYellowBackground;
-    @Mock private BottomSheetContent mBottomSheetContentCyanBackground;
+    @Mock private BottomSheetContent mSheetContent;
 
     @Mock private OmniboxSuggestionsVisualState mOmniboxSuggestionsVisualState;
 
@@ -123,11 +121,7 @@
         when(mContextualSearchManager.getOverlayPanelStateProviderSupplier())
                 .thenReturn(mOverlayPanelStateProviderSupplier);
 
-        when(mBottomSheetContentNullBackground.getBackgroundColor()).thenReturn(null);
-        when(mBottomSheetContentYellowBackground.getBackgroundColor())
-                .thenReturn(BOTTOM_SHEET_YELLOW);
-        when(mBottomSheetContentCyanBackground.getBackgroundColor()).thenReturn(BOTTOM_SHEET_CYAN);
-
+        doReturn(null).when(mBottomSheetController).getSheetBackgroundColor();
         when(mBottomSheetController.isFullWidth()).thenReturn(true);
         when(mSnackbarManager.isFullWidth()).thenReturn(true);
 
@@ -454,7 +448,8 @@
     public void testAdaptsColorToBottomSheet() {
         doReturn(false).when(mBottomSheetController).isAnchoredToBottomControls();
 
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentNullBackground);
+        doReturn(null).when(mBottomSheetController).getSheetBackgroundColor();
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mColorChangeObserver.assertState(null, false, false);
 
         mBottomAttachedUiObserver.onSheetOpened(0);
@@ -462,18 +457,21 @@
         mBottomAttachedUiObserver.onSheetClosed(0);
         mColorChangeObserver.assertState(null, false, false);
 
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentCyanBackground);
+        doReturn(BOTTOM_SHEET_CYAN).when(mBottomSheetController).getSheetBackgroundColor();
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mBottomAttachedUiObserver.onSheetOpened(0);
         mColorChangeObserver.assertState(BOTTOM_SHEET_CYAN, false, false);
         mBottomAttachedUiObserver.onSheetClosed(0);
         mColorChangeObserver.assertState(null, false, false);
 
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentYellowBackground);
+        doReturn(BOTTOM_SHEET_YELLOW).when(mBottomSheetController).getSheetBackgroundColor();
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mColorChangeObserver.assertState(null, false, false);
 
         mBottomAttachedUiObserver.onSheetOpened(0);
         mColorChangeObserver.assertState(BOTTOM_SHEET_YELLOW, false, false);
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentCyanBackground);
+        doReturn(BOTTOM_SHEET_CYAN).when(mBottomSheetController).getSheetBackgroundColor();
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mColorChangeObserver.assertState(BOTTOM_SHEET_CYAN, false, false);
         mBottomAttachedUiObserver.onSheetClosed(0);
         mColorChangeObserver.assertState(null, false, false);
@@ -485,7 +483,8 @@
         when(mBottomSheetController.isFullWidth()).thenReturn(false, false);
         when(mBottomControlsStacker.isLayerVisible(eq(LayerType.BOTTOM_CHIN))).thenReturn(false);
 
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentYellowBackground);
+        doReturn(BOTTOM_SHEET_YELLOW).when(mBottomSheetController).getSheetBackgroundColor();
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mColorChangeObserver.assertState(null, false, false);
 
         mBottomAttachedUiObserver.onSheetOpened(0);
@@ -500,7 +499,8 @@
         when(mBottomSheetController.isFullWidth()).thenReturn(false, false);
         when(mBottomControlsStacker.isLayerVisible(eq(LayerType.BOTTOM_CHIN))).thenReturn(true);
 
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentYellowBackground);
+        doReturn(BOTTOM_SHEET_YELLOW).when(mBottomSheetController).getSheetBackgroundColor();
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mColorChangeObserver.assertState(null, false, false);
 
         mBottomAttachedUiObserver.onSheetOpened(0);
@@ -515,7 +515,8 @@
         when(mBottomSheetController.isFullWidth()).thenReturn(false);
         when(mBottomControlsStacker.isLayerVisible(eq(LayerType.BOTTOM_CHIN))).thenReturn(false);
 
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentYellowBackground);
+        doReturn(BOTTOM_SHEET_YELLOW).when(mBottomSheetController).getSheetBackgroundColor();
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mColorChangeObserver.assertState(null, false, false);
 
         mBottomAttachedUiObserver.onSheetOpened(0);
@@ -532,7 +533,8 @@
         when(mBottomControlsStacker.hasVisibleLayersOtherThan(eq(LayerType.BOTTOM_CHIN)))
                 .thenReturn(false);
 
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentYellowBackground);
+        doReturn(BOTTOM_SHEET_YELLOW).when(mBottomSheetController).getSheetBackgroundColor();
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mColorChangeObserver.assertColor(null).assertForceShowDivider(false);
 
         mBottomAttachedUiObserver.onSheetOpened(0);
@@ -549,7 +551,8 @@
         when(mBottomControlsStacker.hasVisibleLayersOtherThan(eq(LayerType.BOTTOM_CHIN)))
                 .thenReturn(false);
 
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentYellowBackground);
+        doReturn(BOTTOM_SHEET_YELLOW).when(mBottomSheetController).getSheetBackgroundColor();
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mColorChangeObserver.assertColor(null).assertForceShowDivider(false);
 
         mBottomAttachedUiObserver.onSheetOpened(0);
@@ -566,7 +569,8 @@
         when(mBottomControlsStacker.hasVisibleLayersOtherThan(eq(LayerType.BOTTOM_CHIN)))
                 .thenReturn(true);
 
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentYellowBackground);
+        doReturn(BOTTOM_SHEET_YELLOW).when(mBottomSheetController).getSheetBackgroundColor();
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mColorChangeObserver.assertColor(null).assertForceShowDivider(false);
 
         mBottomAttachedUiObserver.onSheetOpened(0);
@@ -583,7 +587,8 @@
         when(mBottomControlsStacker.hasVisibleLayersOtherThan(eq(LayerType.BOTTOM_CHIN)))
                 .thenReturn(false);
 
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentYellowBackground);
+        doReturn(BOTTOM_SHEET_YELLOW).when(mBottomSheetController).getSheetBackgroundColor();
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mColorChangeObserver.assertColor(null).assertForceShowDivider(false);
 
         mBottomAttachedUiObserver.onSheetOpened(0);
@@ -600,7 +605,8 @@
         when(mBottomControlsStacker.hasVisibleLayersOtherThan(eq(LayerType.BOTTOM_CHIN)))
                 .thenReturn(false);
 
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentYellowBackground);
+        doReturn(BOTTOM_SHEET_YELLOW).when(mBottomSheetController).getSheetBackgroundColor();
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mColorChangeObserver.assertColor(null).assertForceShowDivider(false);
 
         mBottomAttachedUiObserver.onSheetOpened(0);
@@ -617,7 +623,8 @@
         when(mBottomControlsStacker.hasVisibleLayersOtherThan(eq(LayerType.BOTTOM_CHIN)))
                 .thenReturn(true);
 
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentYellowBackground);
+        doReturn(BOTTOM_SHEET_YELLOW).when(mBottomSheetController).getSheetBackgroundColor();
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mColorChangeObserver.assertColor(null).assertForceShowDivider(false);
 
         mBottomAttachedUiObserver.onSheetOpened(0);
@@ -742,7 +749,8 @@
         mColorChangeObserver.assertState(OVERLAY_PANEL_COLOR, false, false);
 
         // Show bottom sheet.
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentYellowBackground);
+        doReturn(BOTTOM_SHEET_YELLOW).when(mBottomSheetController).getSheetBackgroundColor();
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mBottomAttachedUiObserver.onSheetOpened(0);
         mColorChangeObserver.assertState(BOTTOM_SHEET_YELLOW, false, false);
 
@@ -806,13 +814,15 @@
         mBottomAttachedUiObserver.onOverlayPanelStateChanged(
                 OverlayPanel.PanelState.PEEKED, OVERLAY_PANEL_COLOR);
 
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentYellowBackground);
+        doReturn(BOTTOM_SHEET_YELLOW).when(mBottomSheetController).getSheetBackgroundColor();
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mBottomAttachedUiObserver.onSheetOpened(0);
         mColorChangeObserver.assertState(BROWSER_CONTROLS_COLOR, false, false);
 
         doReturn(1.0f).when(mBrowserControlsStateProvider).getBrowserControlHiddenRatio();
 
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentYellowBackground);
+        doReturn(BOTTOM_SHEET_YELLOW).when(mBottomSheetController).getSheetBackgroundColor();
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mBottomAttachedUiObserver.onSheetOpened(0);
         mColorChangeObserver.assertState(BOTTOM_SHEET_YELLOW, false, false);
 
@@ -868,7 +878,7 @@
     })
     @DisableFeatures({ChromeFeatureList.EDGE_TO_EDGE_BOTTOM_CHIN})
     public void testNavBarColorAnimationsBottomSheet() {
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentNullBackground);
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mColorChangeObserver.assertState(null, false, false);
 
         mBottomAttachedUiObserver.onSheetOpened(0);
@@ -876,7 +886,8 @@
         mBottomAttachedUiObserver.onSheetClosed(0);
         mColorChangeObserver.assertState(null, false, false);
 
-        mBottomAttachedUiObserver.onSheetContentChanged(mBottomSheetContentCyanBackground);
+        doReturn(BOTTOM_SHEET_CYAN).when(mBottomSheetController).getSheetBackgroundColor();
+        mBottomAttachedUiObserver.onSheetContentChanged(mSheetContent);
         mBottomAttachedUiObserver.onSheetOpened(0);
         // Nav bar color animations disabled on appearance.
         mColorChangeObserver.assertState(BOTTOM_SHEET_CYAN, false, true);
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 10ff525..af31e4e 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3769,26 +3769,6 @@
         {" - all windowing modes", kAuxiliaryNavigationStaysInBrowserOn,
          std::size(kAuxiliaryNavigationStaysInBrowserOn), nullptr}};
 
-const FeatureEntry::FeatureParam kShowNewTabAnimationsBounce[] = {
-    {"version", "1"}};
-const FeatureEntry::FeatureParam kShowNewTabAnimationsDecelerate[] = {
-    {"version", "2"}};
-const FeatureEntry::FeatureParam kShowNewTabAnimationsBounceDecelerate[] = {
-    {"version", "3"}};
-const FeatureEntry::FeatureParam kShowNewTabAnimationsM137[] = {
-    {"version", "0"}};
-const FeatureEntry::FeatureVariation kShowNewTabAnimationsVariations[] = {
-    {"- Bouncy GTS icon with delay", kShowNewTabAnimationsBounce,
-     std::size(kShowNewTabAnimationsBounce), nullptr},
-    {"- Bouncy GTS icon with decelerate arc",
-     kShowNewTabAnimationsBounceDecelerate,
-     std::size(kShowNewTabAnimationsBounceDecelerate), nullptr},
-    {"- Decelerate arc", kShowNewTabAnimationsDecelerate,
-     std::size(kShowNewTabAnimationsDecelerate), nullptr},
-    {"- M137 with new duration", kShowNewTabAnimationsM137,
-     std::size(kShowNewTabAnimationsM137), nullptr},
-};
-
 #endif  // BUILDFLAG(IS_ANDROID)
 
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || \
@@ -4245,25 +4225,6 @@
     {"with password manager heuristics", kSensitiveContentUsePwmHeuristics,
      std::size(kSensitiveContentUsePwmHeuristics), nullptr},
 };
-
-const FeatureEntry::FeatureParam kAndroidHubEnableBookmarks[] = {
-    {"enable_bookmark_provider", "true"}};
-const FeatureEntry::FeatureParam kAndroidHubEnableHistory[] = {
-    {"enable_history_provider", "true"}};
-const FeatureEntry::FeatureParam kAndroidHubEnableAllExtraProviders[] = {
-    {"enable_bookmark_provider", "true"},
-    {"enable_history_provider", "true"}};
-const FeatureEntry::FeatureParam kAndroidHubEnableEnterToSearch[] = {
-    {"enable_press_enter_to_search", "true"}};
-const FeatureEntry::FeatureVariation kAndroidHubSearchVariations[] = {
-    {"with bookmarks", kAndroidHubEnableBookmarks,
-     std::size(kAndroidHubEnableBookmarks), nullptr},
-    {"with history", kAndroidHubEnableHistory,
-     std::size(kAndroidHubEnableHistory), nullptr},
-    {"with all extra providers", kAndroidHubEnableAllExtraProviders,
-     std::size(kAndroidHubEnableAllExtraProviders), nullptr},
-    {"with pressing enter to search", kAndroidHubEnableEnterToSearch,
-     std::size(kAndroidHubEnableEnterToSearch), nullptr}};
 #endif  // BUILDFLAG(IS_ANDROID)
 
 // Feature variations for kSubframeProcessReuseThresholds.
@@ -6762,8 +6723,7 @@
 
     {"omnibox-show-popup-on-mouse-released",
      flag_descriptions::kOmniboxShowPopupOnMouseReleasedName,
-     flag_descriptions::kOmniboxShowPopupOnMouseReleasedDescription,
-     kOsDesktop,
+     flag_descriptions::kOmniboxShowPopupOnMouseReleasedDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(omnibox::kShowPopupOnMouseReleased)},
 
     {"omnibox-hide-suggestion-group-headers",
@@ -7685,9 +7645,7 @@
 
     {"show-new-tab-animations", flag_descriptions::kShowNewTabAnimationsName,
      flag_descriptions::kShowNewTabAnimationsDescription, kOsAndroid,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(chrome::android::kShowNewTabAnimations,
-                                    kShowNewTabAnimationsVariations,
-                                    "ShowNewTabAnimations")},
+     FEATURE_VALUE_TYPE(chrome::android::kShowNewTabAnimations)},
 
     {"tab-switcher-color-blend-animate",
      flag_descriptions::kTabSwitcherColorBlendAnimateName,
@@ -10577,11 +10535,6 @@
      FEATURE_VALUE_TYPE(blink::features::kObservableAPI)},
 
 #if BUILDFLAG(IS_ANDROID)
-    {"android-hub-search", flag_descriptions::kAndroidHubSearchName,
-     flag_descriptions::kAndroidHubSearchDescription, kOsAndroid,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(omnibox::kAndroidHubSearch,
-                                    kAndroidHubSearchVariations,
-                                    "AndroidHubSearch")},
     {"android-hub-search-tab-groups",
      flag_descriptions::kAndroidHubSearchTabGroupsName,
      flag_descriptions::kAndroidHubSearchTabGroupsDescription, kOsAndroid,
diff --git a/chrome/browser/ash/arc/screen_capture/arc_screen_capture_bridge.cc b/chrome/browser/ash/arc/screen_capture/arc_screen_capture_bridge.cc
index 25358420..ad6e500a 100644
--- a/chrome/browser/ash/arc/screen_capture/arc_screen_capture_bridge.cc
+++ b/chrome/browser/ash/arc/screen_capture/arc_screen_capture_bridge.cc
@@ -13,11 +13,13 @@
 #include "base/memory/singleton.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/system/sys_info.h"
+#include "base/types/expected.h"
 #include "chrome/browser/ash/arc/screen_capture/arc_screen_capture_session.h"
 #include "chrome/browser/media/webrtc/desktop_media_list_ash.h"
 #include "chromeos/ash/experiences/arc/arc_browser_context_keyed_service_factory_base.h"
 #include "chromeos/ash/experiences/arc/session/arc_bridge_service.h"
 #include "content/public/browser/browser_thread.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 #include "ui/base/mojom/ui_base_types.mojom-shared.h"
 
 namespace {
@@ -124,18 +126,24 @@
 
 void ArcScreenCaptureBridge::PermissionPromptCallback(
     const std::string& package_name,
-    content::DesktopMediaID desktop_id) {
+    base::expected<content::DesktopMediaID,
+                   blink::mojom::MediaStreamRequestResult> result) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
   auto found = pending_permissions_map_.find(package_name);
   if (found == pending_permissions_map_.end()) {
     // This is normal if the dialog was accepted from testing.
     return;
   }
-  if (desktop_id.is_null()) {
+
+  if (!result.has_value() || result.value().is_null()) {
     std::move(found->second.callback).Run(false);
     pending_permissions_map_.erase(found);
     return;
   }
+
+  const content::DesktopMediaID desktop_id = result.value();
+
   // Remove any existing entry since emplace will not overwrite it.
   // This is OK since these persist forever and this may be requested again with
   // a different desktop.
diff --git a/chrome/browser/ash/arc/screen_capture/arc_screen_capture_bridge.h b/chrome/browser/ash/arc/screen_capture/arc_screen_capture_bridge.h
index 739259ff..7104bdc 100644
--- a/chrome/browser/ash/arc/screen_capture/arc_screen_capture_bridge.h
+++ b/chrome/browser/ash/arc/screen_capture/arc_screen_capture_bridge.h
@@ -10,10 +10,12 @@
 #include <unordered_map>
 
 #include "base/memory/raw_ptr.h"
+#include "base/types/expected.h"
 #include "chrome/browser/media/webrtc/desktop_media_picker.h"
 #include "chromeos/ash/experiences/arc/mojom/screen_capture.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "content/public/browser/desktop_media_id.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 
 namespace content {
 class BrowserContext;
@@ -75,8 +77,10 @@
     const bool enable_notification;
   };
 
-  void PermissionPromptCallback(const std::string& package_name,
-                                content::DesktopMediaID desktop_id);
+  void PermissionPromptCallback(
+      const std::string& package_name,
+      base::expected<content::DesktopMediaID,
+                     blink::mojom::MediaStreamRequestResult> result);
 
   const raw_ptr<ArcBridgeService>
       arc_bridge_service_;  // Owned by ArcServiceManager.
diff --git a/chrome/browser/ash/browser_delegate/browser_controller_impl.cc b/chrome/browser/ash/browser_delegate/browser_controller_impl.cc
index 78aad1f..1dd05f2 100644
--- a/chrome/browser/ash/browser_delegate/browser_controller_impl.cc
+++ b/chrome/browser/ash/browser_delegate/browser_controller_impl.cc
@@ -70,7 +70,7 @@
 
 BrowserDelegate* BrowserControllerImpl::GetLastUsedVisibleBrowser() {
   for (Browser* browser : BrowserList::GetInstance()->OrderedByActivation()) {
-    if (browser->window()->GetNativeWindow()->IsVisible()) {
+    if (browser->window()->IsVisible()) {
       return GetDelegate(browser);
     }
   }
diff --git a/chrome/browser/chromeos/app_mode/BUILD.gn b/chrome/browser/chromeos/app_mode/BUILD.gn
index 31c5af8..6aae5e0 100644
--- a/chrome/browser/chromeos/app_mode/BUILD.gn
+++ b/chrome/browser/chromeos/app_mode/BUILD.gn
@@ -54,6 +54,7 @@
     "//base",
     "//build:buildflag_header_h",
     "//chrome/browser:browser_public_dependencies",
+    "//chrome/browser/apps/app_service/publishers/proto",
     "//chrome/browser/profiles:profile",
     "//chrome/browser/ui:browser_list",
     "//chrome/browser/web_applications",
diff --git a/chrome/browser/component_updater/iwa_key_distribution_component_installer.cc b/chrome/browser/component_updater/iwa_key_distribution_component_installer.cc
index 5b75c09..05a77f9 100644
--- a/chrome/browser/component_updater/iwa_key_distribution_component_installer.cc
+++ b/chrome/browser/component_updater/iwa_key_distribution_component_installer.cc
@@ -163,10 +163,6 @@
           << " in " << install_dir;
   web_app::IwaKeyDistributionInfoProvider& info_provider =
       CHECK_DEREF(web_app::IwaKeyDistributionInfoProvider::GetInstance());
-  if (IsOnDemandUpdateSupported()) {
-    info_provider.SetUp(base::BindRepeating(
-        &IwaKeyDistributionComponentInstallerPolicy::QueueOnDemandUpdate));
-  }
   info_provider.LoadKeyDistributionData(
       version, install_dir.Append(kDataFileName),
       /*is_preloaded=*/manifest.FindBool(kPreloadedKey).value_or(false));
@@ -205,6 +201,14 @@
     return;
   }
 
+  // `RegisterIwaKeyDistributionComponent` is effectively called before the user
+  // profile is created. Hence we can avoid eventual initialization race
+  // conditions for user sessions.
+  web_app::IwaKeyDistributionInfoProvider::GetInstance()->SetUp(
+      IsOnDemandUpdateSupported(),
+      base::BindRepeating(
+          &IwaKeyDistributionComponentInstallerPolicy::QueueOnDemandUpdate));
+
   base::MakeRefCounted<ComponentInstaller>(
       std::make_unique<IwaKeyDistributionComponentInstallerPolicy>())
       ->Register(cus, base::DoNothing());
diff --git a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabSheetContent.java b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabSheetContent.java
index 5f907175..cfde892 100644
--- a/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabSheetContent.java
+++ b/chrome/browser/creator/android/java/src/org/chromium/chrome/browser/creator/CreatorTabSheetContent.java
@@ -278,8 +278,8 @@
     }
 
     @Override
-    public @Nullable Integer getBackgroundColor() {
-        return null;
+    public boolean hasSolidBackgroundColor() {
+        return false;
     }
 
     @Override
diff --git a/chrome/browser/device/android/java/src/org/chromium/chrome/browser/device/DeviceClassManager.java b/chrome/browser/device/android/java/src/org/chromium/chrome/browser/device/DeviceClassManager.java
index aca3e756..e87e09d 100644
--- a/chrome/browser/device/android/java/src/org/chromium/chrome/browser/device/DeviceClassManager.java
+++ b/chrome/browser/device/android/java/src/org/chromium/chrome/browser/device/DeviceClassManager.java
@@ -9,6 +9,7 @@
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.ui.util.XrUtils;
 
 /**
  * This class is used to turn on and off certain features for different types of
@@ -53,7 +54,10 @@
 
         // Flag based configurations.
         CommandLine commandLine = CommandLine.getInstance();
-        mEnableFullscreen = !commandLine.hasSwitch(ChromeSwitches.DISABLE_FULLSCREEN);
+        // To provide a desktop like behavior on an immersive XR device the full screen mode is
+        // disabled on the browser. It is also not controlled by the command line argument.
+        mEnableFullscreen =
+                !XrUtils.isXrDevice() && !commandLine.hasSwitch(ChromeSwitches.DISABLE_FULLSCREEN);
     }
 
     /**
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 4310de0..86dd994 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -529,6 +529,8 @@
       "api/identity/identity_unimplemented_functions_android.cc",
       "api/identity/identity_unimplemented_functions_android.h",
       "api/management/chrome_management_api_delegate_android.cc",
+      "api/tabs/tabs_api_stub.cc",
+      "api/tabs/tabs_api_stub.h",
       "extension_disabled_ui_android.cc",
       "extension_error_ui_android.cc",
       "extension_error_ui_android.h",
diff --git a/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc b/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc
index e49015b..25b2cd9 100644
--- a/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc
+++ b/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc
@@ -9,6 +9,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/types/expected.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h"
@@ -25,6 +26,7 @@
 #include "extensions/test/test_extension_dir.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_capture_types.h"
 #include "ui/base/ozone_buildflags.h"
 
@@ -32,10 +34,11 @@
 
 namespace {
 
-using content::DesktopMediaID;
-using content::WebContentsMediaCaptureId;
-using testing::Combine;
-using testing::Values;
+using ::blink::mojom::MediaStreamRequestResult;
+using ::content::DesktopMediaID;
+using ::content::WebContentsMediaCaptureId;
+using ::testing::Combine;
+using ::testing::Values;
 
 class DesktopCaptureApiTest : public ExtensionApiTest {
  public:
@@ -86,78 +89,86 @@
   // Each element in the following array corresponds to one test in
   // chrome/test/data/extensions/api_test/desktop_capture/test.js .
   FakeDesktopMediaPickerFactory::TestFlags test_flags[] = {
-    // pickerUiCanceled()
-    {.expect_screens = true, .expect_windows = true},
-    // chooseMedia()
-    {.expect_screens = true,
-     .expect_windows = true,
-     .selected_source =
-         DesktopMediaID(DesktopMediaID::TYPE_SCREEN, DesktopMediaID::kNullId)},
-    // screensOnly()
-    {.expect_screens = true},
-    // WindowsOnly()
-    {.expect_windows = true},
-    // tabOnly()
-    {.expect_tabs = true},
-    // audioShareNoApproval()
-    {.expect_screens = true,
-     .expect_windows = true,
-     .expect_tabs = true,
-     .expect_audio = true,
-     .selected_source =
-         DesktopMediaID(DesktopMediaID::TYPE_WEB_CONTENTS, 123, false)},
-    // audioShareApproval()
-    {.expect_screens = true,
-     .expect_windows = true,
-     .expect_tabs = true,
-     .expect_audio = true,
-     .selected_source =
-         DesktopMediaID(DesktopMediaID::TYPE_WEB_CONTENTS, 123, true)},
-    // chooseMediaAndGetStream()
-    {.expect_screens = true,
-     .expect_windows = true,
-     .selected_source = DesktopMediaID(DesktopMediaID::TYPE_SCREEN,
+      // pickerUiCanceled()
+      {.expect_screens = true,
+       .expect_windows = true,
+       .picker_result = base::unexpected(
+           MediaStreamRequestResult::PERMISSION_DENIED_BY_USER)},
+      // chooseMedia()
+      {.expect_screens = true,
+       .expect_windows = true,
+       .picker_result = DesktopMediaID(DesktopMediaID::TYPE_SCREEN,
+                                       DesktopMediaID::kNullId)},
+      // screensOnly()
+      {.expect_screens = true,
+       .picker_result = DesktopMediaID(DesktopMediaID::TYPE_SCREEN,
+                                       DesktopMediaID::kNullId)},
+      // WindowsOnly()
+      {.expect_windows = true,
+       .picker_result = DesktopMediaID(DesktopMediaID::TYPE_WINDOW,
+                                       DesktopMediaID::kFakeId)},
+      // tabOnly()
+      {.expect_tabs = true,
+       .picker_result = DesktopMediaID(DesktopMediaID::TYPE_WEB_CONTENTS, 123)},
+      // audioShareNoApproval()
+      {.expect_screens = true,
+       .expect_windows = true,
+       .expect_tabs = true,
+       .expect_audio = true,
+       .picker_result =
+           DesktopMediaID(DesktopMediaID::TYPE_WEB_CONTENTS, 123, false)},
+      // audioShareApproval()
+      {.expect_screens = true,
+       .expect_windows = true,
+       .expect_tabs = true,
+       .expect_audio = true,
+       .picker_result =
+           DesktopMediaID(DesktopMediaID::TYPE_WEB_CONTENTS, 123, true)},
+      // chooseMediaAndGetStream()
+      {.expect_screens = true,
+       .expect_windows = true,
+       .picker_result = DesktopMediaID(DesktopMediaID::TYPE_SCREEN,
                                        webrtc::kFullDesktopScreenId)},
-    // chooseMediaAndTryGetStreamWithInvalidId()
-    {.expect_screens = true,
-     .expect_windows = true,
-     .selected_source = DesktopMediaID(DesktopMediaID::TYPE_SCREEN,
+      // chooseMediaAndTryGetStreamWithInvalidId()
+      {.expect_screens = true,
+       .expect_windows = true,
+       .picker_result = DesktopMediaID(DesktopMediaID::TYPE_SCREEN,
                                        webrtc::kFullDesktopScreenId)},
-    // cancelDialog()
-    {.expect_screens = true, .expect_windows = true, .cancelled = true},
+      // cancelDialog()
+      {.expect_screens = true, .expect_windows = true, .cancelled = true},
   // TODO(crbug.com/41366624): Test fails; invalid device IDs being generated.
 #if 0
       // tabShareWithAudioPermissionGetStream()
       {.expect_tabs = true,
        .expect_audio = true,
-       .selected_source = MakeFakeWebContentsMediaId(true)},
+       .picker_result = MakeFakeWebContentsMediaId(true)},
 #endif
-    // windowShareWithAudioGetStream()
-    {.expect_windows = true,
-     .expect_audio = true,
-     .selected_source = DesktopMediaID(DesktopMediaID::TYPE_WINDOW,
+      // windowShareWithAudioGetStream()
+      {.expect_windows = true,
+       .expect_audio = true,
+       .picker_result = DesktopMediaID(DesktopMediaID::TYPE_WINDOW,
                                        DesktopMediaID::kFakeId, true)},
-    // screenShareWithAudioGetStream()
-    {.expect_screens = true,
-     .expect_audio = true,
-     .selected_source = DesktopMediaID(DesktopMediaID::TYPE_SCREEN,
+      // screenShareWithAudioGetStream()
+      {.expect_screens = true,
+       .expect_audio = true,
+       .picker_result = DesktopMediaID(DesktopMediaID::TYPE_SCREEN,
                                        webrtc::kFullDesktopScreenId, true)},
   // TODO(crbug.com/41366624): Test fails; invalid device IDs being generated.
 #if 0
       // tabShareWithoutAudioPermissionGetStream()
       {.expect_tabs = true,
        .expect_audio = true,
-       .selected_source = MakeFakeWebContentsMediaId(false)},
+       .picker_result = MakeFakeWebContentsMediaId(false)},
 #endif
-    // windowShareWithoutAudioGetStream()
-    {.expect_windows = true,
-     .expect_audio = true,
-     .selected_source =
-         DesktopMediaID(DesktopMediaID::TYPE_WINDOW, DesktopMediaID::kFakeId)},
-    // screenShareWithoutAudioGetStream()
-    {.expect_screens = true,
-     .expect_audio = true,
-     .selected_source = DesktopMediaID(DesktopMediaID::TYPE_SCREEN,
+      // windowShareWithoutAudioGetStream()
+      {.expect_windows = true,
+       .expect_audio = true,
+       .picker_result = DesktopMediaID(DesktopMediaID::TYPE_WINDOW,
+                                       DesktopMediaID::kFakeId)},
+      // screenShareWithoutAudioGetStream()
+      {.expect_screens = true,
+       .expect_audio = true,
+       .picker_result = DesktopMediaID(DesktopMediaID::TYPE_SCREEN,
                                        webrtc::kFullDesktopScreenId)},
   };
   picker_factory_.SetTestFlags(test_flags, std::size(test_flags));
@@ -191,15 +202,15 @@
   FakeDesktopMediaPickerFactory::TestFlags test_flags[] = {
       {.expect_screens = true,
        .expect_windows = true,
-       .selected_source = DesktopMediaID(DesktopMediaID::TYPE_SCREEN,
-                                         webrtc::kFullDesktopScreenId)},
+       .picker_result = DesktopMediaID(DesktopMediaID::TYPE_SCREEN,
+                                       webrtc::kFullDesktopScreenId)},
       {.expect_screens = true,
        .expect_windows = true,
-       .selected_source = DesktopMediaID(DesktopMediaID::TYPE_SCREEN,
-                                         DesktopMediaID::kNullId)},
+       .picker_result = DesktopMediaID(DesktopMediaID::TYPE_SCREEN,
+                                       DesktopMediaID::kNullId)},
       {.expect_screens = true,
        .expect_windows = true,
-       .selected_source =
+       .picker_result =
            DesktopMediaID(DesktopMediaID::TYPE_SCREEN, DesktopMediaID::kNullId),
        .cancelled = true},
   };
@@ -308,8 +319,7 @@
       browser(), GetURLForPath("localhost", "/test_file.html")));
 
   FakeDesktopMediaPickerFactory::TestFlags test_flags[] = {
-      {.expect_tabs = true,
-       .selected_source = MakeFakeWebContentsMediaId(true)},
+      {.expect_tabs = true, .picker_result = MakeFakeWebContentsMediaId(true)},
   };
   picker_factory_.SetTestFlags(test_flags, std::size(test_flags));
 
diff --git a/chrome/browser/extensions/api/tabs/tabs_api_stub.cc b/chrome/browser/extensions/api/tabs/tabs_api_stub.cc
new file mode 100644
index 0000000..933be8c
--- /dev/null
+++ b/chrome/browser/extensions/api/tabs/tabs_api_stub.cc
@@ -0,0 +1,306 @@
+// Copyright 2025 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/extensions/api/tabs/tabs_api_stub.h"
+
+#include "base/notimplemented.h"
+#include "base/values.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/ui/android/tab_model/tab_model.h"
+#include "chrome/browser/ui/android/tab_model/tab_model_list.h"
+#include "url/gurl.h"
+
+namespace extensions {
+
+namespace windows = api::windows;
+namespace tabs = api::tabs;
+
+namespace {
+
+constexpr char kNotImplemented[] = "Not implemented";
+
+}  // namespace
+
+// Windows ---------------------------------------------------------------------
+
+ExtensionFunction::ResponseAction WindowsGetFunction::Run() {
+  std::optional<windows::Get::Params> params =
+      windows::Get::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction WindowsGetCurrentFunction::Run() {
+  std::optional<windows::GetCurrent::Params> params =
+      windows::GetCurrent::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction WindowsGetLastFocusedFunction::Run() {
+  std::optional<windows::GetLastFocused::Params> params =
+      windows::GetLastFocused::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction WindowsGetAllFunction::Run() {
+  std::optional<windows::GetAll::Params> params =
+      windows::GetAll::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction WindowsCreateFunction::Run() {
+  std::optional<windows::Create::Params> params =
+      windows::Create::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction WindowsUpdateFunction::Run() {
+  std::optional<windows::Update::Params> params =
+      windows::Update::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction WindowsRemoveFunction::Run() {
+  std::optional<windows::Remove::Params> params =
+      windows::Remove::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+// Tabs ------------------------------------------------------------------------
+
+ExtensionFunction::ResponseAction TabsGetSelectedFunction::Run() {
+  std::optional<tabs::GetSelected::Params> params =
+      tabs::GetSelected::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction TabsGetAllInWindowFunction::Run() {
+  std::optional<tabs::GetAllInWindow::Params> params =
+      tabs::GetAllInWindow::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction TabsQueryFunction::Run() {
+  std::optional<tabs::Query::Params> params =
+      tabs::Query::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  NOTIMPLEMENTED() << "Using stub implementation and returning active tab";
+  base::Value::List result;
+  api::tabs::Tab tab_object;
+  // Always return the active tab in the current window.
+  for (TabModel* tab_model : TabModelList::models()) {
+    if (!tab_model->IsActiveModel()) {
+      continue;
+    }
+    auto* web_contents = tab_model->GetActiveWebContents();
+    if (!web_contents) {
+      continue;
+    }
+    tab_object.id = ExtensionTabUtil::GetTabId(web_contents);
+    result.Append(tab_object.ToValue());
+    return RespondNow(WithArguments(std::move(result)));
+  }
+  return RespondNow(Error("No active tab"));
+}
+
+ExtensionFunction::ResponseAction TabsCreateFunction::Run() {
+  std::optional<tabs::Create::Params> params =
+      tabs::Create::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction TabsDuplicateFunction::Run() {
+  std::optional<tabs::Duplicate::Params> params =
+      tabs::Duplicate::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction TabsGetFunction::Run() {
+  std::optional<tabs::Get::Params> params = tabs::Get::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction TabsGetCurrentFunction::Run() {
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction TabsHighlightFunction::Run() {
+  std::optional<tabs::Highlight::Params> params =
+      tabs::Highlight::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+TabsUpdateFunction::TabsUpdateFunction() = default;
+
+ExtensionFunction::ResponseAction TabsUpdateFunction::Run() {
+  std::optional<tabs::Update::Params> params =
+      tabs::Update::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction TabsMoveFunction::Run() {
+  std::optional<tabs::Move::Params> params = tabs::Move::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction TabsReloadFunction::Run() {
+  std::optional<tabs::Reload::Params> params =
+      tabs::Reload::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+TabsRemoveFunction::TabsRemoveFunction() = default;
+
+ExtensionFunction::ResponseAction TabsRemoveFunction::Run() {
+  std::optional<tabs::Remove::Params> params =
+      tabs::Remove::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction TabsGroupFunction::Run() {
+  std::optional<tabs::Group::Params> params =
+      tabs::Group::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction TabsUngroupFunction::Run() {
+  std::optional<tabs::Ungroup::Params> params =
+      tabs::Ungroup::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+TabsCaptureVisibleTabFunction::TabsCaptureVisibleTabFunction() = default;
+
+ExtensionFunction::ResponseAction TabsCaptureVisibleTabFunction::Run() {
+  EXTENSION_FUNCTION_VALIDATE(has_args());
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction TabsDetectLanguageFunction::Run() {
+  std::optional<tabs::DetectLanguage::Params> params =
+      tabs::DetectLanguage::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExecuteCodeInTabFunction::ExecuteCodeInTabFunction() = default;
+
+ExecuteCodeInTabFunction::~ExecuteCodeInTabFunction() = default;
+
+ExecuteCodeFunction::InitResult ExecuteCodeInTabFunction::Init() {
+  NOTIMPLEMENTED();
+  return set_init_result(VALIDATION_FAILURE);
+}
+
+bool ExecuteCodeInTabFunction::ShouldInsertCSS() const {
+  return false;
+}
+
+bool ExecuteCodeInTabFunction::ShouldRemoveCSS() const {
+  return false;
+}
+
+bool ExecuteCodeInTabFunction::CanExecuteScriptOnPage(std::string* error) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+ScriptExecutor* ExecuteCodeInTabFunction::GetScriptExecutor(
+    std::string* error) {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+bool ExecuteCodeInTabFunction::IsWebView() const {
+  return false;
+}
+
+int ExecuteCodeInTabFunction::GetRootFrameId() const {
+  NOTIMPLEMENTED();
+  return ExtensionApiFrameIdMap::kTopFrameId;
+}
+
+const GURL& ExecuteCodeInTabFunction::GetWebViewSrc() const {
+  NOTIMPLEMENTED();
+  return GURL::EmptyGURL();
+}
+
+bool TabsInsertCSSFunction::ShouldInsertCSS() const {
+  return true;
+}
+
+bool TabsRemoveCSSFunction::ShouldRemoveCSS() const {
+  return true;
+}
+
+ExtensionFunction::ResponseAction TabsSetZoomFunction::Run() {
+  std::optional<tabs::SetZoom::Params> params =
+      tabs::SetZoom::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction TabsGetZoomFunction::Run() {
+  std::optional<tabs::GetZoom::Params> params =
+      tabs::GetZoom::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction TabsSetZoomSettingsFunction::Run() {
+  std::optional<tabs::SetZoomSettings::Params> params =
+      tabs::SetZoomSettings::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction TabsGetZoomSettingsFunction::Run() {
+  std::optional<tabs::GetZoomSettings::Params> params =
+      tabs::GetZoomSettings::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+TabsDiscardFunction::TabsDiscardFunction() = default;
+
+ExtensionFunction::ResponseAction TabsDiscardFunction::Run() {
+  std::optional<tabs::Discard::Params> params =
+      tabs::Discard::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction TabsGoForwardFunction::Run() {
+  std::optional<tabs::GoForward::Params> params =
+      tabs::GoForward::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+ExtensionFunction::ResponseAction TabsGoBackFunction::Run() {
+  std::optional<tabs::GoBack::Params> params =
+      tabs::GoBack::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+  return RespondNow(Error(kNotImplemented));
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/tabs/tabs_api_stub.h b/chrome/browser/extensions/api/tabs/tabs_api_stub.h
new file mode 100644
index 0000000..a42987f
--- /dev/null
+++ b/chrome/browser/extensions/api/tabs/tabs_api_stub.h
@@ -0,0 +1,253 @@
+// Copyright 2025 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_EXTENSIONS_API_TABS_TABS_API_STUB_H_
+#define CHROME_BROWSER_EXTENSIONS_API_TABS_TABS_API_STUB_H_
+
+#include "chrome/common/extensions/api/tabs.h"
+#include "extensions/browser/api/execute_code_function.h"
+#include "extensions/browser/extension_function.h"
+
+namespace extensions {
+
+// This file provides a stub implementation of the chrome.tabs and
+// chrome.windows APIs. They are intended for desktop android bringup, as there
+// are other APIs (e.g. cookies) that rely types from tabs and windows.
+
+// Windows
+class WindowsGetFunction : public ExtensionFunction {
+  ~WindowsGetFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("windows.get", WINDOWS_GET)
+};
+class WindowsGetCurrentFunction : public ExtensionFunction {
+  ~WindowsGetCurrentFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("windows.getCurrent", WINDOWS_GETCURRENT)
+};
+class WindowsGetLastFocusedFunction : public ExtensionFunction {
+  ~WindowsGetLastFocusedFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("windows.getLastFocused", WINDOWS_GETLASTFOCUSED)
+};
+class WindowsGetAllFunction : public ExtensionFunction {
+  ~WindowsGetAllFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("windows.getAll", WINDOWS_GETALL)
+};
+class WindowsCreateFunction : public ExtensionFunction {
+  ~WindowsCreateFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("windows.create", WINDOWS_CREATE)
+};
+class WindowsUpdateFunction : public ExtensionFunction {
+  ~WindowsUpdateFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("windows.update", WINDOWS_UPDATE)
+};
+class WindowsRemoveFunction : public ExtensionFunction {
+  ~WindowsRemoveFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("windows.remove", WINDOWS_REMOVE)
+};
+
+// Tabs
+class TabsGetFunction : public ExtensionFunction {
+  ~TabsGetFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.get", TABS_GET)
+};
+class TabsGetCurrentFunction : public ExtensionFunction {
+  ~TabsGetCurrentFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.getCurrent", TABS_GETCURRENT)
+};
+class TabsGetSelectedFunction : public ExtensionFunction {
+  ~TabsGetSelectedFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.getSelected", TABS_GETSELECTED)
+};
+class TabsGetAllInWindowFunction : public ExtensionFunction {
+  ~TabsGetAllInWindowFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.getAllInWindow", TABS_GETALLINWINDOW)
+};
+class TabsQueryFunction : public ExtensionFunction {
+  ~TabsQueryFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.query", TABS_QUERY)
+};
+class TabsCreateFunction : public ExtensionFunction {
+  ~TabsCreateFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.create", TABS_CREATE)
+};
+class TabsDuplicateFunction : public ExtensionFunction {
+  ~TabsDuplicateFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.duplicate", TABS_DUPLICATE)
+};
+class TabsHighlightFunction : public ExtensionFunction {
+  ~TabsHighlightFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.highlight", TABS_HIGHLIGHT)
+};
+class TabsUpdateFunction : public ExtensionFunction {
+ public:
+  TabsUpdateFunction();
+
+ private:
+  ~TabsUpdateFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.update", TABS_UPDATE)
+};
+class TabsMoveFunction : public ExtensionFunction {
+  ~TabsMoveFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.move", TABS_MOVE)
+};
+class TabsReloadFunction : public ExtensionFunction {
+  ~TabsReloadFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.reload", TABS_RELOAD)
+};
+class TabsRemoveFunction : public ExtensionFunction {
+ public:
+  TabsRemoveFunction();
+
+ private:
+  ~TabsRemoveFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.remove", TABS_REMOVE)
+};
+class TabsGroupFunction : public ExtensionFunction {
+  ~TabsGroupFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.group", TABS_GROUP)
+};
+class TabsUngroupFunction : public ExtensionFunction {
+  ~TabsUngroupFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.ungroup", TABS_UNGROUP)
+};
+class TabsDetectLanguageFunction : public ExtensionFunction {
+ private:
+  ~TabsDetectLanguageFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.detectLanguage", TABS_DETECTLANGUAGE)
+};
+class TabsCaptureVisibleTabFunction : public ExtensionFunction {
+ public:
+  TabsCaptureVisibleTabFunction();
+
+ private:
+  ~TabsCaptureVisibleTabFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.captureVisibleTab", TABS_CAPTUREVISIBLETAB)
+};
+
+// Implement API calls tabs.executeScript, tabs.insertCSS, and tabs.removeCSS.
+class ExecuteCodeInTabFunction : public ExecuteCodeFunction {
+ public:
+  ExecuteCodeInTabFunction();
+
+ protected:
+  ~ExecuteCodeInTabFunction() override;
+
+  InitResult Init() override;
+  bool ShouldInsertCSS() const override;
+  bool ShouldRemoveCSS() const override;
+  bool CanExecuteScriptOnPage(std::string* error) override;
+  ScriptExecutor* GetScriptExecutor(std::string* error) override;
+  bool IsWebView() const override;
+  int GetRootFrameId() const override;
+  const GURL& GetWebViewSrc() const override;
+};
+
+class TabsExecuteScriptFunction : public ExecuteCodeInTabFunction {
+ private:
+  ~TabsExecuteScriptFunction() override = default;
+
+  DECLARE_EXTENSION_FUNCTION("tabs.executeScript", TABS_EXECUTESCRIPT)
+};
+
+class TabsInsertCSSFunction : public ExecuteCodeInTabFunction {
+ private:
+  ~TabsInsertCSSFunction() override = default;
+
+  bool ShouldInsertCSS() const override;
+
+  DECLARE_EXTENSION_FUNCTION("tabs.insertCSS", TABS_INSERTCSS)
+};
+
+class TabsRemoveCSSFunction : public ExecuteCodeInTabFunction {
+ private:
+  ~TabsRemoveCSSFunction() override = default;
+
+  bool ShouldRemoveCSS() const override;
+
+  DECLARE_EXTENSION_FUNCTION("tabs.removeCSS", TABS_REMOVECSS)
+};
+
+class TabsSetZoomFunction : public ExtensionFunction {
+ private:
+  ~TabsSetZoomFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.setZoom", TABS_SETZOOM)
+};
+
+class TabsGetZoomFunction : public ExtensionFunction {
+ private:
+  ~TabsGetZoomFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.getZoom", TABS_GETZOOM)
+};
+
+class TabsSetZoomSettingsFunction : public ExtensionFunction {
+ private:
+  ~TabsSetZoomSettingsFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.setZoomSettings", TABS_SETZOOMSETTINGS)
+};
+
+class TabsGetZoomSettingsFunction : public ExtensionFunction {
+ private:
+  ~TabsGetZoomSettingsFunction() override = default;
+  ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.getZoomSettings", TABS_GETZOOMSETTINGS)
+};
+
+class TabsDiscardFunction : public ExtensionFunction {
+ public:
+  TabsDiscardFunction();
+
+ private:
+  ~TabsDiscardFunction() override = default;
+  ExtensionFunction::ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.discard", TABS_DISCARD)
+};
+
+class TabsGoForwardFunction : public ExtensionFunction {
+ public:
+  TabsGoForwardFunction() {}
+
+ private:
+  ~TabsGoForwardFunction() override = default;
+  ExtensionFunction::ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.goForward", TABS_GOFORWARD)
+};
+
+class TabsGoBackFunction : public ExtensionFunction {
+ public:
+  TabsGoBackFunction() {}
+
+ private:
+  ~TabsGoBackFunction() override = default;
+  ExtensionFunction::ResponseAction Run() override;
+  DECLARE_EXTENSION_FUNCTION("tabs.goBack", TABS_GOBACK)
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_TABS_TABS_API_STUB_H_
diff --git a/chrome/browser/extensions/extension_action_dispatcher.cc b/chrome/browser/extensions/extension_action_dispatcher.cc
index 6cabb75..13bf726 100644
--- a/chrome/browser/extensions/extension_action_dispatcher.cc
+++ b/chrome/browser/extensions/extension_action_dispatcher.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/extensions/extension_action_dispatcher.h"
 
 #include "base/lazy_instance.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
 #include "components/sessions/content/session_tab_helper.h"
 #include "components/sessions/core/session_id.h"
 #include "content/public/browser/web_contents.h"
@@ -15,10 +16,6 @@
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/common/mojom/context_type.mojom.h"
 
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-#include "chrome/browser/extensions/extension_tab_util.h"
-#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
-
 namespace extensions {
 
 static base::LazyInstance<
@@ -63,7 +60,6 @@
     const ExtensionAction& extension_action,
     content::WebContents* web_contents,
     const Extension* extension) {
-#if BUILDFLAG(ENABLE_EXTENSIONS)
   events::HistogramValue histogram_value = events::UNKNOWN;
   const char* event_name = nullptr;
   switch (extension_action.action_type()) {
@@ -99,11 +95,6 @@
                              extension_action.extension_id(), histogram_value,
                              event_name, std::move(args));
   }
-#else
-  // TODO(crbug.com/393179880): Once we can create JS tab objects via
-  // ExtensionTabUtil::CreateTabObject() enable this method.
-  NOTIMPLEMENTED() << "Dispatching actions not yet supported on Android.";
-#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 }
 
 void ExtensionActionDispatcher::ClearAllValuesForTab(
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc
index 959e848a..094aaacf 100644
--- a/chrome/browser/extensions/extension_tab_util.cc
+++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -21,7 +21,11 @@
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/common/extension.h"
 #include "extensions/common/mojom/api_permission_id.mojom-shared.h"
+#include "extensions/common/mojom/context_type.mojom.h"
+#include "extensions/common/permissions/api_permission.h"
+#include "extensions/common/permissions/permissions_data.h"
 #include "third_party/blink/public/common/chrome_debug_urls.h"
 #include "third_party/blink/public/common/features.h"
 
@@ -76,14 +80,10 @@
 #include "extensions/browser/extension_util.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/error_utils.h"
-#include "extensions/common/extension.h"
 #include "extensions/common/feature_switch.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/manifest_handlers/incognito_info.h"
 #include "extensions/common/manifest_handlers/options_page_info.h"
-#include "extensions/common/mojom/context_type.mojom.h"
-#include "extensions/common/permissions/api_permission.h"
-#include "extensions/common/permissions/permissions_data.h"
 #include "url/gurl.h"
 #include "url/url_constants.h"
 #endif
@@ -94,10 +94,10 @@
 
 namespace extensions {
 
-#if !BUILDFLAG(IS_ANDROID)
-
 namespace {
 
+#if !BUILDFLAG(IS_ANDROID)
+
 constexpr char kGroupNotFoundError[] = "No group with id: *.";
 constexpr char kInvalidUrlError[] = "Invalid url: \"*\".";
 
@@ -164,6 +164,7 @@
   return url.SchemeIsFile() || (url.SchemeIs(content::kViewSourceScheme) &&
                                 GURL(url.GetContent()).SchemeIsFile());
 }
+#endif  // !BUILDFLAG(IS_ANDROID)
 
 ExtensionTabUtil::ScrubTabBehaviorType GetScrubTabBehaviorImpl(
     const Extension* extension,
@@ -203,6 +204,7 @@
   return ExtensionTabUtil::kDontScrubTab;
 }
 
+#if !BUILDFLAG(IS_ANDROID)
 bool HasValidMainFrameProcess(content::WebContents* contents) {
   content::RenderFrameHost* main_frame_host = contents->GetPrimaryMainFrame();
   content::RenderProcessHost* process_host = main_frame_host->GetProcess();
@@ -226,9 +228,11 @@
 
   base::UmaHistogramEnumeration("Extensions.Navigation.Scheme", scheme);
 }
+#endif  // !BUILDFLAG(IS_ANDROID)
 
 }  // namespace
 
+#if !BUILDFLAG(IS_ANDROID)
 ExtensionTabUtil::OpenTabParams::OpenTabParams() = default;
 
 ExtensionTabUtil::OpenTabParams::~OpenTabParams() = default;
@@ -469,6 +473,7 @@
 std::string ExtensionTabUtil::GetBrowserWindowTypeText(const Browser& browser) {
   return WindowControllerFromBrowser(&browser)->GetWindowTypeText();
 }
+#endif  // !BUILDFLAG(IS_ANDROID)
 
 // static
 api::tabs::Tab ExtensionTabUtil::CreateTabObject(
@@ -477,6 +482,13 @@
     const Extension* extension,
     TabStripModel* tab_strip,
     int tab_index) {
+#if BUILDFLAG(IS_ANDROID)
+  NOTIMPLEMENTED() << "Using stub implementation of CreateTabObject";
+  api::tabs::Tab tab_object;
+  tab_object.id = GetTabId(contents);
+  tab_object.index = tab_index;
+  return tab_object;
+#else
   if (!tab_strip)
     ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index);
   api::tabs::Tab tab_object;
@@ -558,8 +570,11 @@
 
   ScrubTabForExtension(extension, contents, &tab_object, scrub_tab_behavior);
   return tab_object;
+#endif
 }
 
+#if !BUILDFLAG(IS_ANDROID)
+// static
 base::Value::List ExtensionTabUtil::CreateTabList(const Browser* browser,
                                                   const Extension* extension,
                                                   mojom::ContextType context) {
@@ -600,6 +615,7 @@
   }
   return info;
 }
+#endif
 
 // static
 ExtensionTabUtil::ScrubTabBehavior ExtensionTabUtil::GetScrubTabBehavior(
@@ -666,6 +682,7 @@
   }
 }
 
+#if !BUILDFLAG(IS_ANDROID)
 // static
 bool ExtensionTabUtil::GetTabStripModel(const WebContents* web_contents,
                                         TabStripModel** tab_strip_model,
diff --git a/chrome/browser/extensions/extension_tab_util.h b/chrome/browser/extensions/extension_tab_util.h
index 425b57d..af7411b 100644
--- a/chrome/browser/extensions/extension_tab_util.h
+++ b/chrome/browser/extensions/extension_tab_util.h
@@ -86,6 +86,7 @@
       "Cannot navigate to a file URL without local file access.";
 
   static constexpr char kTabsKey[] = "tabs";
+#endif  // !BUILDFLAG(IS_ANDROID)
 
   enum ScrubTabBehaviorType {
     kScrubTabFully,
@@ -98,6 +99,7 @@
     ScrubTabBehaviorType pending_info;
   };
 
+#if !BUILDFLAG(IS_ANDROID)
   struct OpenTabParams {
     OpenTabParams();
     ~OpenTabParams();
@@ -151,6 +153,7 @@
 
   // Returns the tabs:: API constant for the window type of the `browser`.
   static std::string GetBrowserWindowTypeText(const Browser& browser);
+#endif  // !BUILDFLAG(IS_ANDROID)
 
   // Creates a Tab object (see chrome/common/extensions/api/tabs.json) with
   // information about the state of a browser tab for the given `web_contents`.
@@ -170,7 +173,7 @@
                                         const Extension* extension,
                                         TabStripModel* tab_strip,
                                         int tab_index);
-
+#if !BUILDFLAG(IS_ANDROID)
   // Creates a base::Value::Dict representing the window for the given
   // `browser`, and scrubs any privacy-sensitive data that `extension` does not
   // have access to. `populate_tab_behavior` determines whether tabs will be
@@ -186,6 +189,7 @@
   // Creates a tab MutedInfo object (see chrome/common/extensions/api/tabs.json)
   // with information about the mute state of a browser tab.
   static api::tabs::MutedInfo CreateMutedInfo(content::WebContents* contents);
+#endif  // !BUILDFLAG(IS_ANDROID)
 
   // Gets the level of scrubbing of tab data that needs to happen for a given
   // extension and web contents. This is the preferred way to get
@@ -207,6 +211,7 @@
                                    api::tabs::Tab* tab,
                                    ScrubTabBehavior scrub_tab_behavior);
 
+#if !BUILDFLAG(IS_ANDROID)
   // Gets the `tab_strip_model` and `tab_index` for the given `web_contents`.
   static bool GetTabStripModel(const content::WebContents* web_contents,
                                TabStripModel** tab_strip_model,
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 87bf79c..5db754a 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -243,11 +243,6 @@
     "expiry_milestone": 137
   },
   {
-    "name": "android-hub-search",
-    "owners": [ "wylieb@google.com", "clank-tab-dev@google.com" ],
-    "expiry_milestone": 140
-  },
-  {
     "name": "android-hub-search-tab-groups",
     "owners": [ "wylieb@google.com", "clank-tab-dev@google.com" ],
     "expiry_milestone": 140
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 5513d38..b8f5065a 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -4637,10 +4637,6 @@
 const char kAndroidElegantTextHeightDescription[] =
     "Enables elegant text height in core BrowserUI theme.";
 
-const char kAndroidHubSearchName[] = "Android Hub Search";
-const char kAndroidHubSearchDescription[] =
-    "Enables searching through the hub.";
-
 const char kAndroidHubSearchTabGroupsName[] = "Android Hub Tab Group Search";
 const char kAndroidHubSearchTabGroupsDescription[] =
     "Enables searching through tab groups in the hub.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 14b920b..f643f08 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2718,9 +2718,6 @@
 extern const char kAndroidElegantTextHeightName[];
 extern const char kAndroidElegantTextHeightDescription[];
 
-extern const char kAndroidHubSearchName[];
-extern const char kAndroidHubSearchDescription[];
-
 extern const char kAndroidHubSearchTabGroupsName[];
 extern const char kAndroidHubSearchTabGroupsDescription[];
 
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 ddf94b9c..fac64a2 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
@@ -576,7 +576,6 @@
     public static final String TAB_GROUP_SYNC_AUTO_OPEN_KILL_SWITCH =
             "TabGroupSyncAutoOpenKillSwitch";
     public static final String TABLET_TAB_STRIP_ANIMATION = "TabletTabStripAnimation";
-    public static final String TAB_RESUMPTION_MODULE_ANDROID = "TabResumptionModuleAndroid";
     public static final String TAB_STATE_FLAT_BUFFER = "TabStateFlatBuffer";
     public static final String TAB_STRIP_CONTEXT_MENU = "TabStripContextMenuAndroid";
     public static final String TAB_STRIP_DENSITY_CHANGE_ANDROID = "TabStripDensityChangeAndroid";
@@ -808,7 +807,10 @@
     public static final CachedFlag sMagicStackAndroid = newCachedFlag(MAGIC_STACK_ANDROID, true);
     public static final CachedFlag sMiniOriginBar = newCachedFlag(MINI_ORIGIN_BAR, false, true);
     public static final CachedFlag sMostVisitedTilesCustomization =
-            newCachedFlag(MOST_VISITED_TILES_CUSTOMIZATION, false);
+            newCachedFlag(
+                    MOST_VISITED_TILES_CUSTOMIZATION,
+                    /* defaultValue= */ false,
+                    /* defaultValueInTests= */ true);
     public static final CachedFlag sMostVisitedTilesReselect =
             newCachedFlag(MOST_VISITED_TILES_RESELECT, false);
     public static final CachedFlag sMultiInstanceApplicationStatusCleanup =
@@ -1590,8 +1592,6 @@
             sDisableBottomControlsStackerYOffsetDispatching =
                     sBottomBrowserControlsRefactor.newBooleanParam(
                             "disable_bottom_controls_stacker_y_offset", false);
-    public static final MutableIntParamWithSafeDefault sShowNewTabAnimationsVersion =
-            sShowNewTabAnimations.newIntParam("version", 4);
     public static final MutableIntParamWithSafeDefault sTabSwitcherColorBlendAnimateDurationMs =
             sTabSwitcherColorBlendAnimate.newIntParam("animation_duration_ms", 240);
     public static final MutableIntParamWithSafeDefault sTabSwitcherColorBlendAnimateInterpolator =
diff --git a/chrome/browser/glic/glic_user_status_browsertest.cc b/chrome/browser/glic/glic_user_status_browsertest.cc
index 32829c6..69b239f 100644
--- a/chrome/browser/glic/glic_user_status_browsertest.cc
+++ b/chrome/browser/glic/glic_user_status_browsertest.cc
@@ -49,11 +49,6 @@
 namespace {
 const char kGlicUserStatusRelativeTestUrl[] = "/userstatus";
 
-// Define constants that are used in prefs checks
-static constexpr char kUserStatus[] = "user_status";
-static constexpr char kUpdatedAt[] = "updated_at";
-static constexpr char kAccountId[] = "account_id";
-
 // Simple wrapper to serves as a POD for the test accounts.
 struct TestAccount {
   const std::string email;
@@ -216,7 +211,7 @@
   network::TestURLLoaderFactory test_url_loader_factory_;
 };
 
-IN_PROC_BROWSER_TEST_F(GlicUserStatusBrowserTest, Enterprise_SignIn_Enabled) {
+IN_PROC_BROWSER_TEST_F(GlicUserStatusBrowserTest, EnterpriseSignInEnabled) {
   policy::ScopedManagementServiceOverrideForTesting platform_management(
       policy::ManagementServiceFactory::GetForProfile(profile()),
       policy::EnterpriseManagementAuthority::CLOUD);
@@ -247,7 +242,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(GlicUserStatusBrowserTest,
-                       Enterprise_GeminiSettingsChange_SignedOut) {
+                       EnterpriseSignInEnabledGeminiSettings) {
   policy::ScopedManagementServiceOverrideForTesting platform_management(
       policy::ManagementServiceFactory::GetForProfile(profile()),
       policy::EnterpriseManagementAuthority::CLOUD);
@@ -332,7 +327,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(GlicUserStatusBrowserTest,
-                       Enterprise_GeminiSettingsChange_NoSignedOut) {
+                       EnterpriseGeminiSettingsChangeNoSignedOut) {
   policy::ScopedManagementServiceOverrideForTesting platform_management(
       policy::ManagementServiceFactory::GetForProfile(profile()),
       policy::EnterpriseManagementAuthority::CLOUD);
@@ -398,7 +393,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(GlicUserStatusBrowserTest,
-                       Enterprise_SignIn_DisabledByAdmin) {
+                       EnterpriseSignInDisabledByAdmin) {
   policy::ScopedManagementServiceOverrideForTesting platform_management(
       policy::ManagementServiceFactory::GetForProfile(profile()),
       policy::EnterpriseManagementAuthority::CLOUD);
@@ -428,7 +423,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(GlicUserStatusBrowserTest,
-                       Enterprise_SignIn_DisabledOther) {
+                       EnterpriseSignInDisabledOther) {
   policy::ScopedManagementServiceOverrideForTesting platform_management(
       policy::ManagementServiceFactory::GetForProfile(profile()),
       policy::EnterpriseManagementAuthority::CLOUD);
@@ -458,7 +453,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(GlicUserStatusBrowserTest,
-                       Enterprise_SignIn_ServerUnavailable_NoStoredResult) {
+                       EnterpriseSignInServerUnavailableNoStoredResult) {
   policy::ScopedManagementServiceOverrideForTesting platform_management(
       policy::ManagementServiceFactory::GetForProfile(profile()),
       policy::EnterpriseManagementAuthority::CLOUD);
@@ -483,7 +478,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(GlicUserStatusBrowserTest,
-                       Enterprise_SignIn_ServerUnavailable_HasStoredResult) {
+                       EnterpriseSignInServerUnavailableHasStoredResult) {
   policy::ScopedManagementServiceOverrideForTesting platform_management(
       policy::ManagementServiceFactory::GetForProfile(profile()),
       policy::EnterpriseManagementAuthority::CLOUD);
@@ -513,7 +508,7 @@
   EXPECT_FALSE(IsGlicEnabled());
 }
 
-IN_PROC_BROWSER_TEST_F(GlicUserStatusBrowserTest, Enterprise_SignOut) {
+IN_PROC_BROWSER_TEST_F(GlicUserStatusBrowserTest, EnterpriseSignOut) {
   policy::ScopedManagementServiceOverrideForTesting platform_management(
       policy::ManagementServiceFactory::GetForProfile(profile()),
       policy::EnterpriseManagementAuthority::CLOUD);
@@ -547,7 +542,7 @@
   EXPECT_FALSE(IsGlicEnabled());
 }
 
-IN_PROC_BROWSER_TEST_F(GlicUserStatusBrowserTest, NonEnterprise_SignIn) {
+IN_PROC_BROWSER_TEST_F(GlicUserStatusBrowserTest, NonEnterpriseSignIn) {
   bool request_received = false;
   embedded_test_server()->RegisterRequestHandler(base::BindLambdaForTesting(
       [=, &request_received](const net::test_server::HttpRequest& request)
@@ -586,5 +581,61 @@
   ASSERT_TRUE(IsGlicEnabled());
 }
 
+IN_PROC_BROWSER_TEST_F(GlicUserStatusBrowserTest, EnterpriseDataProtection) {
+  policy::ScopedManagementServiceOverrideForTesting platform_management(
+      policy::ManagementServiceFactory::GetForProfile(profile()),
+      policy::EnterpriseManagementAuthority::CLOUD);
+
+  RegisterUserStatusHandler(
+      net::HTTP_OK,
+      R"({"isGlicEnabled": true, "isAccessDeniedByAdmin": false,
+       "isEnterpriseAccountDataProtected": true })");
+  net::test_server::EmbeddedTestServerHandle test_server_handle;
+  ASSERT_TRUE(test_server_handle =
+                  embedded_test_server()->StartAndReturnHandle());
+
+  SetGlicUserStatusUrlForTest();
+
+  SimulatePrimaryAccountChangedSignIn(&enterpriseAccount);
+
+  ASSERT_TRUE(base::test::RunUntil(
+      [&]() { return GetCachedStatusDict().has_value(); }));
+
+  // Verify the isEnterpriseAccountDataProtected field.
+  EXPECT_EQ(profile()
+                ->GetPrefs()
+                ->GetDict(prefs::kGlicUserStatus)
+                .FindBool(kIsEnterpriseAccountDataProtected),
+            true);
+}
+
+IN_PROC_BROWSER_TEST_F(GlicUserStatusBrowserTest,
+                       EnterpriseDataProtectionMissingInServerResponse) {
+  policy::ScopedManagementServiceOverrideForTesting platform_management(
+      policy::ManagementServiceFactory::GetForProfile(profile()),
+      policy::EnterpriseManagementAuthority::CLOUD);
+
+  RegisterUserStatusHandler(
+      net::HTTP_OK,
+      R"({"isGlicEnabled": true, "isAccessDeniedByAdmin": false})");
+  net::test_server::EmbeddedTestServerHandle test_server_handle;
+  ASSERT_TRUE(test_server_handle =
+                  embedded_test_server()->StartAndReturnHandle());
+
+  SetGlicUserStatusUrlForTest();
+
+  SimulatePrimaryAccountChangedSignIn(&enterpriseAccount);
+
+  ASSERT_TRUE(base::test::RunUntil(
+      [&]() { return GetCachedStatusDict().has_value(); }));
+
+  // Verify the isEnterpriseAccountDataProtected field.
+  EXPECT_EQ(profile()
+                ->GetPrefs()
+                ->GetDict(prefs::kGlicUserStatus)
+                .FindBool(kIsEnterpriseAccountDataProtected),
+            false);
+}
+
 }  // namespace
 }  // namespace glic
diff --git a/chrome/browser/glic/glic_user_status_code.h b/chrome/browser/glic/glic_user_status_code.h
index 70accb9e..8ae3862 100644
--- a/chrome/browser/glic/glic_user_status_code.h
+++ b/chrome/browser/glic/glic_user_status_code.h
@@ -5,10 +5,22 @@
 #ifndef CHROME_BROWSER_GLIC_GLIC_USER_STATUS_CODE_H_
 #define CHROME_BROWSER_GLIC_GLIC_USER_STATUS_CODE_H_
 
+#include "base/json/json_value_converter.h"
 #include "base/time/time.h"
 
 namespace glic {
 
+// Keys of the pref dict.
+inline constexpr char kUserStatus[] = "user_status";
+inline constexpr char kUpdatedAt[] = "updated_at";
+inline constexpr char kAccountId[] = "account_id";
+
+// Keys of the JSON response of the glic user status RPC.
+inline constexpr char kIsGlicEnabled[] = "isGlicEnabled";
+inline constexpr char kIsAccessDeniedByAdmin[] = "isAccessDeniedByAdmin";
+inline constexpr char kIsEnterpriseAccountDataProtected[] =
+    "isEnterpriseAccountDataProtected";
+
 // These enums are persisted in the disk as integers. They should not be
 // renumbered or removed.
 enum UserStatusCode {
@@ -20,6 +32,9 @@
 
 struct CachedUserStatus {
   UserStatusCode user_status_code;
+  // If true, this is an enterprise account for whom different disclosures
+  // should be shown. See b/413482904 for details.
+  bool is_enterprise_account_data_protected;
   base::Time last_updated;
 };
 
diff --git a/chrome/browser/glic/glic_user_status_fetcher.cc b/chrome/browser/glic/glic_user_status_fetcher.cc
index 4bd0508..2090f895 100644
--- a/chrome/browser/glic/glic_user_status_fetcher.cc
+++ b/chrome/browser/glic/glic_user_status_fetcher.cc
@@ -73,10 +73,6 @@
       }
     }
    )");
-
-constexpr char kUserStatus[] = "user_status";
-constexpr char kUpdatedAt[] = "updated_at";
-constexpr char kAccountId[] = "account_id";
 }  // namespace
 
 namespace glic {
@@ -146,6 +142,7 @@
 
   return CachedUserStatus{
       UserStatusCode(pref_dict.FindInt(kUserStatus).value_or(0)),
+      pref_dict.FindBool(kIsEnterpriseAccountDataProtected).value_or(false),
       last_updated_default_value};
 }
 
@@ -303,14 +300,17 @@
 }
 
 void GlicUserStatusFetcher::ProcessResponse(const std::string& account_id_hash,
-                                            UserStatusCode result_code) {
+                                            CachedUserStatus user_status) {
   // We don't overwrite the previous GlicUserStatus when UserStatusCode is
   // SERVER_UNAVAILABLE.
-  if (result_code != UserStatusCode::SERVER_UNAVAILABLE) {
+  if (user_status.user_status_code != UserStatusCode::SERVER_UNAVAILABLE) {
     base::Value::Dict data;
     data.Set(kAccountId, account_id_hash);
-    data.Set(kUserStatus, result_code);
-    data.Set(kUpdatedAt, base::Time::Now().InSecondsFSinceUnixEpoch());
+    data.Set(kUserStatus, user_status.user_status_code);
+    data.Set(kUpdatedAt, user_status.last_updated.InSecondsFSinceUnixEpoch());
+    data.Set(kIsEnterpriseAccountDataProtected,
+             user_status.is_enterprise_account_data_protected);
+
     profile_->GetPrefs()->SetDict(glic::prefs::kGlicUserStatus,
                                   std::move(data));
   }
diff --git a/chrome/browser/glic/glic_user_status_fetcher.h b/chrome/browser/glic/glic_user_status_fetcher.h
index ead3b2e..010d7ae 100644
--- a/chrome/browser/glic/glic_user_status_fetcher.h
+++ b/chrome/browser/glic/glic_user_status_fetcher.h
@@ -83,7 +83,7 @@
   void FetchNow();
 
   void ProcessResponse(const std::string& account_id_hash,
-                       UserStatusCode result_code);
+                       CachedUserStatus user_status);
 
   bool is_user_status_waiting_for_refresh_token_ = false;
   raw_ptr<Profile> profile_;
diff --git a/chrome/browser/glic/glic_user_status_request.cc b/chrome/browser/glic/glic_user_status_request.cc
index 203d7a5..83bd6c08 100644
--- a/chrome/browser/glic/glic_user_status_request.cc
+++ b/chrome/browser/glic/glic_user_status_request.cc
@@ -7,19 +7,35 @@
 #include "base/json/json_reader.h"
 #include "base/logging.h"
 #include "base/strings/string_util.h"
+#include "chrome/browser/glic/glic_user_status_code.h"
 #include "google_apis/common/api_error_codes.h"
 
 namespace {
-constexpr char kIsGlicEnabled[] = "isGlicEnabled";
-constexpr char kIsAccessDeniedByAdmin[] = "isAccessDeniedByAdmin";
+// The server response would be first converted to JSON. The JSON object would
+// be converted to this struct.
+struct GlicUserStatusResponse {
+  bool is_glic_enabled = true;
+  bool is_access_denied_by_admin = false;
+  bool is_enterprise_account_data_protected = false;
+  static void RegisterJSONConverter(
+      base::JSONValueConverter<GlicUserStatusResponse>* converter) {
+    converter->RegisterBoolField(glic::kIsGlicEnabled,
+                                 &GlicUserStatusResponse::is_glic_enabled);
+    converter->RegisterBoolField(
+        glic::kIsAccessDeniedByAdmin,
+        &GlicUserStatusResponse::is_access_denied_by_admin);
+    converter->RegisterBoolField(
+        glic::kIsEnterpriseAccountDataProtected,
+        &GlicUserStatusResponse::is_enterprise_account_data_protected);
+  }
+};
 }  // namespace
 
 namespace glic {
 GlicUserStatusRequest::GlicUserStatusRequest(
     google_apis::RequestSender* sender,
     GURL url,
-    base::OnceCallback<void(UserStatusCode result_code)>
-        process_response_callback)
+    base::OnceCallback<void(CachedUserStatus)> process_response_callback)
     : UrlFetchRequestBase(sender,
                           google_apis::ProgressCallback(),
                           google_apis::ProgressCallback()),
@@ -36,7 +52,8 @@
     google_apis::ApiErrorCode code,
     const std::string& reason) {
   // This method is to map error reason parsed from response body to
-  // ApiErrorCode. we assume for now that result is to be sent as ApiErrorCode.
+  // ApiErrorCode. we assume for now that result is to be sent as
+  // ApiErrorCode.
   return code;
 }
 
@@ -49,9 +66,10 @@
     const network::mojom::URLResponseHead* response_head,
     base::FilePath response_file,
     std::string response_body) {
-  std::move(process_response_callback_)
-      .Run(MapApiErrorCodeAndResponseBodyToUserStatus(GetErrorCode(),
-                                                      response_body));
+  auto cached_user_status =
+      MapApiErrorCodeAndResponseBodyToUserStatus(GetErrorCode(), response_body);
+
+  std::move(process_response_callback_).Run(cached_user_status);
 
   OnProcessURLFetchResultsComplete();
 }
@@ -59,40 +77,68 @@
 // called when request is canceled or auth is failed.
 void GlicUserStatusRequest::RunCallbackOnPrematureFailure(
     google_apis::ApiErrorCode error) {
-  std::move(process_response_callback_)
-      .Run(MapApiErrorCodeAndResponseBodyToUserStatus(error, ""));
+  auto cached_user_status =
+      MapApiErrorCodeAndResponseBodyToUserStatus(error, "");
+  std::move(process_response_callback_).Run(cached_user_status);
 }
 
-UserStatusCode
+CachedUserStatus
 GlicUserStatusRequest::MapApiErrorCodeAndResponseBodyToUserStatus(
     google_apis::ApiErrorCode api_error_code,
-    std::string_view response_body) {
+    std::string_view response_body_as_string) {
+  // Currently, the is_enterprise_account_data_protected is not used for any
+  // Chrome behavir. Its sole use is to tell the user if their data is logged.
+  // It is worse to tell the user that their data  when in fact it is, than to
+  // tell the user that their data is logged when in fact it is not. (And that
+  // messaging is the only thing this boolean controls). Therefore, we default
+  // the field to false. If the field is to be used in other ways later, the
+  // default value may need to change too.
+  CachedUserStatus user_status = {
+      .user_status_code = UserStatusCode::SERVER_UNAVAILABLE,
+      .is_enterprise_account_data_protected = false,
+      .last_updated = base::Time::Now()};
+
   if (api_error_code != google_apis::HTTP_SUCCESS) {
-    return UserStatusCode::SERVER_UNAVAILABLE;
+    return user_status;
   }
 
   // Parse response body to JSON in the form of
   // {
   //    is_glic_enabled: true/false
   //    is_access_denied_by_admin: true/false
+  //    is_enterprise_account_data_protected: true/false
   // }
-  std::optional<base::Value::Dict> parsed =
-      base::JSONReader::ReadDict(response_body);
+  std::optional<base::Value::Dict> parsed_json =
+      base::JSONReader::ReadDict(response_body_as_string);
 
-  if (!parsed.has_value()) {
-    DVLOG(1) << "Failed reading response body: " << response_body;
-    return UserStatusCode::SERVER_UNAVAILABLE;
+  if (!parsed_json.has_value()) {
+    DVLOG(1) << "Failed reading response body: " << response_body_as_string;
+    return user_status;
   }
 
-  // The feature is enabled (if the response fails to mention it, we assume it
-  // is).
-  if (parsed->FindBool(kIsGlicEnabled).value_or(true)) {
-    return UserStatusCode::ENABLED;
+  // Convert response body in JSON format to the GlicUserStatusResponse
+  // struct.
+  GlicUserStatusResponse response;
+  base::JSONValueConverter<GlicUserStatusResponse> converter;
+
+  if (!converter.Convert(parsed_json.value(), &response)) {
+    return user_status;
   }
 
-  // The feature is disabled (find the reason, if given).
-  return parsed->FindBool(kIsAccessDeniedByAdmin).value_or(false)
-             ? UserStatusCode::DISABLED_BY_ADMIN
-             : UserStatusCode::DISABLED_OTHER;
+  user_status.is_enterprise_account_data_protected =
+      response.is_enterprise_account_data_protected;
+
+  if (response.is_glic_enabled) {
+    // The feature is enabled (if the response fails to mention it, we assume it
+    // is).
+    user_status.user_status_code = UserStatusCode::ENABLED;
+  } else {
+    // The feature is disabled (find the reason, if given).
+    user_status.user_status_code = response.is_access_denied_by_admin
+                                       ? UserStatusCode::DISABLED_BY_ADMIN
+                                       : UserStatusCode::DISABLED_OTHER;
+  }
+
+  return user_status;
 }
 }  // namespace glic
diff --git a/chrome/browser/glic/glic_user_status_request.h b/chrome/browser/glic/glic_user_status_request.h
index b5f7e3c6..a7cc3e333 100644
--- a/chrome/browser/glic/glic_user_status_request.h
+++ b/chrome/browser/glic/glic_user_status_request.h
@@ -19,8 +19,7 @@
       google_apis::RequestSender* sender,
       GURL url,
 
-      base::OnceCallback<void(UserStatusCode result_code)>
-          process_response_callback);
+      base::OnceCallback<void(CachedUserStatus)> process_response_callback);
   GlicUserStatusRequest(const GlicUserStatusRequest&) = delete;
   GlicUserStatusRequest& operator=(const GlicUserStatusRequest&) = delete;
   ~GlicUserStatusRequest() override;
@@ -42,13 +41,12 @@
   void RunCallbackOnPrematureFailure(google_apis::ApiErrorCode code) override;
 
  private:
-  static UserStatusCode MapApiErrorCodeAndResponseBodyToUserStatus(
+  static CachedUserStatus MapApiErrorCodeAndResponseBodyToUserStatus(
       google_apis::ApiErrorCode result_code,
       std::string_view response_body);
 
   GURL url_;
-  base::OnceCallback<void(UserStatusCode result_code)>
-      process_response_callback_;
+  base::OnceCallback<void(CachedUserStatus)> process_response_callback_;
 };
 
 }  // namespace glic
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarMediator.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarMediator.java
index 350d3d7..d5615aeb 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarMediator.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarMediator.java
@@ -37,7 +37,6 @@
 import org.chromium.chrome.browser.ui.searchactivityutils.SearchActivityExtras.ResolutionType;
 import org.chromium.components.embedder_support.util.UrlConstants;
 import org.chromium.components.feature_engagement.Tracker;
-import org.chromium.components.omnibox.OmniboxFeatures;
 import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.url.GURL;
@@ -154,9 +153,7 @@
 
             mRemoveReferenceButtonObservers.add(() -> supplier.removeObserver(observer));
 
-            if (OmniboxFeatures.sAndroidHubSearch.isEnabled()) {
-                pane.getHubSearchEnabledStateSupplier().addObserver(mOnHubSearchEnabledStateChange);
-            }
+            pane.getHubSearchEnabledStateSupplier().addObserver(mOnHubSearchEnabledStateChange);
         }
         ObservableSupplier<Pane> focusedPaneSupplier = paneManager.getFocusedPaneSupplier();
         focusedPaneSupplier.addObserver(mOnFocusedPaneChange);
@@ -169,12 +166,10 @@
 
         mPropertyModel.set(PANE_BUTTON_LOOKUP_CALLBACK, this::consumeButtonLookup);
 
-        if (OmniboxFeatures.sAndroidHubSearch.isEnabled()) {
-            mPropertyModel.set(SEARCH_LISTENER, this::onSearchClicked);
-            // Fire an event for the original setup.
-            mComponentCallbacks.onConfigurationChanged(mContext.getResources().getConfiguration());
-            mContext.registerComponentCallbacks(mComponentCallbacks);
-        }
+        mPropertyModel.set(SEARCH_LISTENER, this::onSearchClicked);
+        // Fire an event for the original setup.
+        mComponentCallbacks.onConfigurationChanged(mContext.getResources().getConfiguration());
+        mContext.registerComponentCallbacks(mComponentCallbacks);
     }
 
     /** Cleans up observers. */
@@ -186,15 +181,12 @@
         mRemoveReferenceButtonObservers.forEach(Runnable::run);
         mRemoveReferenceButtonObservers.clear();
         mPaneManager.getFocusedPaneSupplier().removeObserver(mOnFocusedPaneChange);
-        if (OmniboxFeatures.sAndroidHubSearch.isEnabled()) {
-            mContext.unregisterComponentCallbacks(mComponentCallbacks);
+        mContext.unregisterComponentCallbacks(mComponentCallbacks);
 
-            for (@PaneId int paneId : mPaneManager.getPaneOrderController().getPaneOrder()) {
-                @Nullable Pane pane = mPaneManager.getPaneForId(paneId);
-                if (pane == null) continue;
-                pane.getHubSearchEnabledStateSupplier()
-                        .removeObserver(mOnHubSearchEnabledStateChange);
-            }
+        for (@PaneId int paneId : mPaneManager.getPaneOrderController().getPaneOrder()) {
+            @Nullable Pane pane = mPaneManager.getPaneForId(paneId);
+            if (pane == null) continue;
+            pane.getHubSearchEnabledStateSupplier().removeObserver(mOnHubSearchEnabledStateChange);
         }
     }
 
@@ -291,16 +283,14 @@
         // This must be called before IS_INCOGNITO is set for all valid focused panes. This is
         // because hub search box elements (hint text) that will be updated via incognito state
         // changing will depend on a delay property key set in the configuration changed callback.
-        if (OmniboxFeatures.sAndroidHubSearch.isEnabled()) {
-            // Fire an event to determine what is shown.
-            mComponentCallbacks.onConfigurationChanged(mContext.getResources().getConfiguration());
+        // Fire an event to determine what is shown.
+        mComponentCallbacks.onConfigurationChanged(mContext.getResources().getConfiguration());
 
-            // Reset the enabled state of hub search to the supplier value or true if uninitialized
-            // when toggling panes to account for a potential disabled state from incognito reauth.
-            Boolean hubSearchEnabledState = focusedPane.getHubSearchEnabledStateSupplier().get();
-            boolean enabled = hubSearchEnabledState == null ? true : hubSearchEnabledState;
-            mPropertyModel.set(HUB_SEARCH_ENABLED_STATE, enabled);
-        }
+        // Reset the enabled state of hub search to the supplier value or true if uninitialized
+        // when toggling panes to account for a potential disabled state from incognito reauth.
+        Boolean hubSearchEnabledState = focusedPane.getHubSearchEnabledStateSupplier().get();
+        boolean enabled = hubSearchEnabledState == null ? true : hubSearchEnabledState;
+        mPropertyModel.set(HUB_SEARCH_ENABLED_STATE, enabled);
 
         mPropertyModel.set(MENU_BUTTON_VISIBLE, focusedPane.getMenuButtonVisible());
 
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarView.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarView.java
index f6b92be..5bef2f3 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarView.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarView.java
@@ -52,7 +52,6 @@
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.hub.HubToolbarProperties.PaneButtonLookup;
-import org.chromium.components.omnibox.OmniboxFeatures;
 import org.chromium.ui.animation.AnimationHandler;
 
 import java.util.List;
@@ -231,9 +230,7 @@
 
     void setColorMixer(HubColorMixer mixer) {
         registerColorBlends(mixer);
-        if (OmniboxFeatures.sAndroidHubSearch.isEnabled()) {
-            registerSearchBoxColorBlends(mixer);
-        }
+        registerSearchBoxColorBlends(mixer);
     }
 
     private void registerColorBlends(HubColorMixer mixer) {
@@ -456,9 +453,7 @@
     }
 
     void updateIncognitoElements(boolean isIncognito) {
-        if (OmniboxFeatures.sAndroidHubSearch.isEnabled()) {
-            updateSearchBoxElements(isIncognito);
-        }
+        updateSearchBoxElements(isIncognito);
     }
 
     private @Nullable View getButtonView(int index) {
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarViewUnitTest.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarViewUnitTest.java
index 53351f61..509bad6f 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarViewUnitTest.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/HubToolbarViewUnitTest.java
@@ -62,12 +62,9 @@
 import org.chromium.base.test.BaseRobolectricTestRule;
 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;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.hub.HubToolbarProperties.PaneButtonLookup;
 import org.chromium.components.browser_ui.styles.SemanticColorUtils;
-import org.chromium.components.omnibox.OmniboxFeatureList;
 import org.chromium.ui.base.TestActivity;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
@@ -307,7 +304,6 @@
     }
 
     @Test
-    @EnableFeatures(OmniboxFeatureList.ANDROID_HUB_SEARCH)
     public void testUpdateIncognitoElements() {
         mPropertyModel.set(IS_INCOGNITO, true);
         assertEquals(
@@ -319,7 +315,6 @@
     }
 
     @Test
-    @EnableFeatures(OmniboxFeatureList.ANDROID_HUB_SEARCH)
     public void testUpdateSearchBoxColorScheme() {
         forceSetColorScheme(HubColorScheme.INCOGNITO);
         assertEquals(
@@ -343,7 +338,6 @@
     }
 
     @Test
-    @EnableFeatures(OmniboxFeatureList.ANDROID_HUB_SEARCH)
     public void testHubSearchEnabledState() {
         mPropertyModel.set(HUB_SEARCH_ENABLED_STATE, false);
         assertFalse(mSearchBox.isEnabled());
@@ -357,17 +351,10 @@
     }
 
     @Test
-    @EnableFeatures(OmniboxFeatureList.ANDROID_HUB_SEARCH)
     public void testHubColorMixer_searchBoxEnabled() {
         verify(mColorMixer, times(8)).registerBlend(any());
     }
 
-    @Test
-    @DisableFeatures(OmniboxFeatureList.ANDROID_HUB_SEARCH)
-    public void testHubColorMixer_searchBoxDisabled() {
-        verify(mColorMixer, times(5)).registerBlend(any());
-    }
-
     /**
      * Setting the color twice forces {@link HubColorMixerImpl} to make a color scheme change
      * without an animation.
diff --git a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/ShrinkExpandHubLayoutAnimatorProvider.java b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/ShrinkExpandHubLayoutAnimatorProvider.java
index 6765c78..f1f7f26 100644
--- a/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/ShrinkExpandHubLayoutAnimatorProvider.java
+++ b/chrome/browser/hub/internal/android/java/src/org/chromium/chrome/browser/hub/ShrinkExpandHubLayoutAnimatorProvider.java
@@ -27,7 +27,6 @@
 import org.chromium.base.supplier.SyncOneshotSupplierImpl;
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
-import org.chromium.components.omnibox.OmniboxFeatures;
 import org.chromium.ui.animation.AnimationPerformanceTracker;
 import org.chromium.ui.animation.AnimationPerformanceTracker.AnimationMetrics;
 import org.chromium.ui.interpolators.Interpolators;
@@ -300,10 +299,8 @@
         }
 
         int searchBoxHeight =
-                OmniboxFeatures.sAndroidHubSearch.isEnabled()
-                        ? HubUtils.getSearchBoxHeight(
-                                mHubContainerView, R.id.hub_toolbar, R.id.toolbar_action_container)
-                        : 0;
+                HubUtils.getSearchBoxHeight(
+                        mHubContainerView, R.id.hub_toolbar, R.id.toolbar_action_container);
         Rect initialRect = animationData.getInitialRect();
         Rect finalRect = animationData.getFinalRect();
         assert mShrinkExpandImageView != null;
diff --git a/chrome/browser/magic_stack/android/junit/src/org/chromium/chrome/browser/magic_stack/HomeModulesCoordinatorUnitTest.java b/chrome/browser/magic_stack/android/junit/src/org/chromium/chrome/browser/magic_stack/HomeModulesCoordinatorUnitTest.java
index d715759..64bd3f00 100644
--- a/chrome/browser/magic_stack/android/junit/src/org/chromium/chrome/browser/magic_stack/HomeModulesCoordinatorUnitTest.java
+++ b/chrome/browser/magic_stack/android/junit/src/org/chromium/chrome/browser/magic_stack/HomeModulesCoordinatorUnitTest.java
@@ -55,7 +55,6 @@
 import org.chromium.base.FeatureOverrides;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.base.test.util.Features.DisableFeatures;
 import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.magic_stack.ModuleDelegate.ModuleType;
@@ -338,9 +337,6 @@
 
     @Test
     @SmallTest
-    @DisableFeatures({
-        ChromeFeatureList.TAB_RESUMPTION_MODULE_ANDROID,
-    })
     public void testRecordMagicStackScroll_Scrolled() {
         mCoordinator = createCoordinator(/* skipInitProfile= */ true);
         mCoordinator.setMediatorForTesting(mMediator);
@@ -358,9 +354,6 @@
 
     @Test
     @SmallTest
-    @DisableFeatures({
-        ChromeFeatureList.TAB_RESUMPTION_MODULE_ANDROID,
-    })
     public void testRecordMagicStackScroll_NotScrolled() {
         when(mModuleDelegateHost.isHomeSurface()).thenReturn(true);
         mCoordinator = createCoordinator(/* skipInitProfile= */ true);
@@ -376,9 +369,6 @@
 
     @Test
     @SmallTest
-    @DisableFeatures({
-        ChromeFeatureList.TAB_RESUMPTION_MODULE_ANDROID,
-    })
     public void testOnModuleChangedCallback() {
         when(mModuleDelegateHost.isHomeSurface()).thenReturn(true);
         mCoordinator = createCoordinator(/* skipInitProfile= */ true);
diff --git a/chrome/browser/media/webrtc/desktop_capture_access_handler.cc b/chrome/browser/media/webrtc/desktop_capture_access_handler.cc
index c1f3b78..d145ef1 100644
--- a/chrome/browser/media/webrtc/desktop_capture_access_handler.cc
+++ b/chrome/browser/media/webrtc/desktop_capture_access_handler.cc
@@ -15,6 +15,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/types/expected.h"
 #include "build/build_config.h"
 #include "chrome/browser/media/webrtc/capture_policy_utils.h"
 #include "chrome/browser/media/webrtc/desktop_capture_devices_util.h"
@@ -67,8 +68,9 @@
 #include "chrome/browser/media/webrtc/system_media_capture_permissions_mac.h"
 #endif  // BUILDFLAG(IS_MAC)
 
-using content::BrowserThread;
-using extensions::mojom::ManifestLocation;
+using ::blink::mojom::MediaStreamRequestResult;
+using ::content::BrowserThread;
+using ::extensions::mojom::ManifestLocation;
 
 namespace {
 
@@ -163,25 +165,26 @@
   return audio_permitted && audio_requested && audio_supported;
 }
 
-// Returns whether the request is approved or not. Some extensions do not
-// require user approval, because they provide their own user approval UI. For
-// others, shows a message box and asks for user approval.
-bool IsRequestApproved(content::WebContents* web_contents,
-                       const content::MediaStreamRequest& request,
-                       const extensions::Extension* extension,
-                       bool is_allowlisted_extension) {
+// Checks whether the request is approved.
+// If it is approved, returns MediaStreamRequestResult::OK.
+// If not approved, returns the relevant MediaStreamRequestResult error code.
+MediaStreamRequestResult CheckIfRequestApproved(
+    content::WebContents* web_contents,
+    const content::MediaStreamRequest& request,
+    const extensions::Extension* extension,
+    bool is_allowlisted_extension) {
   // Component extensions and some external extensions are approved by default.
   if (extension &&
       (extension->location() == ManifestLocation::kComponent ||
        extension->location() == ManifestLocation::kExternalComponent ||
        is_allowlisted_extension)) {
-    return true;
+    return MediaStreamRequestResult::OK;
   }
 
   // chrome://feedback/ is allowed by default.
   // The user can still decide whether the screenshot taken is shared or not.
   if (request.security_origin.spec() == chrome::kChromeUIFeedbackURL) {
-    return true;
+    return MediaStreamRequestResult::OK;
   }
 
 #if !BUILDFLAG(IS_ANDROID)
@@ -202,7 +205,15 @@
       l10n_util::GetStringFUTF16(IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TITLE,
                                  application_name),
       confirmation_text);
-  return mb_result == chrome::MESSAGE_BOX_RESULT_YES;
+  switch (mb_result) {
+    case chrome::MESSAGE_BOX_RESULT_NO:
+      return MediaStreamRequestResult::PERMISSION_DENIED_BY_USER;
+    case chrome::MESSAGE_BOX_RESULT_YES:
+      return MediaStreamRequestResult::OK;
+    case chrome::MESSAGE_BOX_RESULT_DEFERRED:
+      break;
+  }
+  NOTREACHED();
 }
 
 }  // namespace
@@ -245,16 +256,17 @@
   if (!screen_capture_enabled || !origin_is_secure) {
     std::move(pending_request->callback)
         .Run(blink::mojom::StreamDevicesSet(),
-             blink::mojom::MediaStreamRequestResult::INVALID_STATE,
+             MediaStreamRequestResult::INVALID_STATE,
              /*ui=*/nullptr);
     return;
   }
 
-  if (!IsRequestApproved(web_contents, pending_request->request, extension,
-                         pending_request->is_allowlisted_extension)) {
+  const MediaStreamRequestResult request_result =
+      CheckIfRequestApproved(web_contents, pending_request->request, extension,
+                             pending_request->is_allowlisted_extension);
+  if (request_result != MediaStreamRequestResult::OK) {
     std::move(pending_request->callback)
-        .Run(blink::mojom::StreamDevicesSet(),
-             blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
+        .Run(blink::mojom::StreamDevicesSet(), request_result,
              /*ui=*/nullptr);
     return;
   }
@@ -265,7 +277,7 @@
               pending_request->request.render_frame_id))) {
     std::move(pending_request->callback)
         .Run(blink::mojom::StreamDevicesSet(),
-             blink::mojom::MediaStreamRequestResult::INVALID_STATE,
+             MediaStreamRequestResult::INVALID_STATE,
              /*ui=*/nullptr);
     return;
   }
@@ -339,7 +351,7 @@
       blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE) {
     std::move(pending_request->callback)
         .Run(blink::mojom::StreamDevicesSet(),
-             blink::mojom::MediaStreamRequestResult::INVALID_STATE,
+             MediaStreamRequestResult::INVALID_STATE,
              /*ui=*/nullptr);
     return;
   }
@@ -351,7 +363,7 @@
   if (allowed_capture_level == AllowedScreenCaptureLevel::kDisallowed) {
     std::move(pending_request->callback)
         .Run(blink::mojom::StreamDevicesSet(),
-             blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
+             MediaStreamRequestResult::PERMISSION_DENIED,
              /*ui=*/nullptr);
     return;
   }
@@ -368,7 +380,7 @@
     if (allowed_capture_level < AllowedScreenCaptureLevel::kDesktop) {
       std::move(pending_request->callback)
           .Run(blink::mojom::StreamDevicesSet(),
-               blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
+               MediaStreamRequestResult::PERMISSION_DENIED,
                /*ui=*/nullptr);
       return;
     }
@@ -378,8 +390,7 @@
             system_permission_settings::SystemPermission::kAllowed) {
       std::move(pending_request->callback)
           .Run(blink::mojom::StreamDevicesSet(),
-               blink::mojom::MediaStreamRequestResult::
-                   PERMISSION_DENIED_BY_SYSTEM,
+               MediaStreamRequestResult::PERMISSION_DENIED_BY_SYSTEM,
                /*ui=*/nullptr);
       return;
     }
@@ -417,7 +428,7 @@
   if (media_id.type == content::DesktopMediaID::TYPE_NONE) {
     std::move(pending_request->callback)
         .Run(blink::mojom::StreamDevicesSet(),
-             blink::mojom::MediaStreamRequestResult::INVALID_STATE,
+             MediaStreamRequestResult::INVALID_STATE,
              /*ui=*/nullptr);
     return;
   }
@@ -425,7 +436,7 @@
   if (!IsMediaTypeAllowed(allowed_capture_level, media_id.type)) {
     std::move(pending_request->callback)
         .Run(blink::mojom::StreamDevicesSet(),
-             blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
+             MediaStreamRequestResult::PERMISSION_DENIED,
              /*ui=*/nullptr);
     return;
   }
@@ -434,10 +445,9 @@
       system_media_permissions::CheckSystemScreenCapturePermission() !=
           system_permission_settings::SystemPermission::kAllowed) {
     std::move(pending_request->callback)
-        .Run(
-            blink::mojom::StreamDevicesSet(),
-            blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED_BY_SYSTEM,
-            /*ui=*/nullptr);
+        .Run(blink::mojom::StreamDevicesSet(),
+             MediaStreamRequestResult::PERMISSION_DENIED_BY_SYSTEM,
+             /*ui=*/nullptr);
     return;
   }
 #endif
@@ -449,7 +459,7 @@
               media_id.web_contents_id.main_render_frame_id))) {
     std::move(pending_request->callback)
         .Run(blink::mojom::StreamDevicesSet(),
-             blink::mojom::MediaStreamRequestResult::TAB_CAPTURE_FAILURE,
+             MediaStreamRequestResult::TAB_CAPTURE_FAILURE,
              /*ui=*/nullptr);
     return;
   }
@@ -486,7 +496,7 @@
     if (!pending_request->picker) {
       std::move(pending_request->callback)
           .Run(blink::mojom::StreamDevicesSet(),
-               blink::mojom::MediaStreamRequestResult::INVALID_STATE,
+               MediaStreamRequestResult::INVALID_STATE,
                /*ui=*/nullptr);
       return;
     }
@@ -594,7 +604,8 @@
 void DesktopCaptureAccessHandler::OnPickerDialogResults(
     base::WeakPtr<content::WebContents> web_contents,
     const std::u16string& application_title,
-    content::DesktopMediaID media_id) {
+    base::expected<content::DesktopMediaID,
+                   blink::mojom::MediaStreamRequestResult> result) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   if (!web_contents) {
@@ -618,12 +629,13 @@
       std::move(queue.front());
   queue.pop_front();
 
-  if (media_id.is_null()) {
+  if (!result.has_value()) {
     std::move(pending_request->callback)
-        .Run(blink::mojom::StreamDevicesSet(),
-             blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
+        .Run(blink::mojom::StreamDevicesSet(), result.error(),
              /*ui=*/nullptr);
   } else {
+    const content::DesktopMediaID media_id = result.value();
+    CHECK(!media_id.is_null());
 #if BUILDFLAG(IS_CHROMEOS)
     // base::Unretained(this) is safe because DesktopCaptureAccessHandler is
     // owned by MediaCaptureDevicesDispatcher, which is a lazy singleton which
@@ -639,8 +651,10 @@
                   media_id.audio_share);
 #endif  // !BUILDFLAG(IS_CHROMEOS)
   }
-  if (!queue.empty())
+
+  if (!queue.empty()) {
     ProcessQueuedAccessRequest(queue, web_contents.get());
+  }
 }
 
 void DesktopCaptureAccessHandler::WebContentsDestroyed(
@@ -696,8 +710,7 @@
                          pending_request->is_allowlisted_extension);
 
   std::move(pending_request->callback)
-      .Run(stream_devices_set, blink::mojom::MediaStreamRequestResult::OK,
-           std::move(ui));
+      .Run(stream_devices_set, MediaStreamRequestResult::OK, std::move(ui));
 }
 
 #if BUILDFLAG(IS_CHROMEOS)
@@ -718,7 +731,7 @@
   if (!is_dlp_allowed) {
     std::move(pending_request->callback)
         .Run(blink::mojom::StreamDevicesSet(),
-             blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
+             MediaStreamRequestResult::PERMISSION_DENIED,
              /*ui=*/nullptr);
     return;
   }
diff --git a/chrome/browser/media/webrtc/desktop_capture_access_handler.h b/chrome/browser/media/webrtc/desktop_capture_access_handler.h
index cb2ca13..e684bf9a 100644
--- a/chrome/browser/media/webrtc/desktop_capture_access_handler.h
+++ b/chrome/browser/media/webrtc/desktop_capture_access_handler.h
@@ -10,6 +10,7 @@
 #include <utility>
 
 #include "base/memory/raw_ptr.h"
+#include "base/types/expected.h"
 #include "chrome/browser/media/capture_access_handler_base.h"
 #include "chrome/browser/media/media_access_handler.h"
 #include "chrome/browser/media/webrtc/desktop_media_list.h"
@@ -18,6 +19,7 @@
 #include "chrome/browser/tab_contents/web_contents_collection.h"
 #include "content/public/browser/desktop_media_id.h"
 #include "content/public/browser/media_stream_request.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 
 #if BUILDFLAG(IS_CHROMEOS)
 namespace aura {
@@ -86,9 +88,11 @@
       std::unique_ptr<PendingAccessRequest> pending_request);
   void ProcessQueuedAccessRequest(const RequestsQueue& queue,
                                   content::WebContents* web_contents);
-  void OnPickerDialogResults(base::WeakPtr<content::WebContents> web_contents,
-                             const std::u16string& application_title,
-                             content::DesktopMediaID source);
+  void OnPickerDialogResults(
+      base::WeakPtr<content::WebContents> web_contents,
+      const std::u16string& application_title,
+      base::expected<content::DesktopMediaID,
+                     blink::mojom::MediaStreamRequestResult> result);
   void DeletePendingAccessRequest(int render_process_id,
                                   int render_frame_id,
                                   int page_request_id);
diff --git a/chrome/browser/media/webrtc/desktop_capture_access_handler_unittest.cc b/chrome/browser/media/webrtc/desktop_capture_access_handler_unittest.cc
index 5ed7feb..8611af6 100644
--- a/chrome/browser/media/webrtc/desktop_capture_access_handler_unittest.cc
+++ b/chrome/browser/media/webrtc/desktop_capture_access_handler_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
 #include "base/run_loop.h"
+#include "base/types/expected.h"
 #include "build/build_config.h"
 #include "chrome/browser/media/webrtc/fake_desktop_media_picker_factory.h"
 #include "chrome/common/chrome_switches.h"
@@ -108,16 +109,19 @@
   }
 
   void ProcessDeviceUpdateRequest(
-      const content::DesktopMediaID& fake_desktop_media_id_response,
+      const base::expected<content::DesktopMediaID,
+                           blink::mojom::MediaStreamRequestResult>& response,
       blink::mojom::MediaStreamRequestResult* request_result,
       blink::mojom::StreamDevices* stream_devices_result,
       blink::MediaStreamRequestType request_type,
       bool request_audio) {
     FakeDesktopMediaPickerFactory::TestFlags test_flags[] = {
-        {false /* expect_screens */, false /* expect_windows*/,
-         true /* expect_tabs */, false /* expect_current_tab */,
-         request_audio /* expect_audio */,
-         fake_desktop_media_id_response /* selected_source */}};
+        {.expect_screens = false,
+         .expect_windows = false,
+         .expect_tabs = true,
+         .expect_current_tab = false,
+         .expect_audio = request_audio,
+         .picker_result = response}};
     picker_factory_->SetTestFlags(test_flags, std::size(test_flags));
     blink::mojom::MediaStreamType audio_type =
         request_audio ? blink::mojom::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE
@@ -212,9 +216,11 @@
 TEST_F(DesktopCaptureAccessHandlerTest, ChangeSourcePermissionDenied) {
   blink::mojom::MediaStreamRequestResult result;
   blink::mojom::StreamDevices stream_devices;
-  ProcessDeviceUpdateRequest(content::DesktopMediaID(), &result,
-                             &stream_devices, blink::MEDIA_DEVICE_UPDATE,
-                             false /*request audio*/);
+  ProcessDeviceUpdateRequest(
+      base::unexpected(
+          blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED),
+      &result, &stream_devices, blink::MEDIA_DEVICE_UPDATE,
+      false /*request audio*/);
   EXPECT_EQ(blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED, result);
   EXPECT_EQ(0u, blink::CountDevices(stream_devices));
 }
diff --git a/chrome/browser/media/webrtc/desktop_media_picker.h b/chrome/browser/media/webrtc/desktop_media_picker.h
index 509e618..a09ac0e 100644
--- a/chrome/browser/media/webrtc/desktop_media_picker.h
+++ b/chrome/browser/media/webrtc/desktop_media_picker.h
@@ -12,11 +12,13 @@
 #include "base/feature_list.h"
 #include "base/functional/callback_forward.h"
 #include "base/memory/raw_ptr.h"
+#include "base/types/expected.h"
 #include "build/android_buildflags.h"
 #include "build/buildflag.h"
 #include "content/public/browser/desktop_media_id.h"
 #include "content/public/browser/media_stream_request.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 #include "ui/base/mojom/ui_base_types.mojom-shared.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/gfx/native_widget_types.h"
@@ -37,7 +39,10 @@
 // TODO(crbug.com/40637301): Rename this class.
 class DesktopMediaPicker {
  public:
-  using DoneCallback = base::OnceCallback<void(content::DesktopMediaID id)>;
+  using DoneCallbackArgumentType =
+      base::expected<content::DesktopMediaID,
+                     blink::mojom::MediaStreamRequestResult>;
+  using DoneCallback = base::OnceCallback<void(DoneCallbackArgumentType)>;
 
   struct Params {
     // Possible sources of the request.
diff --git a/chrome/browser/media/webrtc/desktop_media_picker_controller.cc b/chrome/browser/media/webrtc/desktop_media_picker_controller.cc
index e4fc467b..151d1d0 100644
--- a/chrome/browser/media/webrtc/desktop_media_picker_controller.cc
+++ b/chrome/browser/media/webrtc/desktop_media_picker_controller.cc
@@ -12,6 +12,7 @@
 #include "base/containers/contains.h"
 #include "base/functional/bind.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/types/expected.h"
 #include "build/build_config.h"
 #include "chrome/browser/media/webrtc/capture_policy_utils.h"
 #include "chrome/browser/media/webrtc/desktop_media_picker.h"
@@ -32,8 +33,11 @@
 #include "extensions/common/switches.h"
 #include "media/audio/audio_features.h"
 #include "media/base/media_switches.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
 
+using ::content::DesktopMediaID;
+
 DesktopMediaPickerController::DesktopMediaPickerController(
     DesktopMediaPickerFactory* picker_factory)
     : picker_factory_(picker_factory
@@ -77,7 +81,7 @@
 }
 
 void DesktopMediaPickerController::WebContentsDestroyed() {
-  OnPickerDialogResults(std::string(), content::DesktopMediaID());
+  OnPickerDialogResults(std::string(), DesktopMediaID());
 }
 
 // static
@@ -108,8 +112,8 @@
   if (source_list->GetSourceCount() == 1) {
     // With only one possible source, the picker dialog is being bypassed. Apply
     // the default value of the "audio checkbox" here for desktop screen share.
-    content::DesktopMediaID media_id = source_list->GetSource(0).id;
-    DCHECK_EQ(media_id.type, content::DesktopMediaID::TYPE_SCREEN);
+    DesktopMediaID media_id = source_list->GetSource(0).id;
+    DCHECK_EQ(media_id.type, DesktopMediaID::TYPE_SCREEN);
     media_id.audio_share =
         params_.request_audio &&
         IsSystemAudioCaptureSupported(params_.request_source);
@@ -141,7 +145,11 @@
 
 void DesktopMediaPickerController::OnPickerDialogResults(
     const std::string& err,
-    content::DesktopMediaID source) {
-  if (done_callback_)
+    base::expected<content::DesktopMediaID,
+                   blink::mojom::MediaStreamRequestResult> result) {
+  if (done_callback_) {
+    const content::DesktopMediaID source =
+        result.value_or(content::DesktopMediaID());
     std::move(done_callback_).Run(err, source);
+  }
 }
diff --git a/chrome/browser/media/webrtc/desktop_media_picker_controller.h b/chrome/browser/media/webrtc/desktop_media_picker_controller.h
index 6276a06b..1d64ca1 100644
--- a/chrome/browser/media/webrtc/desktop_media_picker_controller.h
+++ b/chrome/browser/media/webrtc/desktop_media_picker_controller.h
@@ -11,10 +11,12 @@
 
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/types/expected.h"
 #include "chrome/browser/media/webrtc/desktop_media_list.h"
 #include "chrome/browser/media/webrtc/desktop_media_picker.h"
 #include "content/public/browser/desktop_media_id.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 #include "ui/base/ui_base_types.h"
 
 class DesktopMediaList;
@@ -89,8 +91,10 @@
   // This function is responsible to call |done_callback_| and after running the
   // callback |this| might be destroyed. Do **not** access fields after calling
   // this function.
-  void OnPickerDialogResults(const std::string& err,
-                             content::DesktopMediaID source);
+  void OnPickerDialogResults(
+      const std::string& err,
+      base::expected<content::DesktopMediaID,
+                     blink::mojom::MediaStreamRequestResult> result);
 
   Params params_;
   DoneCallback done_callback_;
diff --git a/chrome/browser/media/webrtc/display_media_access_handler.cc b/chrome/browser/media/webrtc/display_media_access_handler.cc
index 89da8b3..656cb16c 100644
--- a/chrome/browser/media/webrtc/display_media_access_handler.cc
+++ b/chrome/browser/media/webrtc/display_media_access_handler.cc
@@ -13,6 +13,7 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/types/expected.h"
 #include "build/build_config.h"
 #include "chrome/browser/bad_message.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
@@ -274,6 +275,10 @@
     // before sending IPC, but just to be sure double check here as well. This
     // is not treated as a BadMessage because it is possible for the transient
     // user activation to expire between the renderer side check and this check.
+    //
+    // TODO(crbug.com/416448339): Introduce and use a new result value,
+    // MediaStreamRequestResult::NO_TRANSIENT_ACTIVATION. In JS, it should map
+    // to `InvalidStateError`, not to `NotAllowedError`.
     if (!rfh->HasTransientUserActivation() &&
         capture_policy::IsTransientActivationRequiredForGetDisplayMedia(
             web_contents)) {
@@ -621,7 +626,7 @@
 
 void DisplayMediaAccessHandler::OnDisplaySurfaceSelected(
     base::WeakPtr<WebContents> web_contents,
-    DesktopMediaID media_id) {
+    base::expected<DesktopMediaID, MediaStreamRequestResult> result) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   if (!web_contents) {
@@ -630,12 +635,14 @@
     return;
   }
 
-  if (media_id.is_null()) {
-    RejectRequest(web_contents.get(),
-                  MediaStreamRequestResult::PERMISSION_DENIED);
+  if (!result.has_value()) {
+    RejectRequest(web_contents.get(), result.error());
     return;
   }
 
+  const DesktopMediaID media_id = result.value();
+  CHECK(!media_id.is_null());
+
   // If the media id is tied to a tab, check that it hasn't been destroyed.
   if (media_id.type == DesktopMediaID::TYPE_WEB_CONTENTS &&
       !WebContents::FromRenderFrameHost(content::RenderFrameHost::FromID(
diff --git a/chrome/browser/media/webrtc/display_media_access_handler.h b/chrome/browser/media/webrtc/display_media_access_handler.h
index a74500c4..088b69c4 100644
--- a/chrome/browser/media/webrtc/display_media_access_handler.h
+++ b/chrome/browser/media/webrtc/display_media_access_handler.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/memory/weak_ptr.h"
+#include "base/types/expected.h"
 #include "build/build_config.h"
 #include "chrome/browser/media/capture_access_handler_base.h"
 #include "chrome/browser/media/media_access_handler.h"
@@ -18,6 +19,7 @@
 #include "chrome/browser/tab_contents/web_contents_collection.h"
 #include "content/public/browser/desktop_media_id.h"
 #include "content/public/browser/web_contents.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 
 namespace extensions {
 class Extension;
@@ -97,12 +99,16 @@
   void AcceptRequest(content::WebContents* web_contents,
                      const content::DesktopMediaID& media_id);
 
-  // Called back after the user chooses one of the possible desktop media
-  // sources for the request that's currently being processed. If no |media_id|
-  // is given, the request was rejected, either by the browser or by the user.
+  // Called after the user interacts with the media-picker.
+  // - If the user chooses to share a tab/window/screen, `result.value()` holds
+  //   the media-ID of the chosen surface.
+  // - If the user rejects the prompt, or if any error occurs, or if the system
+  //   automatically rejects the request, `result.error()` holds the relevant
+  //   error code.
   void OnDisplaySurfaceSelected(
       base::WeakPtr<content::WebContents> web_contents,
-      content::DesktopMediaID media_id);
+      base::expected<content::DesktopMediaID,
+                     blink::mojom::MediaStreamRequestResult> result);
 
 #if BUILDFLAG(IS_CHROMEOS)
   // Called back after checking Data Leak Prevention (DLP) restrictions.
diff --git a/chrome/browser/media/webrtc/display_media_access_handler_unittest.cc b/chrome/browser/media/webrtc/display_media_access_handler_unittest.cc
index 0edb61e..82f93e82 100644
--- a/chrome/browser/media/webrtc/display_media_access_handler_unittest.cc
+++ b/chrome/browser/media/webrtc/display_media_access_handler_unittest.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-
 #include "chrome/browser/media/webrtc/display_media_access_handler.h"
 
 #include <array>
@@ -15,6 +14,7 @@
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/mock_callback.h"
+#include "base/types/expected.h"
 #include "build/build_config.h"
 #include "chrome/browser/media/webrtc/fake_desktop_media_picker_factory.h"
 #include "chrome/common/pref_names.h"
@@ -71,7 +71,7 @@
          .expect_tabs = true,
          .expect_current_tab = false,
          .expect_audio = request_audio,
-         .selected_source =
+         .picker_result =
              content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN,
                                      content::DesktopMediaID::kFakeId)});
   }
@@ -155,15 +155,18 @@
   }
 
   void ProcessRequest(
-      const content::DesktopMediaID& fake_desktop_media_id_response,
+      base::expected<content::DesktopMediaID,
+                     blink::mojom::MediaStreamRequestResult> response,
       blink::mojom::MediaStreamRequestResult* request_result,
       blink::mojom::StreamDevices& devices_result,
       bool request_audio,
       bool expect_result = true) {
-    SetTestFlags({{true /* expect_screens */, true /* expect_windows*/,
-                   true /* expect_tabs */, /* expect_current_tab, */ false,
-                   request_audio,
-                   fake_desktop_media_id_response /* selected_source */}});
+    SetTestFlags({{.expect_screens = true,
+                   .expect_windows = true,
+                   .expect_tabs = true,
+                   .expect_current_tab = false,
+                   .expect_audio = request_audio,
+                   .picker_result = response}});
 
     content::MediaStreamRequest request = MakeRequest(request_audio);
 
@@ -315,8 +318,9 @@
 TEST_F(DisplayMediaAccessHandlerTest, PermissionDenied) {
   blink::mojom::MediaStreamRequestResult result;
   blink::mojom::StreamDevices devices;
-  ProcessRequest(content::DesktopMediaID(), &result, devices,
-                 true /* request_audio */);
+  ProcessRequest(base::unexpected(
+                     blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED),
+                 &result, devices, true /* request_audio */);
   EXPECT_EQ(blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED, result);
   EXPECT_EQ(0u, blink::CountDevices(devices));
 }
@@ -887,7 +891,9 @@
   SetTestFlags({{/*expect_screens=*/!exclude_monitor_type_surfaces_,
                  /*expect_windows=*/true,
                  /*expect_tabs=*/true, /*expect_current_tab=*/false,
-                 /*expect_audio=*/false, content::DesktopMediaID(),
+                 /*expect_audio=*/false,
+                 base::unexpected(
+                     blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED),
                  /*cancelled=*/false}});
   blink::mojom::MediaStreamRequestResult result;
   blink::mojom::StreamDevices devices;
diff --git a/chrome/browser/media/webrtc/fake_desktop_media_picker_factory.cc b/chrome/browser/media/webrtc/fake_desktop_media_picker_factory.cc
index 7659cf1..79186ab9 100644
--- a/chrome/browser/media/webrtc/fake_desktop_media_picker_factory.cc
+++ b/chrome/browser/media/webrtc/fake_desktop_media_picker_factory.cc
@@ -77,7 +77,8 @@
 }
 
 void FakeDesktopMediaPicker::CallCallback(DoneCallback done_callback) {
-  std::move(done_callback).Run(expectation_->selected_source);
+  CHECK(expectation_->picker_result.has_value());
+  std::move(done_callback).Run(expectation_->picker_result.value());
 }
 
 FakeDesktopMediaPickerFactory::FakeDesktopMediaPickerFactory() = default;
diff --git a/chrome/browser/media/webrtc/fake_desktop_media_picker_factory.h b/chrome/browser/media/webrtc/fake_desktop_media_picker_factory.h
index 6047596..ef253ad 100644
--- a/chrome/browser/media/webrtc/fake_desktop_media_picker_factory.h
+++ b/chrome/browser/media/webrtc/fake_desktop_media_picker_factory.h
@@ -9,10 +9,12 @@
 #include <vector>
 
 #include "base/memory/raw_ptr.h"
+#include "base/types/expected.h"
 #include "chrome/browser/media/webrtc/desktop_media_list.h"
 #include "chrome/browser/media/webrtc/desktop_media_picker.h"
 #include "chrome/browser/media/webrtc/desktop_media_picker_factory.h"
 #include "content/public/browser/desktop_media_id.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 
 class FakeDesktopMediaPicker;
 
@@ -26,7 +28,9 @@
     bool expect_tabs = false;
     bool expect_current_tab = false;
     bool expect_audio = false;
-    content::DesktopMediaID selected_source;
+    std::optional<base::expected<content::DesktopMediaID,
+                                 blink::mojom::MediaStreamRequestResult>>
+        picker_result;
     bool cancelled = false;
 
     // Following flags are set by FakeDesktopMediaPicker when it's created and
diff --git a/chrome/browser/media/webrtc/webrtc_desktop_capture_browsertest.cc b/chrome/browser/media/webrtc/webrtc_desktop_capture_browsertest.cc
index 589481d..6ab38a0 100644
--- a/chrome/browser/media/webrtc/webrtc_desktop_capture_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_desktop_capture_browsertest.cc
@@ -256,7 +256,7 @@
         .expect_screens = true,
         .expect_windows = true,
         .expect_tabs = true,
-        .selected_source = std::move(media_id_callback).Run(),
+        .picker_result = std::move(media_id_callback).Run(),
     };
     picker_factory_.SetTestFlags(&test_flags, /*tests_count=*/1);
 
diff --git a/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc b/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc
index 77dad4c..ebafcf5 100644
--- a/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc
@@ -2512,3 +2512,42 @@
   EXPECT_FALSE(HasCscIndicator(capture_session.initially_captured_tab()));
   EXPECT_FALSE(HasCscIndicator(capture_session.other_tab()));
 }
+
+class WebRtcScreenCaptureBrowserTestUserRejection
+    : public WebRtcScreenCaptureBrowserTest,
+      public testing::WithParamInterface<bool> {
+ public:
+  WebRtcScreenCaptureBrowserTestUserRejection()
+      : prefer_current_tab_(GetParam()) {}
+  ~WebRtcScreenCaptureBrowserTestUserRejection() override = default;
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    WebRtcScreenCaptureBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(prefer_current_tab_
+                                   ? switches::kThisTabCaptureAutoReject
+                                   : switches::kCaptureAutoReject);
+  }
+
+  bool PreferCurrentTab() const override { return prefer_current_tab_; }
+
+ private:
+  const bool prefer_current_tab_;
+};
+
+INSTANTIATE_TEST_SUITE_P(, WebRtcScreenCaptureBrowserTestUserRejection, Bool());
+
+IN_PROC_BROWSER_TEST_P(WebRtcScreenCaptureBrowserTestUserRejection,
+                       CorrectErrorReported) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  OpenTestPageInNewTab(kCapturedPageMain);
+  content::WebContents* capturing_tab = OpenTestPageInNewTab(kMainHtmlPage);
+
+  RunGetDisplayMedia(
+      capturing_tab,
+      GetConstraints(
+          /*video=*/true, /*audio=*/false),
+      /*is_fake_ui=*/false,
+      /*expect_success=*/false,
+      /*is_tab_capture=*/true,
+      /*expected_error=*/"NotAllowedError: Permission denied by user");
+}
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc
index 4a5d0d68..ed7bd987 100644
--- a/chrome/browser/net/system_network_context_manager.cc
+++ b/chrome/browser/net/system_network_context_manager.cc
@@ -44,6 +44,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/google_url_loader_throttle.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/common/request_header_integrity/buildflags.h"
 #include "components/certificate_transparency/ct_known_logs.h"
 #include "components/embedder_support/user_agent_utils.h"
 #include "components/net_log/net_export_file_writer.h"
@@ -105,6 +106,10 @@
 #include "chrome/browser/net/chrome_mojo_proxy_resolver_win.h"
 #endif  // BUILDFLAG(IS_WIN)
 
+#if BUILDFLAG(ENABLE_REQUEST_HEADER_INTEGRITY)
+#include "chrome/common/request_header_integrity/request_header_integrity_url_loader_throttle.h"  // nogncheck crbug.com/1125897
+#endif
+
 namespace {
 // Enumeration of possible sandbox states. These values are persisted to logs,
 // so entries should not be renumbered and numeric values should never be
@@ -859,6 +864,10 @@
     network::mojom::NetworkContextParams* network_context_params) {
   variations::UpdateCorsExemptHeaderForVariations(network_context_params);
   GoogleURLLoaderThrottle::UpdateCorsExemptHeader(network_context_params);
+#if BUILDFLAG(ENABLE_REQUEST_HEADER_INTEGRITY)
+  request_header_integrity::RequestHeaderIntegrityURLLoaderThrottle::
+      UpdateCorsExemptHeaders(network_context_params);
+#endif  // BUILDFLAG(ENABLE_REQUEST_HEADER_INTEGRITY)
 
   network_context_params->enable_brotli = true;
 
diff --git a/chrome/browser/ntp_customization/java/res/layout/ntp_customization_bottom_sheet.xml b/chrome/browser/ntp_customization/java/res/layout/ntp_customization_bottom_sheet.xml
index 2947d21..7769bf3f 100644
--- a/chrome/browser/ntp_customization/java/res/layout/ntp_customization_bottom_sheet.xml
+++ b/chrome/browser/ntp_customization/java/res/layout/ntp_customization_bottom_sheet.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-Copyright 2025 The Chromium Authors.
+Copyright 2025 The Chromium Authors
 Use of this source code is governed by a BSD-style license that can be
 found in the LICENSE file.
 -->
@@ -8,6 +8,7 @@
 <ScrollView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/bottom_sheet_container"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     tools:ignore="UnusedResources">
diff --git a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationBottomSheetContent.java b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationBottomSheetContent.java
index 14aa8bb..fbb81e4 100644
--- a/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationBottomSheetContent.java
+++ b/chrome/browser/ntp_customization/java/src/org/chromium/chrome/browser/ntp_customization/NtpCustomizationBottomSheetContent.java
@@ -49,7 +49,7 @@
 
     @Override
     public int getVerticalScrollOffset() {
-        return 0;
+        return mContentView.findViewById(R.id.bottom_sheet_container).getScrollY();
     }
 
     @Override
diff --git a/chrome/browser/pdf/pdf_searchify_browsertest.cc b/chrome/browser/pdf/pdf_searchify_browsertest.cc
index 4ca6207d..30435c6 100644
--- a/chrome/browser/pdf/pdf_searchify_browsertest.cc
+++ b/chrome/browser/pdf/pdf_searchify_browsertest.cc
@@ -13,7 +13,6 @@
 #include "components/pdf/browser/pdf_document_helper.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
-#include "pdf/pdf_features.h"
 #include "services/screen_ai/public/cpp/utilities.h"
 #include "ui/accessibility/accessibility_features.h"
 #include "ui/accessibility/accessibility_switches.h"
@@ -77,7 +76,6 @@
     if (IsSearchifyActive()) {
       enabled.push_back({::features::kScreenAITestMode, {}});
       enabled.push_back({ax::mojom::features::kScreenAIOCREnabled, {}});
-      enabled.push_back({chrome_pdf::features::kPdfSearchify, {}});
     }
     return enabled;
   }
@@ -190,5 +188,8 @@
       IsScreenReaderEnabled(), IsSearchifyActive() ? 1 : 0);
 }
 
+// TODO(crbug.com/382610226): Add text selection test for PDFs with rotated page
+// or image.
+
 // TODO(crbug.com/382610226): Consider adding save tests like
 // pdf_extension_download_test.cc
diff --git a/chrome/browser/privacy_sandbox/notice/BUILD.gn b/chrome/browser/privacy_sandbox/notice/BUILD.gn
index a4bf546..4f23352 100644
--- a/chrome/browser/privacy_sandbox/notice/BUILD.gn
+++ b/chrome/browser/privacy_sandbox/notice/BUILD.gn
@@ -101,6 +101,7 @@
       ":notice_mojom",
       "//base",
       "//chrome/browser/profiles:profile",
+      "//chrome/browser/sync",
       "//chrome/browser/ui:ui",
       "//chrome/browser/ui/browser_window:browser_window",
       "//chrome/browser/ui/privacy_sandbox:privacy_sandbox",
@@ -215,6 +216,7 @@
     sources += [ "desktop_entrypoint_handlers_browsertest.cc" ]
     deps += [
       ":desktop_view_manager",
+      "//chrome/browser/sync",
       "//chrome/test:test_support_ui",
     ]
   }
diff --git a/chrome/browser/privacy_sandbox/notice/desktop_entrypoint_handlers.cc b/chrome/browser/privacy_sandbox/notice/desktop_entrypoint_handlers.cc
index b5e75776..5eafe61 100644
--- a/chrome/browser/privacy_sandbox/notice/desktop_entrypoint_handlers.cc
+++ b/chrome/browser/privacy_sandbox/notice/desktop_entrypoint_handlers.cc
@@ -7,10 +7,12 @@
 #include "chrome/browser/privacy_sandbox/notice/desktop_entrypoint_handlers_helper.h"
 #include "chrome/browser/privacy_sandbox/notice/desktop_view_manager.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sync/sync_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
 #include "chrome/browser/ui/profiles/profile_customization_bubble_sync_controller.h"
 #include "chrome/common/webui_url_constants.h"
+#include "components/sync/service/sync_service.h"
 #include "components/tabs/public/tab_interface.h"
 #include "components/web_modal/web_contents_modal_dialog_host.h"
 #include "content/public/browser/navigation_handle.h"
@@ -95,6 +97,13 @@
     return;
   }
 
+  // If a Sync setup is in progress, the prompt should not be shown.
+  if (auto* sync_service = SyncServiceFactory::GetForProfile(profile)) {
+    if (sync_service->IsSetupInProgress()) {
+      return;
+    }
+  }
+
   // TODO(crbug.com/408016824):  Add error-event histograms.
 
   HandleEntryPoint(browser_window_interface);
diff --git a/chrome/browser/privacy_sandbox/notice/desktop_entrypoint_handlers_browsertest.cc b/chrome/browser/privacy_sandbox/notice/desktop_entrypoint_handlers_browsertest.cc
index cc097a1..228d9b0 100644
--- a/chrome/browser/privacy_sandbox/notice/desktop_entrypoint_handlers_browsertest.cc
+++ b/chrome/browser/privacy_sandbox/notice/desktop_entrypoint_handlers_browsertest.cc
@@ -9,12 +9,14 @@
 #include "chrome/browser/privacy_sandbox/notice/mocks/mock_notice_service.h"
 #include "chrome/browser/privacy_sandbox/notice/notice_service_factory.h"
 #include "chrome/browser/privacy_sandbox/notice/notice_service_interface.h"
+#include "chrome/browser/sync/sync_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/platform_browser_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/sync/test/test_sync_service.h"
 #include "content/public/test/browser_test.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
@@ -28,6 +30,24 @@
   PrivacySandboxNoticeEntryPointHandlersTest()
       : https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
 
+  void RegisterTestingSyncServiceFactory(content::BrowserContext* context) {
+    SyncServiceFactory::GetInstance()->SetTestingFactory(
+        context,
+        base::BindRepeating(
+            [](content::BrowserContext*) -> std::unique_ptr<KeyedService> {
+              return std::make_unique<syncer::TestSyncService>();
+            }));
+  }
+
+  void SetUpInProcessBrowserTestFixture() override {
+    services_subscription_ =
+        BrowserContextDependencyManager::GetInstance()
+            ->RegisterCreateServicesCallbackForTesting(base::BindRepeating(
+                &PrivacySandboxNoticeEntryPointHandlersTest::
+                    RegisterTestingSyncServiceFactory,
+                base::Unretained(this)));
+  }
+
   void SetUpOnMainThread() override {
     https_test_server()->AddDefaultHandlers(
         base::FilePath(FILE_PATH_LITERAL("content/test/data")));
@@ -51,9 +71,15 @@
         mock_notice_service_->GetDesktopViewManager());
   }
 
+  syncer::TestSyncService* test_sync_service() {
+    return static_cast<syncer::TestSyncService*>(
+        SyncServiceFactory::GetForProfile(browser()->profile()));
+  }
+
  protected:
   raw_ptr<MockPrivacySandboxNoticeService> mock_notice_service_;
   net::EmbeddedTestServer https_test_server_;
+  base::CallbackListSubscription services_subscription_;
 };
 
 // Test that navigation to unsuitable URLS do not alert view manager.
@@ -105,6 +131,37 @@
   Mock::VerifyAndClearExpectations(mock_view_manager());
 }
 
+IN_PROC_BROWSER_TEST_F(PrivacySandboxNoticeEntryPointHandlersTest,
+                       NoPromptSync) {
+  // Check when sync setup is in progress, that no prompt is shown.
+  EXPECT_CALL(*mock_view_manager(), HandleChromeOwnedPageNavigation).Times(0);
+
+  test_sync_service()->SetSetupInProgress();
+
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(),
+                                           GURL(chrome::kChromeUISettingsURL)));
+
+  Mock::VerifyAndClearExpectations(mock_view_manager());
+}
+
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+// Check when profile setup is in progress, that no prompt is shown.
+IN_PROC_BROWSER_TEST_F(PrivacySandboxNoticeEntryPointHandlersTest,
+                       NoPromptProfileSetup) {
+  EXPECT_CALL(*mock_view_manager(), HandleChromeOwnedPageNavigation).Times(0);
+  // Show the profile customization dialog.
+  browser()->signin_view_controller()->ShowModalProfileCustomizationDialog(
+      /*is_local_profile_creation=*/true);
+  ASSERT_TRUE(ui_test_utils::NavigateToURLWithDisposition(
+      browser(), GURL(chrome::kChromeUINewTabPageURL),
+      WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP));
+
+  Mock::VerifyAndClearExpectations(mock_view_manager());
+}
+#endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
+
+// URLS check
 class PrivacySandboxNoticeEntryPointHandlersTest_SuitableUrls
     : public PrivacySandboxNoticeEntryPointHandlersTest,
       public testing::WithParamInterface<GURL> {};
@@ -130,23 +187,5 @@
                     GURL(url::kAboutBlankURL),
                     GURL(chrome::kChromeUISettingsURL),
                     GURL(chrome::kChromeUIHistoryURL)));
-
-#if BUILDFLAG(ENABLE_DICE_SUPPORT)
-// Check when profile setup is in progress, that no prompt is shown.
-IN_PROC_BROWSER_TEST_F(PrivacySandboxNoticeEntryPointHandlersTest,
-                       NoPromptProfileSetup) {
-  EXPECT_CALL(*mock_view_manager(), HandleChromeOwnedPageNavigation).Times(0);
-  // Show the profile customization dialog.
-  browser()->signin_view_controller()->ShowModalProfileCustomizationDialog(
-      /*is_local_profile_creation=*/true);
-  ASSERT_TRUE(ui_test_utils::NavigateToURLWithDisposition(
-      browser(), GURL(chrome::kChromeUINewTabPageURL),
-      WindowOpenDisposition::NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP));
-
-  Mock::VerifyAndClearExpectations(mock_view_manager());
-}
-#endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
-
 }  // namespace
 }  // namespace privacy_sandbox
diff --git a/chrome/browser/resources/commerce/product_specifications/app.ts b/chrome/browser/resources/commerce/product_specifications/app.ts
index 8779f61c..8ab7ff67 100644
--- a/chrome/browser/resources/commerce/product_specifications/app.ts
+++ b/chrome/browser/resources/commerce/product_specifications/app.ts
@@ -464,10 +464,6 @@
   }
 
   private computeShowComparisonTableList_() {
-    if (!loadTimeData.getBoolean('comparisonTableListEnabled')) {
-      return false;
-    }
-
     return this.showEmptyState_ && this.id_ === null && this.sets_.length > 0 &&
         this.appState_ === AppState.TABLE_EMPTY;
   }
@@ -695,13 +691,7 @@
   }
 
   protected seeAllSets_() {
-    if (loadTimeData.getBoolean('comparisonTableListEnabled')) {
-      this.productSpecificationsProxy_.showComparePage(true);
-      return;
-    }
-
-    OpenWindowProxyImpl.getInstance().openUrl(
-        loadTimeData.getString('productSpecificationsManagementUrl'));
+    this.productSpecificationsProxy_.showComparePage(true);
   }
 
   protected async onUrlAdd_(
@@ -1034,8 +1024,7 @@
 
     // If we show the empty state and there are no comparison tables, try to
     // fetch them.
-    if (loadTimeData.getBoolean('comparisonTableListEnabled') &&
-        this.showEmptyState_ && this.sets_.length === 0) {
+    if (this.showEmptyState_ && this.sets_.length === 0) {
       const {sets} = await this.shoppingApi_.getAllProductSpecificationsSets();
       this.sets_ = sets;
     }
diff --git a/chrome/browser/resources/lens/overlay/side_panel/feedback_toast.ts b/chrome/browser/resources/lens/overlay/side_panel/feedback_toast.ts
index 0346fd3..65089b3b 100644
--- a/chrome/browser/resources/lens/overlay/side_panel/feedback_toast.ts
+++ b/chrome/browser/resources/lens/overlay/side_panel/feedback_toast.ts
@@ -76,6 +76,7 @@
 
   protected onHideFeedbackToastClick() {
     this.hide();
+    this.dispatchEvent(new CustomEvent('feedback-toast-dismissed'));
   }
 }
 
diff --git a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html
index b0802395..1163e0dd 100644
--- a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html
+++ b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html
@@ -222,7 +222,7 @@
 
 <cr-toast id="messageToast" duration="4000">
   <div>[[toastMessage]]</div>
-  <cr-button on-click="onHideMessageToastClick">
+  <cr-button id="messageToastDismissButton" on-click="onHideMessageToastClick">
     $i18n{dismiss}
   </cr-button>
 </cr-toast>
diff --git a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.ts b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.ts
index 69ad781..739fe67 100644
--- a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.ts
+++ b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.ts
@@ -14,6 +14,7 @@
 import {ColorChangeUpdater} from '//resources/cr_components/color_change_listener/colors_css_updater.js';
 import {HelpBubbleMixin} from '//resources/cr_components/help_bubble/help_bubble_mixin.js';
 import type {SearchboxElement} from '//resources/cr_components/searchbox/searchbox.js';
+import type {CrButtonElement} from '//resources/cr_elements/cr_button/cr_button.js';
 import type {CrToastElement} from '//resources/cr_elements/cr_toast/cr_toast.js';
 import {I18nMixin} from '//resources/cr_elements/i18n_mixin.js';
 import {assert} from '//resources/js/assert.js';
@@ -29,7 +30,6 @@
 import {handleEscapeSearchbox} from '../searchbox_utils.js';
 
 import type {FeedbackToastElement} from './feedback_toast.js';
-
 import {PostMessageReceiver} from './post_message_communication.js';
 import {getTemplate} from './side_panel_app.html.js';
 import {SidePanelBrowserProxyImpl} from './side_panel_browser_proxy.js';
@@ -41,11 +41,17 @@
 const VIEWPORT_HEIGHT_KEY = 'bih';
 const VIEWPORT_WIDTH_KEY = 'biw';
 
+// The delay in milliseconds to reshow the feedback toast after it was hidden by
+// another toast. This is only used if the feedback toast was not already
+// dismissed.
+const RESHOW_FEEDBACK_TOAST_DELAY_MS = 4100;
+
 export interface LensSidePanelAppElement {
   $: {
     feedbackToast: FeedbackToastElement,
     ghostLoader: SidePanelGhostLoaderElement,
     messageToast: CrToastElement,
+    messageToastDismissButton: CrButtonElement,
     errorPage: SidePanelErrorPageElement,
     results: HTMLIFrameElement,
     searchbox: SearchboxElement,
@@ -202,6 +208,10 @@
   // window.
   private postMessageReceiver: PostMessageReceiver =
       new PostMessageReceiver(SidePanelBrowserProxyImpl.getInstance());
+  // Whether the feedback toast has been explicitly dismissed by the user.
+  private feedbackToastDismissed = false;
+  // The timeout ID for reshowing the feedback toast.
+  private feedbackToastReshowTimeoutId = -1;
 
   private browserProxy: SidePanelBrowserProxy =
       SidePanelBrowserProxyImpl.getInstance();
@@ -260,6 +270,9 @@
     this.eventTracker_.add(
         document, 'query-autocomplete',
         this.handleQueryAutocomplete.bind(this));
+    this.eventTracker_.add(
+        this.$.feedbackToast, 'feedback-toast-dismissed',
+        () => this.feedbackToastDismissed = true);
 
     // Start listening to postMessages on the window.
     this.postMessageReceiver.listen();
@@ -290,7 +303,9 @@
       // focused.
       this.blurSearchbox();
 
+      clearTimeout(this.feedbackToastReshowTimeoutId);
       this.$.feedbackToast.hide();
+      this.$.messageToast.hide();
     } else {
       // Animate away the progress bar once the results are loaded.
       this.progressBarHideAnimation = this.$.uploadProgressBarContainer.animate(
@@ -307,6 +322,7 @@
 
       // Show the feedback on every result load by showing it as soon as the
       // result load animation is complete.
+      this.feedbackToastDismissed = false;
       this.showFeedbackToast();
     }
   }
@@ -474,6 +490,12 @@
   private async showMessageToast(message: string) {
     this.$.feedbackToast.hide();
     await this.showToast(this.$.messageToast, message);
+    if (!this.feedbackToastDismissed) {
+      clearTimeout(this.feedbackToastReshowTimeoutId);
+      this.feedbackToastReshowTimeoutId = setTimeout(() => {
+        this.showFeedbackToast();
+      }, RESHOW_FEEDBACK_TOAST_DELAY_MS);
+    }
   }
 
   private async showToast(toast: CrToastElement, message?: string) {
@@ -494,6 +516,10 @@
 
   private onHideMessageToastClick() {
     this.$.messageToast.hide();
+    if (!this.feedbackToastDismissed) {
+      clearTimeout(this.feedbackToastReshowTimeoutId);
+      this.showFeedbackToast();
+    }
   }
 
   makeGhostLoaderVisibleForTesting() {
diff --git a/chrome/browser/resources/pdf/elements/viewer_text_bottom_toolbar.css b/chrome/browser/resources/pdf/elements/viewer_text_bottom_toolbar.css
index 85f8c98..3822bdd9 100644
--- a/chrome/browser/resources/pdf/elements/viewer_text_bottom_toolbar.css
+++ b/chrome/browser/resources/pdf/elements/viewer_text_bottom_toolbar.css
@@ -14,6 +14,7 @@
 :host {
   --cr-focus-outline-color: var(--viewer-icon-focus-outline-color);
   border-radius: 16px 16px 0 0;
+  z-index: 2;  /* The text box itself uses 1. Use 2 to layer above the box. */
 }
 
 .md-select {
diff --git a/chrome/browser/safe_browsing/chrome_client_side_detection_host_delegate_unittest.cc b/chrome/browser/safe_browsing/chrome_client_side_detection_host_delegate_browsertest.cc
similarity index 79%
rename from chrome/browser/safe_browsing/chrome_client_side_detection_host_delegate_unittest.cc
rename to chrome/browser/safe_browsing/chrome_client_side_detection_host_delegate_browsertest.cc
index 5eb17ae3..1bc582253 100644
--- a/chrome/browser/safe_browsing/chrome_client_side_detection_host_delegate_unittest.cc
+++ b/chrome/browser/safe_browsing/chrome_client_side_detection_host_delegate_browsertest.cc
@@ -11,20 +11,23 @@
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager_factory.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/test/base/browser_with_test_window_test.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
 #include "components/safe_browsing/content/browser/safe_browsing_navigation_observer.h"
 #include "components/safe_browsing/content/browser/safe_browsing_navigation_observer_manager.h"
 #include "components/safe_browsing/core/common/features.h"
 #include "content/public/browser/global_routing_id.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test.h"
 #include "content/public/test/navigation_simulator.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace safe_browsing {
 
-class ChromeClientSideDetectionHostDelegateTest
-    : public BrowserWithTestWindowTest {
+class ChromeClientSideDetectionHostDelegateTest : public InProcessBrowserTest {
  public:
   ChromeClientSideDetectionHostDelegateTest() = default;
 
@@ -33,23 +36,26 @@
   ChromeClientSideDetectionHostDelegateTest& operator=(
       const ChromeClientSideDetectionHostDelegateTest&) = delete;
 
-  void SetUp() override {
-    BrowserWithTestWindowTest::SetUp();
-    AddTab(browser(), GURL("http://foo/0"));
-    Profile* profile = Profile::FromBrowserContext(
-        browser()->tab_strip_model()->GetWebContentsAt(0)->GetBrowserContext());
+  void SetUpOnMainThread() override {
+    InProcessBrowserTest::SetUpOnMainThread();
+    ASSERT_TRUE(ui_test_utils::NavigateToURLWithDisposition(
+        browser(), GURL("http://foo/0"),
+        WindowOpenDisposition::NEW_FOREGROUND_TAB,
+        ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP));
+    Profile* profile = browser()->profile();
     navigation_observer_manager_ =
         SafeBrowsingNavigationObserverManagerFactory::GetForBrowserContext(
             profile);
+    ASSERT_TRUE(browser()->tab_strip_model()->GetActiveWebContents());
     navigation_observer_ = std::make_unique<SafeBrowsingNavigationObserver>(
-        browser()->tab_strip_model()->GetWebContentsAt(0),
+        browser()->tab_strip_model()->GetActiveWebContents(),
         HostContentSettingsMapFactory::GetForProfile(profile),
         navigation_observer_manager_);
   }
 
-  void TearDown() override {
+  void TearDownOnMainThread() override {
     navigation_observer_.reset();
-    BrowserWithTestWindowTest::TearDown();
+    InProcessBrowserTest::TearDownOnMainThread();
   }
 
   NavigationEventList* navigation_event_list() {
@@ -62,7 +68,8 @@
   std::unique_ptr<SafeBrowsingNavigationObserver> navigation_observer_;
 };
 
-TEST_F(ChromeClientSideDetectionHostDelegateTest, GetReferrerChain) {
+IN_PROC_BROWSER_TEST_F(ChromeClientSideDetectionHostDelegateTest,
+                       GetReferrerChain) {
   base::Time now = base::Time::Now();
   base::Time one_second_ago = base::Time::FromSecondsSinceUnixEpoch(
       now.InSecondsFSinceUnixEpoch() - 1.0);
@@ -86,7 +93,7 @@
 
   std::unique_ptr<ChromeClientSideDetectionHostDelegate> csd_host_delegate =
       std::make_unique<ChromeClientSideDetectionHostDelegate>(
-          browser()->tab_strip_model()->GetWebContentsAt(0));
+          browser()->tab_strip_model()->GetActiveWebContents());
   csd_host_delegate->SetNavigationObserverManagerForTesting(
       navigation_observer_manager_);
   std::unique_ptr<ClientPhishingRequest> verdict(new ClientPhishingRequest);
@@ -100,7 +107,8 @@
   EXPECT_EQ("http://a.com/", referrer_chain[0].referrer_url());
 }
 
-TEST_F(ChromeClientSideDetectionHostDelegateTest, NoNavigationObserverManager) {
+IN_PROC_BROWSER_TEST_F(ChromeClientSideDetectionHostDelegateTest,
+                       NoNavigationObserverManager) {
   base::Time now = base::Time::Now();
   base::Time one_second_ago = base::Time::FromSecondsSinceUnixEpoch(
       now.InSecondsFSinceUnixEpoch() - 1.0);
@@ -115,7 +123,7 @@
 
   std::unique_ptr<ChromeClientSideDetectionHostDelegate> csd_host_delegate =
       std::make_unique<ChromeClientSideDetectionHostDelegate>(
-          browser()->tab_strip_model()->GetWebContentsAt(0));
+          browser()->tab_strip_model()->GetActiveWebContents());
   std::unique_ptr<ClientPhishingRequest> verdict(new ClientPhishingRequest);
   csd_host_delegate->AddReferrerChain(verdict.get(), GURL("http://b.com/"),
                                       content::GlobalRenderFrameHostId());
diff --git a/chrome/browser/support_tool/screenshot_data_collector_browsertest.cc b/chrome/browser/support_tool/screenshot_data_collector_browsertest.cc
index 6df3d20..3662041 100644
--- a/chrome/browser/support_tool/screenshot_data_collector_browsertest.cc
+++ b/chrome/browser/support_tool/screenshot_data_collector_browsertest.cc
@@ -71,7 +71,7 @@
       OpenNewTab(GURL(chrome::kChromeUINewTabPageURL));
 
   // Select `new_page_id` in FakeDesktopMediaPickerFactory.
-  test_flags_.selected_source = new_page_id;
+  test_flags_.picker_result = new_page_id;
   picker_factory.SetTestFlags(&test_flags_, 1);
   data_collector.SetPickerFactoryForTesting(&picker_factory);
 
diff --git a/chrome/browser/ui/android/ephemeraltab/java/src/org/chromium/chrome/browser/ephemeraltab/EphemeralTabSheetContent.java b/chrome/browser/ui/android/ephemeraltab/java/src/org/chromium/chrome/browser/ephemeraltab/EphemeralTabSheetContent.java
index c65d328..d5833b3 100644
--- a/chrome/browser/ui/android/ephemeraltab/java/src/org/chromium/chrome/browser/ephemeraltab/EphemeralTabSheetContent.java
+++ b/chrome/browser/ui/android/ephemeraltab/java/src/org/chromium/chrome/browser/ephemeraltab/EphemeralTabSheetContent.java
@@ -287,8 +287,8 @@
     }
 
     @Override
-    public @Nullable Integer getBackgroundColor() {
-        return null;
+    public boolean hasSolidBackgroundColor() {
+        return false;
     }
 
     @Nullable
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
index 8600099..e54aec7f 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
@@ -934,11 +934,7 @@
 
         if (mAutocompleteInput.getPageClassification() == PageClassification.ANDROID_HUB_VALUE) {
             RecordUserAction.record("HubSearch.KeyboardEnterPressed");
-
-            if (!OmniboxFeatures.sAndroidHubSearchEnterPerformsSearch.getValue()) {
-                // For Hub Search, searching by keyboard typed query is not allowed so do nothing.
-                return;
-            }
+            // For Hub Search, default behavior kicks off search by pressing enter, do not return.
         }
 
         if (mAutocomplete.isPresent()) {
diff --git a/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfUtils.java b/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfUtils.java
index 80ea64a..0506a50 100644
--- a/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfUtils.java
+++ b/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfUtils.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.pdf;
 
+import android.content.ContentResolver;
+import android.content.Context;
 import android.net.Uri;
 import android.os.Build;
 import android.os.ext.SdkExtensions;
@@ -25,6 +27,7 @@
 import org.chromium.content_public.browser.ContentFeatureList;
 import org.chromium.content_public.browser.ContentFeatureMap;
 import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.ui.base.MimeTypeUtils;
 import org.chromium.url.GURL;
 
 import java.io.File;
@@ -333,6 +336,26 @@
         }
     }
 
+    /**
+     * Encode content uri if it is PDF MIME type.
+     *
+     * @param uri The uri to be encoded.
+     * @param context The {@link Context} to retrieve {@link ContentResolver}.
+     * @return the encoded content uri if it is PDF MIME type; or null otherwise.
+     */
+    public static @Nullable String getEncodedContentUri(@Nullable String uri, Context context) {
+        if (TextUtils.isEmpty(uri)
+                || !UrlConstants.CONTENT_SCHEME.equals(Uri.parse(uri).getScheme())) {
+            return null;
+        }
+        ContentResolver contentResolver = context.getContentResolver();
+        String mimeType = contentResolver.getType(Uri.parse(uri));
+        if (MimeTypeUtils.PDF_MIME_TYPE.equals(mimeType)) {
+            return PdfUtils.encodePdfPageUrl(uri);
+        }
+        return null;
+    }
+
     static void recordPdfLoad() {
         RecordHistogram.recordBooleanHistogram("Android.Pdf.DocumentLoad", true);
     }
diff --git a/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfUtilsUnitTest.java b/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfUtilsUnitTest.java
index 27706e3..c578d71b 100644
--- a/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfUtilsUnitTest.java
+++ b/chrome/browser/ui/android/pdf/java/src/org/chromium/chrome/browser/pdf/PdfUtilsUnitTest.java
@@ -4,9 +4,14 @@
 
 package org.chromium.chrome.browser.pdf;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
 
+import android.content.ContentResolver;
+import android.content.Context;
 import android.net.Uri;
+import android.text.TextUtils;
 
 import org.junit.After;
 import org.junit.Assert;
@@ -22,11 +27,14 @@
 import org.chromium.chrome.browser.util.ChromeFileProvider;
 import org.chromium.components.embedder_support.util.UrlConstants;
 import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.ui.base.MimeTypeUtils;
 
 @RunWith(BaseRobolectricTestRunner.class)
 public class PdfUtilsUnitTest {
     @Mock private LoadUrlParams mLoadUrlParams;
     @Mock private NativePage mNativePage;
+    @Mock private Context mContext;
+    @Mock private ContentResolver mContentResolver;
     private AutoCloseable mCloseableMocks;
     private String mPdfPageUrl;
     private String mPdfPageBlobUrl;
@@ -51,6 +59,7 @@
         ChromeFileProvider.setGeneratedUriForTesting(Uri.parse(CONTENT_URL));
         mPdfPageUrl = PdfUtils.encodePdfPageUrl(PDF_LINK);
         mPdfPageBlobUrl = PdfUtils.encodePdfPageUrl(PDF_BLOB_URL);
+        when(mContext.getContentResolver()).thenReturn(mContentResolver);
     }
 
     @After
@@ -233,4 +242,24 @@
         Assert.assertEquals(
                 "The decoded url should match", CONTENT_URL_SPECIAL_CHARACTER, decodedUrl);
     }
+
+    @Test
+    public void testGetEncodedContentUri_PDF() {
+        when(mContentResolver.getType(any())).thenReturn(MimeTypeUtils.PDF_MIME_TYPE);
+        String encodedUrl = PdfUtils.getEncodedContentUri(CONTENT_URL, mContext);
+        Assert.assertFalse("The encoded url should exist", TextUtils.isEmpty(encodedUrl));
+    }
+
+    @Test
+    public void testGetEncodedContentUri_Image() {
+        when(mContentResolver.getType(any())).thenReturn("image/jpeg");
+        String encodedUrl = PdfUtils.getEncodedContentUri(CONTENT_URL, mContext);
+        Assert.assertTrue("The encoded url should not exist", TextUtils.isEmpty(encodedUrl));
+    }
+
+    @Test
+    public void testGetEncodedContentUri_Https() {
+        String encodedUrl = PdfUtils.getEncodedContentUri(PDF_LINK, mContext);
+        Assert.assertTrue("The encoded url should not exist", TextUtils.isEmpty(encodedUrl));
+    }
 }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/MiniOriginBarController.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/MiniOriginBarController.java
index bce4f97..8524c1d 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/MiniOriginBarController.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/MiniOriginBarController.java
@@ -125,6 +125,7 @@
     private FrameLayout.LayoutParams mDefaultLocationBarLayoutParams;
     private final TouchEventObserver mTouchEventObserver;
     private final InsetObserver mInsetObserver;
+    private final BooleanSupplier mIsOmniboxFocusedSupplier;
     private final int mDefaultLocationBarRightPadding;
     // The starting horizontal position of the location bar when the mini origin bar is in its
     // least-minimized state.
@@ -154,7 +155,8 @@
             InsetObserver insetObserver,
             ObservableSupplierImpl<Integer> controlContainerTranslationSupplier,
             ObservableSupplierImpl<Integer> controlContainerHeightSupplier,
-            ObservableSupplier<Boolean> isKeyboardAccessorySheetShowing) {
+            ObservableSupplier<Boolean> isKeyboardAccessorySheetShowing,
+            BooleanSupplier isOmniboxFocusedSupplier) {
         mLocationBar = locationBar;
         mIsFormFieldFocusedSupplier = isFormFieldFocusedSupplier;
         mKeyboardVisibilityDelegate = keyboardVisibilityDelegate;
@@ -165,6 +167,7 @@
         mControlContainerHeightSupplier = controlContainerHeightSupplier;
         mIsKeyboardAccessorySheetShowing = isKeyboardAccessorySheetShowing;
         mInsetObserver = insetObserver;
+        mIsOmniboxFocusedSupplier = isOmniboxFocusedSupplier;
         mDefaultLocationBarRightPadding = mLocationBar.getContainerView().getPaddingRight();
         mDefaultLocationBarLayoutParams =
                 (FrameLayout.LayoutParams) mLocationBar.getContainerView().getLayoutParams();
@@ -193,11 +196,13 @@
                                     : MiniOriginEvent.FORM_FIELD_LOST_FOCUS);
                 };
         mKeyboardVisibilityObserver =
-                (showing) ->
-                        updateMiniOriginBarState(
-                                showing
-                                        ? MiniOriginEvent.KEYBOARD_APPEARED
-                                        : MiniOriginEvent.KEYBOARD_DISAPPEARED);
+                (showing) -> {
+                    if (mIsOmniboxFocusedSupplier.getAsBoolean()) return;
+                    updateMiniOriginBarState(
+                            showing
+                                    ? MiniOriginEvent.KEYBOARD_APPEARED
+                                    : MiniOriginEvent.KEYBOARD_DISAPPEARED);
+                };
 
         mIsFormFieldFocusedSupplier.addObserver(mIsFormFieldFocusedObserver);
         mKeyboardVisibilityDelegate.addKeyboardVisibilityListener(mKeyboardVisibilityObserver);
@@ -341,9 +346,10 @@
     }
 
     private boolean waitingForImeAnimationToStart() {
-        return mMiniOriginBarState == MiniOriginState.READY
-                || mMiniOriginBarState == MiniOriginState.SHOWING
-                || mMiniOriginBarState == MiniOriginState.SUPPRESSED_BY_CLICK;
+        return !mIsOmniboxFocusedSupplier.getAsBoolean()
+                && (mMiniOriginBarState == MiniOriginState.READY
+                        || mMiniOriginBarState == MiniOriginState.SHOWING
+                        || mMiniOriginBarState == MiniOriginState.SUPPRESSED_BY_CLICK);
     }
 
     /**
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/MiniOriginBarControllerTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/MiniOriginBarControllerTest.java
index ee3deebe..45cf4e31 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/MiniOriginBarControllerTest.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/MiniOriginBarControllerTest.java
@@ -50,6 +50,7 @@
 import org.chromium.ui.InsetObserver;
 
 import java.util.Collections;
+import java.util.function.BooleanSupplier;
 
 @RunWith(BaseRobolectricTestRunner.class)
 @Config(manifest = Config.NONE)
@@ -91,6 +92,8 @@
             new WindowInsetsAnimationCompat(WindowInsetsCompat.Type.ime(), null, 160);
     private final WindowInsetsAnimationCompat mNonImeAnimation =
             new WindowInsetsAnimationCompat(WindowInsetsCompat.Type.systemBars(), null, 160);
+    private boolean mOmniboxFocused;
+    private final BooleanSupplier mIsOmniboxFocusedSupplier = () -> mOmniboxFocused;
 
     @Before
     public void setUp() {
@@ -114,7 +117,8 @@
                         mInsetObserver,
                         mControlContainerTranslationSupplier,
                         mControlContainerHeightSupplier,
-                        mIsKeyboardAccessorySheetShowing);
+                        mIsKeyboardAccessorySheetShowing,
+                        mIsOmniboxFocusedSupplier);
     }
 
     @Test
@@ -472,5 +476,21 @@
                 MiniOriginState.SHOWING, mMiniOriginBarController.getCurrentStateForTesting());
     }
 
+    @Test
+    public void testOmniboxFocused() {
+        doReturn(ControlsPosition.BOTTOM).when(mBrowserControlsSizer).getControlsPosition();
+        mMiniOriginBarController.onControlsPositionChanged(ControlsPosition.BOTTOM);
+
+        mIsFormFieldFocused.onNodeAttributeUpdated(true, false);
+        mOmniboxFocused = true;
+
+        final MiniOriginWindowInsetsAnimationListener animationListener =
+                mMiniOriginBarController.getAnimationListenerForTesting();
+
+        animationListener.onPrepare(mImeAnimation);
+        mKeyboardVisibilityDelegate.setVisibilityForTests(true);
+        verify(mLocationBar, never()).setShowOriginOnly(anyBoolean());
+    }
+
     // show again, start, finish showing (predictive back)
 }
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.cc
index 0057efc..823e1f3 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.cc
@@ -51,7 +51,9 @@
       auto_accept_this_tab_capture_(ShouldAutoAcceptThisTabCapture()),
       auto_reject_this_tab_capture_(
           base::CommandLine::ForCurrentProcess()->HasSwitch(
-              switches::kThisTabCaptureAutoReject)) {
+              switches::kThisTabCaptureAutoReject)),
+      auto_reject_capture_(base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kCaptureAutoReject)) {
   DCHECK(dialog_);
   DCHECK(media_list_);
 }
@@ -328,5 +330,5 @@
   if (media_list_->GetMediaListType() == DesktopMediaList::Type::kCurrentTab) {
     return auto_reject_this_tab_capture_;
   }
-  return false;
+  return auto_reject_capture_;
 }
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.h b/chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.h
index eb57d1b..a8375eb 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.h
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.h
@@ -174,6 +174,7 @@
   const std::string auto_select_source_;     // Any source by its title.
   const bool auto_accept_this_tab_capture_;  // Only for current-tab capture.
   const bool auto_reject_this_tab_capture_;  // Only for current-tab capture.
+  const bool auto_reject_capture_;           // Applies to any capture.
 
   base::WeakPtrFactory<DesktopMediaListController> weak_factory_{this};
 };
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
index 94eb50e..de6235a4 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
@@ -14,6 +14,7 @@
 #include "base/functional/callback.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/user_metrics.h"
+#include "base/types/expected.h"
 #include "build/build_config.h"
 #include "chrome/browser/media/webrtc/desktop_media_list.h"
 #include "chrome/browser/media/webrtc/desktop_media_picker_controller.h"
@@ -46,6 +47,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/mojom/dialog_button.mojom.h"
@@ -73,11 +75,12 @@
 #include "chrome/browser/glic/resources/grit/glic_browser_resources.h"
 #endif
 
-using content::DesktopMediaID;
-using content::RenderFrameHost;
-using content::WebContents;
-using content::WebContentsMediaCaptureId;
-using RequestSource = DesktopMediaPicker::Params::RequestSource;
+using ::blink::mojom::MediaStreamRequestResult;
+using ::content::DesktopMediaID;
+using ::content::RenderFrameHost;
+using ::content::WebContents;
+using ::content::WebContentsMediaCaptureId;
+using RequestSource = ::DesktopMediaPicker::Params::RequestSource;
 
 const DesktopMediaSourceViewStyle& GetGenericScreenStyle() {
   static const DesktopMediaSourceViewStyle style(
@@ -406,8 +409,11 @@
       base::BindOnce(
           [](DesktopMediaPickerDialogView* dialog) {
             // If the dialog is being closed then notify the parent about it.
+            // That the parent has not yet been detached indicates that there
+            // has been no result yet. We can infer that the user rejected.
             if (dialog->parent_) {
-              dialog->parent_->NotifyDialogResult(DesktopMediaID());
+              dialog->parent_->NotifyDialogResult(base::unexpected(
+                  MediaStreamRequestResult::PERMISSION_DENIED_BY_USER));
             }
           },
           this));
@@ -1156,7 +1162,10 @@
       new DesktopMediaPickerDialogView(params, this, std::move(source_lists));
 }
 
-void DesktopMediaPickerImpl::NotifyDialogResult(const DesktopMediaID& source) {
+void DesktopMediaPickerImpl::NotifyDialogResult(
+    base::expected<DesktopMediaID, MediaStreamRequestResult> result) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
   // Once this method is called the |dialog_| will close and destroy itself.
   dialog_->DetachParent();
   dialog_ = nullptr;
@@ -1170,7 +1179,7 @@
   // Notify the |callback_| asynchronously because it may need to destroy
   // DesktopMediaPicker.
   content::GetUIThreadTaskRunner({})->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback_), source));
+      FROM_HERE, base::BindOnce(std::move(callback_), result));
 }
 
 // static
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h
index 84ff860..774bd5d 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h
@@ -8,11 +8,13 @@
 #include <string>
 
 #include "base/memory/raw_ptr.h"
+#include "base/types/expected.h"
 #include "build/build_config.h"
 #include "chrome/browser/media/webrtc/desktop_media_picker.h"
 #include "chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.h"
 #include "chrome/browser/ui/views/desktop_capture/desktop_media_pane_view.h"
 #include "chrome/browser/ui/views/desktop_capture/screen_capture_permission_checker.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 #include "ui/base/interaction/element_identifier.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/base/mojom/dialog_button.mojom.h"
@@ -220,7 +222,9 @@
   DesktopMediaPickerImpl& operator=(const DesktopMediaPickerImpl&) = delete;
   ~DesktopMediaPickerImpl() override;
 
-  void NotifyDialogResult(const content::DesktopMediaID& source);
+  void NotifyDialogResult(
+      base::expected<content::DesktopMediaID,
+                     blink::mojom::MediaStreamRequestResult> result);
 
   // DesktopMediaPicker:
   void Show(const DesktopMediaPicker::Params& params,
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_unittest.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_unittest.cc
index 7b16b93..28cce78 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_unittest.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/strings/strcat.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/single_thread_task_runner.h"
+#include "base/types/expected.h"
 #include "build/build_config.h"
 #include "chrome/browser/media/webrtc/desktop_media_picker_controller.h"
 #include "chrome/browser/media/webrtc/desktop_media_picker_manager.h"
@@ -32,6 +33,7 @@
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/mojom/dialog_button.mojom.h"
 #include "ui/base/ui_base_switches.h"
@@ -52,7 +54,12 @@
 #include "base/mac/mac_util.h"
 #endif
 
-using content::DesktopMediaID;
+using ::blink::mojom::MediaStreamRequestResult;
+using ::content::DesktopMediaID;
+
+using PickedIdOrErrorCode =
+    base::expected<content::DesktopMediaID,
+                   blink::mojom::MediaStreamRequestResult>;
 
 namespace views {
 
@@ -181,19 +188,19 @@
     return picker_views_->GetDialogViewForTesting();
   }
 
-  void OnPickerDone(content::DesktopMediaID picked_id) {
-    picked_id_ = picked_id;
+  void OnPickerDone(PickedIdOrErrorCode result) {
+    picker_result_ = result;
     run_loop_.Quit();
   }
 
-  std::optional<content::DesktopMediaID> WaitForPickerDone() {
+  PickedIdOrErrorCode WaitForPickerResult() {
     run_loop_.Run();
-    return picked_id_;
+    CHECK(picker_result_.has_value());
+    return picker_result_.value();
   }
 
-  std::optional<content::DesktopMediaID> picked_id() const {
-    return picked_id_;
-  }
+  // Checks whether `picker_result_` was ever set.
+  bool has_picker_result() const { return picker_result_.has_value(); }
 
   const std::vector<DesktopMediaList::Type>& source_types() {
     return source_types_;
@@ -213,7 +220,7 @@
   std::vector<DesktopMediaList::Type> delegated_source_types_;
 
   base::RunLoop run_loop_;
-  std::optional<content::DesktopMediaID> picked_id_;
+  std::optional<PickedIdOrErrorCode> picker_result_;
   std::unique_ptr<views::test::WidgetDestroyedWaiter> widget_destroyed_waiter_;
 
   base::WeakPtrFactory<DesktopMediaPickerViewsTestBase> weak_factory_{this};
@@ -235,7 +242,9 @@
 
 TEST_P(DesktopMediaPickerViewsTest, DoneCallbackCalledWhenWindowClosed) {
   GetPickerDialogView()->GetWidget()->Close();
-  EXPECT_EQ(content::DesktopMediaID(), WaitForPickerDone());
+  EXPECT_EQ(
+      WaitForPickerResult(),
+      base::unexpected(MediaStreamRequestResult::PERMISSION_DENIED_BY_USER));
 }
 
 TEST_P(DesktopMediaPickerViewsTest, DoneCallbackCalledOnOkButtonPressed) {
@@ -254,7 +263,7 @@
       ui::mojom::DialogButton::kOk));
 
   GetPickerDialogView()->AcceptDialog();
-  EXPECT_EQ(kFakeId, WaitForPickerDone());
+  EXPECT_EQ(kFakeId, WaitForPickerResult());
 }
 
 // Regression test for https://crbug.com/1102153
@@ -269,7 +278,7 @@
   media_lists_[DesktopMediaList::Type::kScreen]->AddSourceByFullMediaID(
       kFakeId);
   test_api_.DoubleTapSourceAtIndex(0);
-  EXPECT_FALSE(picked_id().has_value());
+  EXPECT_FALSE(has_picker_result());
 }
 
 TEST_P(DesktopMediaPickerViewsTest, CancelButtonAlwaysEnabled) {
@@ -365,7 +374,7 @@
   test_api_.FocusSourceAtIndex(0);
 
   GetPickerDialogView()->AcceptDialog();
-  EXPECT_EQ(result_id, WaitForPickerDone());
+  EXPECT_EQ(result_id, WaitForPickerResult());
 }
 
 TEST_P(DesktopMediaPickerViewsTest, OkButtonEnabledDuringAcceptSpecific) {
@@ -386,7 +395,7 @@
       ui::mojom::DialogButton::kOk));
 
   GetPickerDialogView()->AcceptSpecificSource(fake_id);
-  EXPECT_EQ(fake_id, WaitForPickerDone());
+  EXPECT_EQ(fake_id, WaitForPickerResult());
 }
 
 #if BUILDFLAG(IS_MAC)
@@ -617,7 +626,7 @@
   media_lists_[Type()]->AddSourceByFullMediaID(fake_id);
 
   GetPickerDialogView()->AcceptSpecificSource(fake_id);
-  EXPECT_EQ(fake_id, WaitForPickerDone());
+  EXPECT_EQ(fake_id, WaitForPickerResult());
 }
 
 class DesktopMediaPickerViewsSystemAudioTest
@@ -904,7 +913,7 @@
       FROM_HERE, run_loop_.QuitClosure());
   run_loop_.Run();
 
-  EXPECT_FALSE(picked_id().has_value());
+  EXPECT_FALSE(has_picker_result());
 }
 
 // This class expects tests to directly call first SetSourceTypes() and then
@@ -1011,7 +1020,9 @@
   media_lists_[DesktopMediaList::Type::kScreen]
       ->OnDelegatedSourceListDismissed();
 
-  EXPECT_EQ(DesktopMediaID(), WaitForPickerDone());
+  EXPECT_EQ(
+      WaitForPickerResult(),
+      base::unexpected(MediaStreamRequestResult::PERMISSION_DENIED_BY_USER));
 }
 
 // Creates a picker without the default fallback pane and verifies that when it
@@ -1026,8 +1037,9 @@
 
   media_lists_[DesktopMediaList::Type::kScreen]
       ->OnDelegatedSourceListDismissed();
-
-  EXPECT_EQ(DesktopMediaID(), WaitForPickerDone());
+  EXPECT_EQ(
+      WaitForPickerResult(),
+      base::unexpected(MediaStreamRequestResult::PERMISSION_DENIED_BY_USER));
 }
 
 #if BUILDFLAG(IS_MAC)
@@ -1049,7 +1061,9 @@
 
   // Dismissing the delegated source list should close the picker
   // without a selection.
-  EXPECT_EQ(content::DesktopMediaID(), WaitForPickerDone());
+  EXPECT_EQ(
+      WaitForPickerResult(),
+      base::unexpected(MediaStreamRequestResult::PERMISSION_DENIED_BY_USER));
 }
 
 // The delegated picker experience on MacOS (using SCContentSharingPicker)
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_tab_list_unittest.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_tab_list_unittest.cc
index d9368ecd..60436b2 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_tab_list_unittest.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_tab_list_unittest.cc
@@ -59,7 +59,7 @@
                                          "DesktopMediaPickerDialogView");
 
     picker_views_->Show(picker_params, std::move(source_lists),
-                        base::BindOnce([](content::DesktopMediaID id) {}));
+                        base::DoNothing());
     test_api_.set_picker(picker_views_.get());
 
     tab_list_ =
diff --git a/chrome/browser/ui/views/desktop_capture/share_this_tab_dialog_views.cc b/chrome/browser/ui/views/desktop_capture/share_this_tab_dialog_views.cc
index c47491f5..ae400d3 100644
--- a/chrome/browser/ui/views/desktop_capture/share_this_tab_dialog_views.cc
+++ b/chrome/browser/ui/views/desktop_capture/share_this_tab_dialog_views.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/time/time.h"
+#include "base/types/expected.h"
 #include "build/build_config.h"
 #include "build/config/chromebox_for_meetings/buildflags.h"  // PLATFORM_CFM
 #include "chrome/browser/media/webrtc/desktop_media_list.h"
@@ -30,6 +31,7 @@
 #include "content/public/browser/desktop_media_id.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents_delegate.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/mojom/dialog_button.mojom.h"
@@ -53,6 +55,9 @@
 
 namespace {
 
+using ::blink::mojom::MediaStreamRequestResult;
+using ::content::DesktopMediaID;
+
 constexpr int kTitleTopMargin = 16;
 constexpr gfx::Insets kAudioToggleInsets = gfx::Insets::VH(8, 16);
 constexpr int kAudioToggleChildSpacing = 8;
@@ -129,8 +134,11 @@
       base::BindOnce(
           [](ShareThisTabDialogView* dialog) {
             // If the dialog is being closed then notify the parent about it.
+            // That the parent has not yet been detached indicates that there
+            // has been no result yet. We can infer that the user rejected.
             if (dialog->parent_) {
-              dialog->parent_->NotifyDialogResult(content::DesktopMediaID());
+              dialog->parent_->NotifyDialogResult(base::unexpected(
+                  MediaStreamRequestResult::PERMISSION_DENIED_BY_USER));
             }
           },
           this));
@@ -241,9 +249,8 @@
 
   source_view_->StopRefreshing();
   if (parent_ && web_contents_) {
-    content::DesktopMediaID desktop_media_id(
-        content::DesktopMediaID::TYPE_WEB_CONTENTS,
-        content::DesktopMediaID::kNullId,
+    DesktopMediaID desktop_media_id(
+        DesktopMediaID::TYPE_WEB_CONTENTS, DesktopMediaID::kNullId,
         content::WebContentsMediaCaptureId(
             web_contents_->GetPrimaryMainFrame()
                 ->GetProcess()
@@ -398,7 +405,8 @@
 }
 
 void ShareThisTabMediaPicker::NotifyDialogResult(
-    const content::DesktopMediaID& source) {
+    base::expected<content::DesktopMediaID,
+                   blink::mojom::MediaStreamRequestResult> result) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // Once this method is called the |dialog_| will close and destroy itself.
@@ -414,5 +422,5 @@
   // Notify the |callback_| asynchronously because it may need to destroy
   // DesktopMediaPicker.
   content::GetUIThreadTaskRunner({})->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback_), source));
+      FROM_HERE, base::BindOnce(std::move(callback_), result));
 }
diff --git a/chrome/browser/ui/views/desktop_capture/share_this_tab_dialog_views.h b/chrome/browser/ui/views/desktop_capture/share_this_tab_dialog_views.h
index 4f46c1b..7c89f43 100644
--- a/chrome/browser/ui/views/desktop_capture/share_this_tab_dialog_views.h
+++ b/chrome/browser/ui/views/desktop_capture/share_this_tab_dialog_views.h
@@ -8,9 +8,11 @@
 #include <string>
 
 #include "base/memory/raw_ptr.h"
+#include "base/types/expected.h"
 #include "build/build_config.h"
 #include "chrome/browser/media/webrtc/desktop_media_picker.h"
 #include "chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
 #include "ui/base/interaction/element_identifier.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/controls/button/toggle_button.h"
@@ -86,7 +88,9 @@
   ShareThisTabMediaPicker& operator=(const ShareThisTabMediaPicker&) = delete;
   ~ShareThisTabMediaPicker() override;
 
-  void NotifyDialogResult(const content::DesktopMediaID& source);
+  void NotifyDialogResult(
+      base::expected<content::DesktopMediaID,
+                     blink::mojom::MediaStreamRequestResult> result);
 
   // DesktopMediaPicker:
   void Show(const DesktopMediaPicker::Params& params,
diff --git a/chrome/browser/ui/views/location_bar/lens_overlay_homework_page_action_icon_view.cc b/chrome/browser/ui/views/location_bar/lens_overlay_homework_page_action_icon_view.cc
index c93890f..21f1e6c 100644
--- a/chrome/browser/ui/views/location_bar/lens_overlay_homework_page_action_icon_view.cc
+++ b/chrome/browser/ui/views/location_bar/lens_overlay_homework_page_action_icon_view.cc
@@ -29,6 +29,10 @@
 #include "ui/views/interaction/element_tracker_views.h"
 #include "ui/views/view_class_properties.h"
 
+#if BUILDFLAG(ENABLE_GLIC)
+#include "chrome/browser/glic/glic_enabling.h"
+#endif  // BUILDFLAG(ENABLE_GLIC)
+
 LensOverlayHomeworkPageActionIconView::LensOverlayHomeworkPageActionIconView(
     IconLabelBubbleView::Delegate* parent_delegate,
     Delegate* delegate,
@@ -80,6 +84,14 @@
     return false;
   }
 
+#if BUILDFLAG(ENABLE_GLIC)
+  if (lens::features::IsLensOverlayEduActionChipDisabledByGlic() &&
+      glic::GlicEnabling::IsEligibleForGlicTieredRollout(
+          browser_->GetProfile())) {
+    return false;
+  }
+#endif  // BUILDFLAG(ENABLE_GLIC)
+
   if (!browser_->GetProfile()->GetPrefs()->GetBoolean(
           omnibox::kShowGoogleLensShortcut)) {
     return false;
diff --git a/chrome/browser/ui/views/toolbar/app_menu.cc b/chrome/browser/ui/views/toolbar/app_menu.cc
index bc911ad..59526cd 100644
--- a/chrome/browser/ui/views/toolbar/app_menu.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu.cc
@@ -1356,8 +1356,12 @@
     }
   }
 
-  auto* browser_view = BrowserView::GetBrowserViewForBrowser(browser_);
-  browser_view->toolbar_button_provider()->GetAppMenuButton()->OnMenuClosed();
+  // This can be called if the app menu was open during browser destruction, at
+  // which point BrowserView may be in the process of being torn down.
+  // Null-check BrowserView to guard against such cases.
+  if (auto* browser_view = BrowserView::GetBrowserViewForBrowser(browser_)) {
+    browser_view->toolbar_button_provider()->GetAppMenuButton()->OnMenuClosed();
+  }
 
   if (bookmark_menu_delegate_.get()) {
     BookmarkMergedSurfaceService* service =
diff --git a/chrome/browser/ui/views/toolbar/app_menu_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/app_menu_interactive_uitest.cc
index e3f814d9..47b8b58 100644
--- a/chrome/browser/ui/views/toolbar/app_menu_interactive_uitest.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu_interactive_uitest.cc
@@ -7,11 +7,13 @@
 #include "base/test/bind.h"
 #include "build/buildflag.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/lifetime/application_lifetime_desktop.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_element_identifiers.h"
 #include "chrome/browser/ui/toolbar/bookmark_sub_menu_model.h"
 #include "chrome/browser/ui/views/toolbar/browser_app_menu_button.h"
+#include "chrome/test/base/ui_test_utils.h"
 #include "chrome/test/interaction/interactive_browser_test.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_model_observer.h"
@@ -303,3 +305,16 @@
       NameSubmenuChild(AppMenuModel::kBookmarksMenuItem, kBNodeMenuId, 9u),
       CheckViewProperty(kBNodeMenuId, &views::MenuItemView::title, u"a"));
 }
+
+using AppMenuInteractiveTest = InteractiveBrowserTest;
+
+IN_PROC_BROWSER_TEST_F(AppMenuInteractiveTest, DoNotCrashOnBrowserClose) {
+  RunTestSequence(
+      // Open the App menu.
+      PressButton(kToolbarAppMenuButtonElementId),
+      // Close all browsers, ensure the browser process does not crash.
+      Do([]() {
+        chrome::CloseAllBrowsers();
+        ui_test_utils::WaitForBrowserToClose();
+      }));
+}
diff --git a/chrome/browser/ui/webui/commerce/product_specifications_ui.cc b/chrome/browser/ui/webui/commerce/product_specifications_ui.cc
index a114d726..af7063af 100644
--- a/chrome/browser/ui/webui/commerce/product_specifications_ui.cc
+++ b/chrome/browser/ui/webui/commerce/product_specifications_ui.cc
@@ -134,14 +134,10 @@
   };
   source->AddLocalizedStrings(kLocalizedStrings);
 
-  source->AddString("productSpecificationsManagementUrl",
-                    kChromeUICompareListsUrl);
   source->AddString("compareLearnMoreUrl", kChromeUICompareLearnMoreUrl);
   source->AddInteger("maxNameLength", kMaxNameLength);
   source->AddInteger("maxTableSize", kMaxTableSize);
 
-  source->AddBoolean("comparisonTableListEnabled", true);
-
   std::string email;
   signin::IdentityManager* identity_manager =
       IdentityManagerFactory::GetForProfile(profile);
diff --git a/chrome/browser/web_applications/isolated_web_apps/key_distribution/iwa_key_distribution_info_provider_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/key_distribution/iwa_key_distribution_info_provider_unittest.cc
index 4d80a05..a4c5628 100644
--- a/chrome/browser/web_applications/isolated_web_apps/key_distribution/iwa_key_distribution_info_provider_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/key_distribution/iwa_key_distribution_info_provider_unittest.cc
@@ -313,10 +313,6 @@
   using ComponentRegistration = component_updater::ComponentRegistration;
 
   void SetUp() override {
-    web_app::IwaKeyDistributionInfoProvider::GetInstance()->SetUp(
-        base::BindRepeating(
-            &component_updater::IwaKeyDistributionComponentInstallerPolicy::
-                QueueOnDemandUpdate));
     auto cus = std::make_unique<
         testing::NiceMock<component_updater::MockComponentUpdateService>>();
     cus_ = cus.get();
@@ -332,8 +328,7 @@
       auto matcher,
       IwaKeyDistributionInfoProvider* key_provider,
       base::OnceClosure task) {
-    bool register_first = GetParam();
-    if (register_first) {
+    if (register_first()) {
       ASSERT_THAT(test::RegisterIwaKeyDistributionComponentAndWaitForLoad(),
                   matcher);
       key_provider->OnMaybeDownloadedComponentDataReady().Post(FROM_HERE,
@@ -346,6 +341,8 @@
     }
   }
 
+  bool register_first() const { return GetParam(); }
+
   base::test::TaskEnvironment& task_environment() { return env_; }
 
   void WillRegisterAndLoadComponent(bool is_preloaded) {
@@ -471,6 +468,11 @@
 
 TEST_P(IwaIwaKeyDistributionInfoProviderReadinessTest,
        PreloadedComponentAndOnMaybeReadyCalledUpdateSuccess) {
+  if (!register_first()) {
+    GTEST_SKIP() << "Disabled until IWA become available outside of "
+                    "non-initial profiles";
+  }
+
   WillRegisterAndLoadComponent(/*is_preloaded=*/true);
   WillRequestOnDemandUpdateWithSuccess();
 
@@ -501,6 +503,11 @@
 
 TEST_P(IwaIwaKeyDistributionInfoProviderReadinessTest,
        PreloadedComponentAndOnMaybeReadyCalledUpdateFails) {
+  if (!register_first()) {
+    GTEST_SKIP() << "Disabled until IWA become available outside of "
+                    "non-initial profiles";
+  }
+
   WillRegisterAndLoadComponent(/*is_preloaded=*/true);
   WillRequestOnDemandUpdateWithoutSuccess();
 
@@ -523,6 +530,11 @@
 
 TEST_P(IwaIwaKeyDistributionInfoProviderReadinessTest,
        PreloadedComponentAndOnMaybeReadyCalledUpdateDelayedSuccess) {
+  if (!register_first()) {
+    GTEST_SKIP() << "Disabled until IWA become available outside of "
+                    "non-initial profiles";
+  }
+
   WillRegisterAndLoadComponent(/*is_preloaded=*/true);
   WillRequestOnDemandUpdateWithSuccess(/*load_delay=*/base::Seconds(30));
 
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index 9458fa4..a7533f02 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1748368508-88655140671c5cad6b34eb5aad5a3f8dfb9c7abf-d08182b0ab799d89612b6f63d505bef7709e69c4.profdata
+chrome-android64-main-1748390213-ccaf8520e13b590d876e94c75464a170cae0cfdd-09299ca336bc81469bbf1d7ce9044c8aaf755bc0.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 683ad0d..8591ebd 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1748375992-89938c148ebb10d16f24dad1bbc2f3bdd729d010-4368a976ba269a508df94a10c67a6bdbdfae4830.profdata
+chrome-mac-arm-main-1748390213-c4347f945a671f33fdbc22138aad8415939adea9-09299ca336bc81469bbf1d7ce9044c8aaf755bc0.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 18eee7e..eb5aba6 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1748368546-c18cfc3887ba2e44120dac714d516a6fdb3fb778-efe97c857f5fec7190a6eb042071b615d70daef1.profdata
+chrome-mac-main-1748390213-6c43742e64b5fd50267e6e45a75da7edaf876004-09299ca336bc81469bbf1d7ce9044c8aaf755bc0.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index 6fe52bf..05049420 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1748368546-b8505c64d06f03abc8bf45d491c6faf003ba2171-efe97c857f5fec7190a6eb042071b615d70daef1.profdata
+chrome-win-arm64-main-1748390213-d2c32cf6045f34f32801c22d74d0baddd3649ea5-09299ca336bc81469bbf1d7ce9044c8aaf755bc0.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 6e5a05a..e632121 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1748336186-ccf2b8b07747c45f782c3149550d8b4f4ebd0701-21a6f9e1f5692d40d1ac97af5f6bd16d12239f36.profdata
+chrome-win32-main-1748368546-8f299642069b3b5b693e632a1da9820609d73839-efe97c857f5fec7190a6eb042071b615d70daef1.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 596296a..d980913 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1748347148-6a52345518edc855e697cbd4d88213dc9a889ea7-f2633b5bd0e5d7b297519c24db7146f02911eaa1.profdata
+chrome-win64-main-1748379548-c617c4f58f09b684b575c498c1114b30e1ae19b2-21369d0a37bf6f7db620dc940a43188af8d820f5.profdata
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 6efda4b..ceb1947 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -629,11 +629,14 @@
 // testing purposes.
 const char kSystemLogUploadFrequency[] = "system-log-upload-frequency";
 
-// This flag makes Chrome auto-accept/reject requests to capture the current
+// These flags make Chrome auto-accept/reject requests to capture the current
 // tab. It should only be used for tests.
 const char kThisTabCaptureAutoAccept[] = "auto-accept-this-tab-capture";
 const char kThisTabCaptureAutoReject[] = "auto-reject-this-tab-capture";
 
+// This flag makes Chrome auto-reject requests capture a tab/window/screen.
+const char kCaptureAutoReject[] = "auto-reject-capture";
+
 // Custom delay for memory log. This should be used only for testing purpose.
 const char kTestMemoryLogDelayInMinutes[] = "test-memory-log-delay-in-minutes";
 
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 1323398..1afb66b 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -56,6 +56,7 @@
 extern const char kAutoSelectWindowCaptureSourceByTitle[];
 extern const char kBrowserSigninAutoAccept[];
 extern const char kBypassAccountAlreadyUsedByAnotherProfileCheck[];
+extern const char kCaptureAutoReject[];
 extern const char kCheckForUpdateIntervalSec[];
 extern const char kCipherSuiteBlacklist[];
 extern const char kCrashOnHangThreads[];
diff --git a/chrome/common/extensions/api/api_sources.gni b/chrome/common/extensions/api/api_sources.gni
index d79675ef..d8a7924 100644
--- a/chrome/common/extensions/api/api_sources.gni
+++ b/chrome/common/extensions/api/api_sources.gni
@@ -20,7 +20,9 @@
   "identity.idl",
   "notifications.idl",
   "scripting.idl",
+  "tabs.json",
   "webstore_private.json",
+  "windows.json",
 ]
 
 # Schemas that should be used only to auto-generate the C++ types.
@@ -35,13 +37,6 @@
 # Some APIs (e.g. cookies) rely on types and headers from other APIs.
 types_only_schema_sources_ = []
 
-if (enable_desktop_android_extensions) {
-  types_only_schema_sources_ += [
-    "tabs.json",
-    "windows.json",
-  ]
-}
-
 if (enable_extensions) {
   schema_sources_ += [
     "accessibility_features.json",
@@ -81,7 +76,6 @@
     "system_private.json",
     "tab_capture.idl",
     "tab_groups.json",
-    "tabs.json",
     "web_authentication_proxy.idl",
     "web_navigation.json",
 
@@ -90,8 +84,6 @@
     "webrtc_audio_private.idl",
     "webrtc_desktop_capture_private.idl",
     "webrtc_logging_private.idl",
-
-    "windows.json",
   ]
 
   if (!is_android) {
diff --git a/chrome/common/request_header_integrity/BUILD.gn b/chrome/common/request_header_integrity/BUILD.gn
index 6ae583d..dc06a76 100644
--- a/chrome/common/request_header_integrity/BUILD.gn
+++ b/chrome/common/request_header_integrity/BUILD.gn
@@ -49,6 +49,7 @@
     "//components/google/core/common",
     "//google_apis",
     "//services/network/public/cpp",
+    "//services/network/public/mojom",
     "//third_party/blink/public/common:headers",
   ]
 }
diff --git a/chrome/common/request_header_integrity/request_header_integrity_url_loader_throttle.cc b/chrome/common/request_header_integrity/request_header_integrity_url_loader_throttle.cc
index 495d17c..37536f3 100644
--- a/chrome/common/request_header_integrity/request_header_integrity_url_loader_throttle.cc
+++ b/chrome/common/request_header_integrity/request_header_integrity_url_loader_throttle.cc
@@ -18,6 +18,7 @@
 #include "components/google/core/common/google_util.h"
 #include "google_apis/google_api_keys.h"
 #include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/mojom/network_context.mojom.h"
 
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/common/request_header_integrity/internal/google_header_names.h"
@@ -87,11 +88,14 @@
           google_apis::GetAPIKey() + embedder_support::GetUserAgent())));
   const std::string channel_name = GetChannelName();
   if (!channel_name.empty()) {
-    request->headers.SetHeader(CHANNEL_NAME_HEADER_NAME, channel_name);
+    request->cors_exempt_headers.SetHeader(CHANNEL_NAME_HEADER_NAME,
+                                           channel_name);
   }
-  request->headers.SetHeader(LASTCHANGE_YEAR_HEADER_NAME, LASTCHANGE_YEAR);
-  request->headers.SetHeader(VALIDATE_HEADER_NAME, digest);
-  request->headers.SetHeader(COPYRIGHT_HEADER_NAME, CHROME_COPYRIGHT);
+  request->cors_exempt_headers.SetHeader(LASTCHANGE_YEAR_HEADER_NAME,
+                                         LASTCHANGE_YEAR);
+  request->cors_exempt_headers.SetHeader(VALIDATE_HEADER_NAME, digest);
+  request->cors_exempt_headers.SetHeader(COPYRIGHT_HEADER_NAME,
+                                         CHROME_COPYRIGHT);
 }
 
 // static
@@ -99,4 +103,13 @@
   return base::FeatureList::IsEnabled(kRequestHeaderIntegrity);
 }
 
+// static
+void RequestHeaderIntegrityURLLoaderThrottle::UpdateCorsExemptHeaders(
+    network::mojom::NetworkContextParams* params) {
+  params->cors_exempt_header_list.push_back(CHANNEL_NAME_HEADER_NAME);
+  params->cors_exempt_header_list.push_back(LASTCHANGE_YEAR_HEADER_NAME);
+  params->cors_exempt_header_list.push_back(VALIDATE_HEADER_NAME);
+  params->cors_exempt_header_list.push_back(COPYRIGHT_HEADER_NAME);
+}
+
 }  // namespace request_header_integrity
diff --git a/chrome/common/request_header_integrity/request_header_integrity_url_loader_throttle.h b/chrome/common/request_header_integrity/request_header_integrity_url_loader_throttle.h
index 71068da..90c92c1 100644
--- a/chrome/common/request_header_integrity/request_header_integrity_url_loader_throttle.h
+++ b/chrome/common/request_header_integrity/request_header_integrity_url_loader_throttle.h
@@ -7,6 +7,10 @@
 
 #include "third_party/blink/public/common/loader/url_loader_throttle.h"
 
+namespace network::mojom {
+class NetworkContextParams;
+}
+
 namespace request_header_integrity {
 
 class RequestHeaderIntegrityURLLoaderThrottle
@@ -25,6 +29,8 @@
                         bool* defer) override;
 
   static bool IsFeatureEnabled();
+  static void UpdateCorsExemptHeaders(
+      network::mojom::NetworkContextParams* params);
 };
 
 }  // namespace request_header_integrity
diff --git a/chrome/common/request_header_integrity/request_header_integrity_url_loader_throttle_unittest.cc b/chrome/common/request_header_integrity/request_header_integrity_url_loader_throttle_unittest.cc
index 57aa49d..a7f8261 100644
--- a/chrome/common/request_header_integrity/request_header_integrity_url_loader_throttle_unittest.cc
+++ b/chrome/common/request_header_integrity/request_header_integrity_url_loader_throttle_unittest.cc
@@ -48,10 +48,10 @@
   network::ResourceRequest request;
   request.url = GURL("https://www.somesite.com/");
 
-  ASSERT_TRUE(request.headers.IsEmpty());
+  ASSERT_TRUE(request.cors_exempt_headers.IsEmpty());
   bool ignored;
   throttle().WillStartRequest(&request, &ignored);
-  EXPECT_TRUE(request.headers.IsEmpty());
+  EXPECT_TRUE(request.cors_exempt_headers.IsEmpty());
 }
 
 #if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
@@ -59,10 +59,10 @@
   network::ResourceRequest request;
   request.url = GURL("https://www.google.com/");
 
-  ASSERT_TRUE(request.headers.IsEmpty());
+  ASSERT_TRUE(request.cors_exempt_headers.IsEmpty());
   bool ignored;
   throttle().WillStartRequest(&request, &ignored);
-  EXPECT_EQ(3u, request.headers.GetHeaderVector().size());
+  EXPECT_EQ(3u, request.cors_exempt_headers.GetHeaderVector().size());
 }
 #endif  // !BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
@@ -79,15 +79,16 @@
   network::ResourceRequest request;
   request.url = GURL("https://www.google.com/");
 
-  ASSERT_TRUE(request.headers.IsEmpty());
+  ASSERT_TRUE(request.cors_exempt_headers.IsEmpty());
   bool ignored;
   throttle().WillStartRequest(&request, &ignored);
-  EXPECT_EQ(4u, request.headers.GetHeaderVector().size());
-  EXPECT_TRUE(request.headers.HasHeader(CHANNEL_NAME_HEADER_NAME));
-  EXPECT_TRUE(request.headers.HasHeader(LASTCHANGE_YEAR_HEADER_NAME));
-  EXPECT_TRUE(request.headers.HasHeader(VALIDATE_HEADER_NAME));
+  EXPECT_EQ(4u, request.cors_exempt_headers.GetHeaderVector().size());
+  EXPECT_TRUE(request.cors_exempt_headers.HasHeader(CHANNEL_NAME_HEADER_NAME));
+  EXPECT_TRUE(
+      request.cors_exempt_headers.HasHeader(LASTCHANGE_YEAR_HEADER_NAME));
+  EXPECT_TRUE(request.cors_exempt_headers.HasHeader(VALIDATE_HEADER_NAME));
   const std::optional<std::string> copyright =
-      request.headers.GetHeader(COPYRIGHT_HEADER_NAME);
+      request.cors_exempt_headers.GetHeader(COPYRIGHT_HEADER_NAME);
   ASSERT_TRUE(copyright.has_value());
   EXPECT_NE(copyright->find("Copyright"), std::string::npos);
 }
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn
index 14717902..e4537f6 100644
--- a/chrome/renderer/BUILD.gn
+++ b/chrome/renderer/BUILD.gn
@@ -5,6 +5,7 @@
 import("//build/config/buildflags_paint_preview.gni")
 import("//build/config/features.gni")
 import("//chrome/common/features.gni")
+import("//chrome/common/request_header_integrity/buildflags.gni")
 import("//components/nacl/features.gni")
 import("//components/offline_pages/buildflags/features.gni")
 import("//components/optimization_guide/features.gni")
@@ -138,6 +139,7 @@
     "//chrome/common",
     "//chrome/common:mojo_bindings",
     "//chrome/common/net",
+    "//chrome/common/request_header_integrity:buildflags",
     "//chrome/common/search:mojo_bindings",
     "//chrome/services/speech/buildflags",
     "//components/autofill/content/renderer",
@@ -296,6 +298,10 @@
     ]
   }
 
+  if (enable_request_header_integrity) {
+    deps += [ "//chrome/common/request_header_integrity" ]
+  }
+
   if (enable_widevine_cdm_component) {
     deps += [ "//third_party/widevine/cdm:headers" ]
   }
diff --git a/chrome/renderer/url_loader_throttle_provider_impl.cc b/chrome/renderer/url_loader_throttle_provider_impl.cc
index 0ed2c94..8a15ac9b1 100644
--- a/chrome/renderer/url_loader_throttle_provider_impl.cc
+++ b/chrome/renderer/url_loader_throttle_provider_impl.cc
@@ -14,6 +14,7 @@
 #include "base/task/sequenced_task_runner.h"
 #include "build/build_config.h"
 #include "chrome/common/google_url_loader_throttle.h"
+#include "chrome/common/request_header_integrity/buildflags.h"
 #include "chrome/renderer/chrome_content_renderer_client.h"
 #include "chrome/renderer/chrome_render_frame_observer.h"
 #include "chrome/renderer/chrome_render_thread_observer.h"
@@ -44,6 +45,10 @@
 #include "extensions/renderer/extension_throttle_manager.h"
 #endif
 
+#if BUILDFLAG(ENABLE_REQUEST_HEADER_INTEGRITY)
+#include "chrome/common/request_header_integrity/request_header_integrity_url_loader_throttle.h"  // nogncheck crbug.com/1125897
+#endif
+
 #if BUILDFLAG(IS_CHROMEOS)
 #include "chrome/renderer/ash_merge_session_loader_throttle.h"
 #endif  // BUILDFLAG(IS_CHROMEOS)
@@ -286,6 +291,15 @@
           ->chromeos_listener()));
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
+#if BUILDFLAG(ENABLE_REQUEST_HEADER_INTEGRITY)
+  if (request_header_integrity::RequestHeaderIntegrityURLLoaderThrottle::
+          IsFeatureEnabled()) {
+    throttles.push_back(
+        std::make_unique<request_header_integrity::
+                             RequestHeaderIntegrityURLLoaderThrottle>());
+  }
+#endif
+
   if (local_frame_token.has_value()) {
     auto throttle =
         content::MaybeCreateIdentityUrlLoaderThrottle(base::BindRepeating(
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 31762ce..2681b04 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -5452,6 +5452,7 @@
     }
     if (safe_browsing_mode == 1) {
       sources += [
+        "../browser/safe_browsing/chrome_client_side_detection_host_delegate_browsertest.cc",
         "../browser/safe_browsing/chrome_password_protection_service_browsertest.cc",
         "../browser/safe_browsing/chrome_password_protection_service_sync_browsertest.cc",
         "../browser/safe_browsing/client_side_detection_host_browsertest.cc",
@@ -9601,7 +9602,6 @@
     # TODO(sgurun): enable tests for safe_browsing==2.
     sources += [
       "../browser/safe_browsing/advanced_protection_status_manager_desktop_unittest.cc",
-      "../browser/safe_browsing/chrome_client_side_detection_host_delegate_unittest.cc",
       "../browser/safe_browsing/chrome_password_reuse_detection_manager_client_unittest.cc",
       "../browser/safe_browsing/chrome_ping_manager_factory_unittest.cc",
       "../browser/safe_browsing/client_side_detection_host_unittest.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherStation.java
index d50d478..85eb872 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherStation.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/hub/TabSwitcherStation.java
@@ -36,7 +36,6 @@
 import org.chromium.chrome.test.transit.page.PageStation;
 import org.chromium.chrome.test.transit.tabmodel.TabCountChangedCondition;
 import org.chromium.chrome.test.util.TabBinningUtil;
-import org.chromium.components.omnibox.OmniboxFeatures;
 
 import java.util.List;
 
@@ -72,22 +71,20 @@
 
         newTabButtonElement =
                 declareView(toolbarElement.descendant(withId(R.id.toolbar_action_button)));
-        if (OmniboxFeatures.sAndroidHubSearch.isEnabled()) {
-            declareElementFactory(
-                    mActivityElement,
-                    delayedElements -> {
-                        Matcher<View> searchBox = withId(R.id.search_box);
-                        ViewSpec<View> searchLoupe =
-                                toolbarElement.descendant(withId(R.id.search_loupe));
-                        if (shouldHubSearchBoxBeVisible()) {
-                            searchElement = delayedElements.declareView(searchLoupe);
-                            delayedElements.declareNoView(searchBox);
-                        } else {
-                            searchElement = delayedElements.declareView(searchBox);
-                            delayedElements.declareNoView(searchLoupe);
-                        }
-                    });
-        }
+        declareElementFactory(
+                mActivityElement,
+                delayedElements -> {
+                    Matcher<View> searchBox = withId(R.id.search_box);
+                    ViewSpec<View> searchLoupe =
+                            toolbarElement.descendant(withId(R.id.search_loupe));
+                    if (shouldHubSearchBoxBeVisible()) {
+                        searchElement = delayedElements.declareView(searchLoupe);
+                        delayedElements.declareNoView(searchBox);
+                    } else {
+                        searchElement = delayedElements.declareView(searchBox);
+                        delayedElements.declareNoView(searchLoupe);
+                    }
+                });
         recyclerViewElement =
                 declareView(
                         paneHostElement.descendant(
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/MvtsFacility.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/MvtsFacility.java
index 2e1c58f..0a7b072 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/MvtsFacility.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/MvtsFacility.java
@@ -55,7 +55,8 @@
         tilesLayoutElement =
                 declareView(withId(R.id.mv_tiles_layout), ViewElement.displayingAtLeastOption(1));
         declareEnterCondition(
-                new ViewHasChildrenCountCondition(tilesLayoutElement, mSiteSuggestions.size()));
+                new ViewHasChildrenCountCondition(
+                        tilesLayoutElement, mSiteSuggestions.size() + mNonTileIndices.size()));
 
         // Will call declareItems()
         super.declareExtraElements();
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/RegularNewTabPageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/RegularNewTabPageStation.java
index b3507d8..21d22a1 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/RegularNewTabPageStation.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/ntp/RegularNewTabPageStation.java
@@ -27,6 +27,7 @@
 import org.chromium.components.omnibox.OmniboxFeatures;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * The New Tab Page screen, with an omnibox, most visited tiles, and the Feed instead of the
@@ -82,9 +83,11 @@
      * @param siteSuggestions the expected SiteSuggestions to be displayed. Use fakes ones for
      *     testing.
      */
-    public MvtsFacility focusOnMvts(List<SiteSuggestion> siteSuggestions) {
+    public MvtsFacility focusOnMvts(
+            List<SiteSuggestion> siteSuggestions, Set<Integer> nonTileIndices) {
         // Assume MVTs are on the screen; if this assumption changes, make sure to scroll to them.
-        return enterFacilitySync(new MvtsFacility(siteSuggestions), /* trigger= */ null);
+        return enterFacilitySync(
+                new MvtsFacility(siteSuggestions, nonTileIndices), /* trigger= */ null);
     }
 
     /** Click the URL bar to enter the Omnibox. */
diff --git a/chrome/test/data/pdf/ink2_manager_test.ts b/chrome/test/data/pdf/ink2_manager_test.ts
index 01bd728..880d095 100644
--- a/chrome/test/data/pdf/ink2_manager_test.ts
+++ b/chrome/test/data/pdf/ink2_manager_test.ts
@@ -9,7 +9,7 @@
 
 import {assertAnnotationBrush, assertDeepEquals, MockDocumentDimensions, setGetAnnotationBrushReply, setUpInkTestContext} from './test_util.js';
 
-const {viewport, mockPlugin, mockWindow} = setUpInkTestContext();
+const {viewport, mockPlugin} = setUpInkTestContext();
 const manager = Ink2Manager.getInstance();
 
 function getTestAnnotation(id: number): TextAnnotation {
@@ -29,7 +29,7 @@
     pageNumber: 0,
     textBoxRect: {
       height: 35,
-      locationX: 20,
+      locationX: 60,
       locationY: 25,
       width: 50,
     },
@@ -51,16 +51,16 @@
 }
 
 // Simulates the way the viewport is rotated from the plugin by setting updated
-// DocumentDimensions. Assumes a non-rotated pageWidth of 80 and pageHeight of
-// 100.
+// DocumentDimensions. Assumes a non-rotated pageWidth of 400 and pageHeight of
+// 500.
 function rotateViewport(orientation: number) {
   const rotatedDocumentDimensions = new MockDocumentDimensions(0, 0);
   // When the plugin notifies the viewport of new dimensions for a rotation,
   // it swaps the width and height if the page is oriented sideways.
   if (orientation === 0 || orientation === 2) {
-    rotatedDocumentDimensions.addPage(80, 100);
+    rotatedDocumentDimensions.addPage(400, 500);
   } else {
-    rotatedDocumentDimensions.addPage(100, 80);
+    rotatedDocumentDimensions.addPage(500, 400);
   }
   rotatedDocumentDimensions.layoutOptions = {
     defaultPageOrientation: orientation,  // 90 degree CCW rotation
@@ -185,7 +185,7 @@
     testAnnotation2.text = 'Goodbye Moon';
     testAnnotation2.textBoxRect = {
       height: 25,
-      locationX: 10,
+      locationX: 60,
       locationY: 65,
       width: 50,
     };
@@ -208,7 +208,7 @@
     // Check that initializing a new annotation in a different location sets
     // a different id.
     let whenInitEvent = eventToPromise('initialize-text-box', testManager);
-    testManager.initializeTextAnnotation({x: 75, y: 20});
+    testManager.initializeTextAnnotation({x: 200, y: 200});
     let initEvent = await whenInitEvent;
     chrome.test.assertEq(2, initEvent.detail.annotation.id);
     chrome.test.assertEq('', initEvent.detail.annotation.text);
@@ -217,13 +217,13 @@
     // Check that the two existing annotations can be activated.
     mockPlugin.clearMessages();
     whenInitEvent = eventToPromise('initialize-text-box', testManager);
-    testManager.initializeTextAnnotation({x: 30, y: 30});
+    testManager.initializeTextAnnotation({x: 120, y: 30});
     initEvent = await whenInitEvent;
     const testAnnotation1ScreenCoords = structuredClone(testAnnotation1);
     // Add page offsets. These are the defaults for the test viewport setup
-    // of a 90x90 page in a 100x100 window.
+    // of a 400x500 page in a 500x500 window.
     testAnnotation1ScreenCoords.textBoxRect.locationX =
-        testAnnotation1.textBoxRect.locationX + 10;
+        testAnnotation1.textBoxRect.locationX + 55;
     testAnnotation1ScreenCoords.textBoxRect.locationY =
         testAnnotation1.textBoxRect.locationY + 3;
     assertDeepEquals(testAnnotation1ScreenCoords, initEvent.detail.annotation);
@@ -231,11 +231,11 @@
 
     mockPlugin.clearMessages();
     whenInitEvent = eventToPromise('initialize-text-box', testManager);
-    testManager.initializeTextAnnotation({x: 30, y: 70});
+    testManager.initializeTextAnnotation({x: 120, y: 70});
     initEvent = await whenInitEvent;
     const testAnnotation2ScreenCoords = structuredClone(testAnnotation2);
     testAnnotation2ScreenCoords.textBoxRect.locationX =
-        testAnnotation2.textBoxRect.locationX + 10;
+        testAnnotation2.textBoxRect.locationX + 55;
     testAnnotation2ScreenCoords.textBoxRect.locationY =
         testAnnotation2.textBoxRect.locationY + 3;
     assertDeepEquals(testAnnotation2ScreenCoords, initEvent.detail.annotation);
@@ -321,11 +321,11 @@
     // Confirm both scrollbars and mock viewport dimensions.
     chrome.test.assertTrue(viewport.documentHasScrollbars().vertical);
     chrome.test.assertTrue(viewport.documentHasScrollbars().horizontal);
-    chrome.test.assertEq(100, viewport.size.width);
-    chrome.test.assertEq(100, viewport.size.height);
+    chrome.test.assertEq(500, viewport.size.width);
+    chrome.test.assertEq(500, viewport.size.height);
     chrome.test.assertFalse(viewport.scrollbarWidth === 0);
 
-    const edge = 100 - viewport.scrollbarWidth;
+    const edge = 500 - viewport.scrollbarWidth;
     Ink2Manager.getInstance().initializeTextAnnotation({x: edge, y: 20});
     chrome.test.assertEq(1, blurEvents);
     Ink2Manager.getInstance().initializeTextAnnotation({x: 20, y: edge});
@@ -341,15 +341,6 @@
   },
 
   async function testInitializeTextboxNoLocation() {
-    // Update the viewport to be sufficiently large to accommodate a default
-    // size textbox for testing.
-    const documentDimensions = new MockDocumentDimensions(0, 0);
-    documentDimensions.addPage(400, 500);
-    viewport.setDocumentDimensions(documentDimensions);
-
-    // Make the viewport window larger.
-    mockWindow.setSize(500, 500);
-
     let whenInitEvent = eventToPromise('initialize-text-box', manager);
     // Initialize without a location. This is what happens when the user creates
     // a textbox by using "Enter" on the plugin, instead of with the mouse.
@@ -417,10 +408,11 @@
     Ink2Manager.getInstance().initializeTextAnnotation();
     initEvent = await whenInitEvent;
 
-    // The default width goes down from 222 to the width of the page, which is
-    // 195 at 0.5 zoom: (pageWidth - 2 * shadow) * zoom = (400 - 2 * 5) * .5.
     chrome.test.assertEq(
         MIN_TEXTBOX_SIZE_PX, initEvent.detail.annotation.textBoxRect.height);
+
+    // The default width goes down from 222 to the width of the page, which is
+    // 195 at 0.5 zoom ( 400 * 0.5 - 2 * shadow ).
     // The page is centered on the viewport in the x direction, so it runs from
     // 152.5 to 347.5. The center is at (152.5 + 347.5) / 2 = 250. Subtract half
     // the default width to get the left edge.
@@ -441,18 +433,11 @@
     // Reset zoom, window size and annotation id for next test.
     viewport.setZoom(1.0);
     manager.resetAnnotationIdForTest();
-    mockWindow.setSize(100, 100);
 
     chrome.test.succeed();
   },
 
   async function testInitializeTextBox() {
-    // Create a new mock document dimensions that has different width from
-    // height. This is relevant for testing different rotations.
-    const documentDimensions = new MockDocumentDimensions(0, 0);
-    documentDimensions.addPage(80, 100);
-    viewport.setDocumentDimensions(documentDimensions);
-
     // Add listeners for the expected events that fire in response to an
     // initializeTextAnnotation call.
     let eventsDispatched: Array<{name: string, detail: any}> = [];
@@ -478,21 +463,20 @@
           MIN_TEXTBOX_SIZE_PX, initData.annotation.textBoxRect.height);
       chrome.test.assertEq(x, initData.annotation.textBoxRect.locationX);
       chrome.test.assertEq(y, initData.annotation.textBoxRect.locationY);
-      // Textbox width gets clamped because the page is small.
       chrome.test.assertEq(
-          rotation % 2 === 0 ? 70 : 90, initData.annotation.textBoxRect.width);
+          DEFAULT_TEXTBOX_WIDTH, initData.annotation.textBoxRect.width);
       chrome.test.assertEq(0, initData.annotation.pageNumber);
       chrome.test.assertEq(id, initData.annotation.id);
       chrome.test.assertEq(rotation, initData.annotation.textOrientation);
-      // Placeholder viewport has a 80x100 page and 100x100 window.
+      // Placeholder viewport has a 400x500 page and 500x500 window.
       // The y offset is always 3px, because the page is always positioned
       // 3px from the top. When the page is oriented vertically, it is centered
       // in the viewport with an additional 5px margin in x, creating pageX =
-      // (100 - 80)/2 + 5 = 15px offset. When the page is oriented horizontally,
-      // it is as wide as the viewport, so it uses the minimum 5px margin for
-      // pageX.
+      // (500 - 400)/2 + 5 = 55px offset. When the page is oriented
+      // horizontally, it is as wide as the viewport, so it uses the minimum
+      // 5px margin for pageX.
       chrome.test.assertEq(
-          rotation % 2 === 0 ? 15 : 5, initData.pageCoordinates.x);
+          rotation % 2 === 0 ? 55 : 5, initData.pageCoordinates.x);
       chrome.test.assertEq(3, initData.pageCoordinates.y);
       chrome.test.assertEq('attributes-changed', eventsDispatched[1]!.name);
       assertDeepEquals(attributes, eventsDispatched[1]!.detail);
@@ -509,13 +493,13 @@
     await verifyTextboxInit(/* x= */ 15, /* y= */ 10, /* rotations= */ 1,
                             /* id= */ 0);
     rotateViewport(/* clockwiseRotations= */ 2);
-    await verifyTextboxInit(/* x= */ 50, /* y= */ 60, /* rotations= */ 2,
+    await verifyTextboxInit(/* x= */ 60, /* y= */ 60, /* rotations= */ 2,
                             /* id= */ 1);
     rotateViewport(/* clockwiseRotations= */ 1);
     await verifyTextboxInit(/* x= */ 80, /* y = */ 20, /* rotations= */ 3,
                             /* id= */ 2);
     rotateViewport(/* clockwiseRotations= */ 0);
-    await verifyTextboxInit(/* x= */ 20, /* y= */ 23, /* rotations= */ 0,
+    await verifyTextboxInit(/* x= */ 200, /* y= */ 23, /* rotations= */ 0,
                             /* id= */ 3);
 
     chrome.test.succeed();
@@ -569,7 +553,7 @@
 
     // Test committing annotations at different rotations to ensure the
     // conversion back to page coordinates works correctly. Note that the
-    // page screen rectangle will be 70x90 since there are 10px of page
+    // page screen rectangle will be 390x490 since there are 10px of page
     // shadow.
 
     // 90 degrees CCW
@@ -579,8 +563,8 @@
     annotationPageCoords.textBoxRect = {
       height: 50,
       width: 35,
-      locationX: 13,
-      locationY: 15,
+      locationX: 333,
+      locationY: 55,
     };
     testCommitAnnotation(annotationScreenCoords, annotationPageCoords);
     // Delete to clear state.
@@ -596,8 +580,8 @@
     annotationPageCoords.textBoxRect = {
       height: 35,
       width: 50,
-      locationX: 15,
-      locationY: 33,
+      locationX: 335,
+      locationY: 433,
     };
     testCommitAnnotation(annotationScreenCoords, annotationPageCoords);
     // Delete to clear state.
@@ -614,7 +598,7 @@
       height: 50,
       width: 35,
       locationX: 22,
-      locationY: 25,
+      locationY: 385,
     };
     testCommitAnnotation(annotationScreenCoords, annotationPageCoords);
     // Delete to clear state.
@@ -652,15 +636,15 @@
 
     const whenUpdateEvent = eventToPromise('initialize-text-box', manager);
     // Click inside the existing text box area.
-    Ink2Manager.getInstance().initializeTextAnnotation({x: 40, y: 40});
+    Ink2Manager.getInstance().initializeTextAnnotation({x: 80, y: 40});
     await whenUpdateEvent;
     chrome.test.assertEq(2, eventsDispatched.length);
     chrome.test.assertEq('initialize-text-box', eventsDispatched[0]!.name);
     const initData = eventsDispatched[0]!.detail as TextBoxInit;
     const testAnnotation = getTestAnnotation(0);
     assertDeepEquals(testAnnotation, initData.annotation);
-    // Still using the 80x100 page from the previous test.
-    chrome.test.assertEq(15, initData.pageCoordinates.x);
+    // Still using the 400x500 page from the previous test.
+    chrome.test.assertEq(55, initData.pageCoordinates.x);
     chrome.test.assertEq(3, initData.pageCoordinates.y);
     chrome.test.assertEq('attributes-changed', eventsDispatched[1]!.name);
     assertDeepEquals(
@@ -678,23 +662,23 @@
     // pageMarginY * zoom = 3 * 1
     chrome.test.assertEq(3, initialParams.pageDimensions.y);
     // (windowWidth - docWidth * zoom)/2 + pageMarginX * zoom =
-    // (100 - 80 * 1)/2 + 5 * 1
-    chrome.test.assertEq(15, initialParams.pageDimensions.x);
+    // (500 - 400 * 1)/2 + 5 * 1
+    chrome.test.assertEq(55, initialParams.pageDimensions.x);
     // 10px of width are taken up by PAGE_SHADOW.
-    chrome.test.assertEq(70, initialParams.pageDimensions.width);
+    chrome.test.assertEq(390, initialParams.pageDimensions.width);
     // 20px of height are also taken up by PAGE_SHADOW.
-    chrome.test.assertEq(90, initialParams.pageDimensions.height);
+    chrome.test.assertEq(490, initialParams.pageDimensions.height);
     chrome.test.assertEq(0, initialParams.clockwiseRotations);
 
     // In this new layout, the existing 50x35 annotation at page coordinate
-    // 5, 22 has its top left corner at 20, 25 in screen coordinates. Make
+    // 5, 22 has its top left corner at 60, 25 in screen coordinates. Make
     // sure clicking there creates the box, and clicking just outside of this
     // does not.
     mockPlugin.clearMessages();
-    Ink2Manager.getInstance().initializeTextAnnotation({x: 20, y: 25});
+    Ink2Manager.getInstance().initializeTextAnnotation({x: 60, y: 25});
     verifyStartTextAnnotationMessage(true);
     mockPlugin.clearMessages();
-    Ink2Manager.getInstance().initializeTextAnnotation({x: 19, y: 24});
+    Ink2Manager.getInstance().initializeTextAnnotation({x: 59, y: 24});
     verifyStartTextAnnotationMessage(false);
 
     // Zoom out should fire an event.
@@ -705,19 +689,19 @@
     // pageMarginY * zoom = 3 * .5
     chrome.test.assertEq(1.5, changedEvent.detail.pageDimensions.y);
     // (windowWidth - docWidth * zoom)/2 + pageMarginX * zoom =
-    // (100 - 80 * .5)/2 + 5 * .5
-    chrome.test.assertEq(32.5, changedEvent.detail.pageDimensions.x);
-    chrome.test.assertEq(35, changedEvent.detail.pageDimensions.width);
-    chrome.test.assertEq(45, changedEvent.detail.pageDimensions.height);
+    // (500 - 400 * .5)/2 + 5 * .5
+    chrome.test.assertEq(152.5, changedEvent.detail.pageDimensions.x);
+    chrome.test.assertEq(195, changedEvent.detail.pageDimensions.width);
+    chrome.test.assertEq(245, changedEvent.detail.pageDimensions.height);
     chrome.test.assertEq(0, changedEvent.detail.clockwiseRotations);
 
     // In this new layout, the existing 50x35 annotation at page coordinate
-    // 5, 22 has its top left corner at 35, 12.5 in screen coordinates.
+    // 5, 22 has its top left corner at 155, 12.5 in screen coordinates.
     mockPlugin.clearMessages();
-    Ink2Manager.getInstance().initializeTextAnnotation({x: 35, y: 13});
+    Ink2Manager.getInstance().initializeTextAnnotation({x: 155, y: 13});
     verifyStartTextAnnotationMessage(true);
     mockPlugin.clearMessages();
-    Ink2Manager.getInstance().initializeTextAnnotation({x: 34, y: 12});
+    Ink2Manager.getInstance().initializeTextAnnotation({x: 154, y: 12});
     verifyStartTextAnnotationMessage(false);
 
     // Zoom in should fire an event.
@@ -729,8 +713,8 @@
     chrome.test.assertEq(6, changedEvent.detail.pageDimensions.y);
     // docWidth * zoom > windowWidth, so this is now pageMarginX * zoom = 5 * 2
     chrome.test.assertEq(10, changedEvent.detail.pageDimensions.x);
-    chrome.test.assertEq(140, changedEvent.detail.pageDimensions.width);
-    chrome.test.assertEq(180, changedEvent.detail.pageDimensions.height);
+    chrome.test.assertEq(780, changedEvent.detail.pageDimensions.width);
+    chrome.test.assertEq(980, changedEvent.detail.pageDimensions.height);
     chrome.test.assertEq(0, changedEvent.detail.clockwiseRotations);
 
     // In this new layout, the existing 50x35 annotation at page coordinate
@@ -751,8 +735,8 @@
     chrome.test.assertEq(-34, changedEvent.detail.pageDimensions.y);
     // Shifts by -20 * zoom = -40 from previous position.
     chrome.test.assertEq(-30, changedEvent.detail.pageDimensions.x);
-    chrome.test.assertEq(140, changedEvent.detail.pageDimensions.width);
-    chrome.test.assertEq(180, changedEvent.detail.pageDimensions.height);
+    chrome.test.assertEq(780, changedEvent.detail.pageDimensions.width);
+    chrome.test.assertEq(980, changedEvent.detail.pageDimensions.height);
     chrome.test.assertEq(0, changedEvent.detail.clockwiseRotations);
 
     // In this new layout, the existing 50x35 annotation at page coordinate
@@ -774,20 +758,22 @@
     chrome.test.assertEq(-34, changedEvent.detail.pageDimensions.y);
     chrome.test.assertEq(-30, changedEvent.detail.pageDimensions.x);
     // Width and height are switched.
-    chrome.test.assertEq(180, changedEvent.detail.pageDimensions.width);
-    chrome.test.assertEq(140, changedEvent.detail.pageDimensions.height);
+    chrome.test.assertEq(980, changedEvent.detail.pageDimensions.width);
+    chrome.test.assertEq(780, changedEvent.detail.pageDimensions.height);
     // Rotations now non-zero.
     chrome.test.assertEq(3, changedEvent.detail.clockwiseRotations);
 
     // In this new layout, the existing 50x35 annotation at page coordinate
-    // 5, 22 has its top left corner at 14, -4 in screen coordinates.
-    // It has width 70 and height 100 so (85, 0) should be just outside the box
-    // and (84, 0) just inside.
+    // 5, 22 has its top left corner at 14, 636 in screen coordinates. This
+    // is outside the viewport, which is only 500px tall. Scroll down by 200, or
+    // 100 more in page coordinates, to put the box at 14, 436 so it can be
+    // activated.
+    viewport.goToPageAndXy(0, 20, 120);
     mockPlugin.clearMessages();
-    Ink2Manager.getInstance().initializeTextAnnotation({x: 84, y: 0});
+    Ink2Manager.getInstance().initializeTextAnnotation({x: 84, y: 436});
     verifyStartTextAnnotationMessage(true);
     mockPlugin.clearMessages();
-    Ink2Manager.getInstance().initializeTextAnnotation({x: 85, y: 0});
+    Ink2Manager.getInstance().initializeTextAnnotation({x: 85, y: 436});
     verifyStartTextAnnotationMessage(false);
 
     chrome.test.succeed();
@@ -799,11 +785,11 @@
     rotateViewport(/* clockwiseRotations= */ 0);  // 0 rotation.
     viewport.goToPageAndXy(0, 0, 0);
 
-    // Simulate creating a textbox at (55, 50) (near center of the viewport).
-    manager.initializeTextAnnotation({x: 55, y: 50});
+    // Simulate creating a textbox at (255, 250) (near center of the viewport).
+    manager.initializeTextAnnotation({x: 255, y: 250});
 
     // Zoom by 2x. This would cause the textbox to be out of the view, at
-    // location 110, 100.
+    // location 510, 500.
     viewport.setZoom(2.0);
 
     mockPlugin.clearMessages();
@@ -812,8 +798,8 @@
     // there). Make sure the manager sends a message to the plugin to scroll
     // the viewport to the textbox.
     manager.textBoxFocused({
-      locationX: 110,
-      locationY: 100,
+      locationX: 510,
+      locationY: 500,
       height: 50,
       width: 50,
     });
@@ -821,17 +807,17 @@
     let syncScrollMessage = mockPlugin.findMessage('syncScrollToRemote');
     chrome.test.assertTrue(syncScrollMessage !== undefined);
     chrome.test.assertEq('syncScrollToRemote', syncScrollMessage.type);
-    // The content is 160x200 (2x page size), and the viewport is 100x100. The
+    // The content is 800x1000 (2x page size), and the viewport is 500x500. The
     // scrollbar is 5px wide.
     // Max scroll is contentSize - viewportSize + scrollbarWidth.
-    // The max scroll is therefore 160 - 100 + 5 = 65 horizontally, so in the x
-    // direction scroll is clamped at 65, which is less than the desired scroll
-    // of 110 - .1 * viewportWidth = 100.
-    // Vertically, the desired y position is 100 - .1 * viewportHeight = 90,
+    // The max scroll is therefore 800 - 500 + 5 = 305 horizontally, so in the x
+    // direction scroll is clamped at 305, which is less than the desired scroll
+    // of 510 - .1 * viewportWidth = 460.
+    // Vertically, the desired y position is 500 - .1 * viewportHeight = 450,
     // which is within the max scroll of
-    // contentWidth - viewportWidth + scrollbarWidth = 105.
-    chrome.test.assertEq(65, syncScrollMessage.x);
-    chrome.test.assertEq(90, syncScrollMessage.y);
+    // contentHeight - viewportHeight + scrollbarWidth = 505.
+    chrome.test.assertEq(305, syncScrollMessage.x);
+    chrome.test.assertEq(450, syncScrollMessage.y);
 
     // Focusing a textbox that is already in the view shouldn't scroll the
     // viewport.
@@ -855,11 +841,12 @@
     syncScrollMessage = mockPlugin.findMessage('syncScrollToRemote');
     chrome.test.assertTrue(syncScrollMessage !== undefined);
     chrome.test.assertEq('syncScrollToRemote', syncScrollMessage.type);
-    // Scroll x to maxScrollWidth - 20 - .1 * viewportWidth = 65 - 20 - 10 = 35.
-    // Scroll y to maxScrollHeight - 10 - .1 * viewportHeight =
-    // 90 - 10 - 10 = 70.
-    chrome.test.assertEq(35, syncScrollMessage.x);
-    chrome.test.assertEq(70, syncScrollMessage.y);
+    // Scroll x to maxScrollWidth - 20 - .1 * viewportWidth = 305 - 20 - 50 =
+    // 235.
+    // Scroll y to currentScrollY - 10 - .1 * viewportHeight =
+    // 450 - 10 - 50 = 390.
+    chrome.test.assertEq(235, syncScrollMessage.x);
+    chrome.test.assertEq(390, syncScrollMessage.y);
 
     chrome.test.succeed();
   },
diff --git a/chrome/test/data/pdf/ink2_text_box_test.ts b/chrome/test/data/pdf/ink2_text_box_test.ts
index 4f48c26..a1daa3c 100644
--- a/chrome/test/data/pdf/ink2_text_box_test.ts
+++ b/chrome/test/data/pdf/ink2_text_box_test.ts
@@ -819,9 +819,9 @@
 
   async function testEscapeAndDelete() {
     viewport.setZoom(1.0);
-    // Initialize to a 100x100 box at 10, 10. Place the box in the top corner
+    // Initialize to a 100x100 box at 55, 10. Place the box in the top corner
     // of the page, so that the viewport won't scroll when it is focused.
-    initializeBox(100, 100, 10, 10);
+    initializeBox(100, 100, 55, 10);
     // Wait for focus to happen so that we can correctly test focus changes
     // later.
     await eventToPromise('textbox-focused-for-test', textbox);
@@ -862,7 +862,7 @@
 
     // If the user is dragging, escape commits the annotation at the start
     // location and hides the box.
-    initializeBox(100, 100, 10, 10);
+    initializeBox(100, 100, 55, 10);
     await microtasksFinished();
     chrome.test.assertTrue(isVisible(textbox));
     mockPlugin.clearMessages();
@@ -884,7 +884,7 @@
     verifyFinishTextAnnotationMessage(testAnnotation);
 
     // Escape without any modification hides the box but doesn't send a message.
-    initializeBox(100, 100, 10, 10);
+    initializeBox(100, 100, 55, 10);
     await microtasksFinished();
     chrome.test.assertTrue(isVisible(textbox));
     mockPlugin.clearMessages();
@@ -895,10 +895,10 @@
     chrome.test.assertEq(
         undefined, mockPlugin.findMessage('setTextAnnotation'));
 
-    // Initialize to a 100x100 box at 10, 10 with some text content. Use
+    // Initialize to a 100x100 box at 55, 10 with some text content. Use
     // "Delete" to clear all the content, which will trigger a message since
     // this is for an existing annotation.
-    initializeBox(100, 100, 10, 10, true);
+    initializeBox(100, 100, 55, 10, true);
     await microtasksFinished();
     chrome.test.assertFalse(textbox.hidden);
     chrome.test.assertTrue(isVisible(textbox));
@@ -999,12 +999,12 @@
 
     // Using manager initialization to get correct coordinates for the zoom
     // level.
-    manager.initializeTextAnnotation({x: 20, y: 20});
+    manager.initializeTextAnnotation({x: 60, y: 60});
     await eventToPromise('textbox-focused-for-test', textbox);
     await microtasksFinished();
     const styles = getComputedStyle(textbox);
-    chrome.test.assertEq('3px', styles.getPropertyValue('left'));
-    chrome.test.assertEq('5px', styles.getPropertyValue('top'));
+    chrome.test.assertEq('43px', styles.getPropertyValue('left'));
+    chrome.test.assertEq('45px', styles.getPropertyValue('top'));
 
     // Scroll away from the textbox. Note this method accepts page coordinates.
     // Scrolling by 35 in page coordinates scrolls by 70 in screen coordinates
@@ -1016,8 +1016,8 @@
     manager.dispatchEvent(new CustomEvent('blur-text-box'));
     viewport.goToPageAndXy(0, 35, 35);
     await microtasksFinished();
-    chrome.test.assertEq('-67px', styles.getPropertyValue('left'));
-    chrome.test.assertEq('-65px', styles.getPropertyValue('top'));
+    chrome.test.assertEq('-27px', styles.getPropertyValue('left'));
+    chrome.test.assertEq('-25px', styles.getPropertyValue('top'));
 
     // Focus the textbox, which should cause the manager to scroll the viewport.
     // This won't actually scroll the viewport in the test, since the plugin
@@ -1027,9 +1027,9 @@
     const syncScrollMessage = mockPlugin.findMessage('syncScrollToRemote');
     chrome.test.assertTrue(syncScrollMessage !== undefined);
     chrome.test.assertEq('syncScrollToRemote', syncScrollMessage.type);
-    // The box is at 20, 20 in viewport coordinates, and the viewport is 100px
+    // The box is at 60, 60 in viewport coordinates, and the viewport is 500px
     // wide. The manager specifies a margin of 10% of the viewport when
-    // scrolling.
+    // scrolling, so both of these end up at 10.
     chrome.test.assertEq(10, syncScrollMessage.x);
     chrome.test.assertEq(10, syncScrollMessage.y);
 
diff --git a/chrome/test/data/pdf/test_util.ts b/chrome/test/data/pdf/test_util.ts
index 7db6411..434ee55 100644
--- a/chrome/test/data/pdf/test_util.ts
+++ b/chrome/test/data/pdf/test_util.ts
@@ -560,26 +560,23 @@
 // Sets up zoomable viewport and a dummy plugin for Ink. This combines the
 // functionality of getZoomableViewport() and setupTestMockPluginForInk(), which
 // are mutually exclusive since they both attempt to call setContent() on the
-// viewport. Returns a reference to the new viewport, plugin and mock window.
-export function setUpInkTestContext(): {
-  viewport: Viewport,
-  mockPlugin: MockPdfPluginElement,
-  mockWindow: MockElement,
-} {
+// viewport. Returns a reference to the new viewport and mock plugin.
+export function setUpInkTestContext():
+    {viewport: Viewport, mockPlugin: MockPdfPluginElement} {
   // Clear the DOM and create dummy content.
   document.body.innerHTML = '';
   const dummyContent = document.createElement('div');
   document.body.appendChild(dummyContent);
 
   // Create the viewport.
-  const mockWindow = new MockElement(100, 100, null);
+  const mockWindow = new MockElement(500, 500, null);
   const mockSizer = new MockSizer();
   const viewport = new Viewport(
       mockWindow as unknown as HTMLElement, mockSizer as unknown as HTMLElement,
       dummyContent, /*scrollbarWidth=*/ 5, /*defaultZoom=*/ 1);
   viewport.setZoomFactorRange([0.25, 0.4, 0.5, 1, 2]);
   const documentDimensions = new MockDocumentDimensions(0, 0);
-  documentDimensions.addPage(90, 90);
+  documentDimensions.addPage(400, 500);
   viewport.setDocumentDimensions(documentDimensions);
 
   // Create mock plugin.
@@ -611,7 +608,7 @@
   // changes. In prod these are piped through the top level pdf-viewer element.
   viewport.setViewportChangedCallback(() => manager.viewportChanged());
 
-  return {viewport, mockPlugin, mockWindow};
+  return {viewport, mockPlugin};
 }
 
 /**
diff --git a/chrome/test/data/webrtc/webrtc_getdisplaymedia_test.html b/chrome/test/data/webrtc/webrtc_getdisplaymedia_test.html
index eec217d..c5f000a 100644
--- a/chrome/test/data/webrtc/webrtc_getdisplaymedia_test.html
+++ b/chrome/test/data/webrtc/webrtc_getdisplaymedia_test.html
@@ -28,7 +28,7 @@
 
   function compareErrors(expectedError) {
     return function(error) {
-      console.log('getUserMedia error: ' + error.name, error);
+      console.log('getDisplayMedia error: ' + error.name, error);
       return logAndReturn(error.toString() == expectedError
           ? "expected-error"
           : "unexpected-error");
@@ -36,7 +36,7 @@
   }
 
   function handleError(error) {
-    console.log('getUserMedia error: ' + error.name, error);
+    console.log('getDisplayMedia error: ' + error.name, error);
     return logAndReturn("capture-failure");
   }
 
diff --git a/chrome/test/data/webui/commerce/product_specifications/app_test.ts b/chrome/test/data/webui/commerce/product_specifications/app_test.ts
index d57ad49c..6461abd 100644
--- a/chrome/test/data/webui/commerce/product_specifications/app_test.ts
+++ b/chrome/test/data/webui/commerce/product_specifications/app_test.ts
@@ -2542,10 +2542,6 @@
       const pluralStringProxy = new TestPluralStringProxy();
       PluralStringProxyImpl.setInstance(pluralStringProxy);
 
-      loadTimeData.overrideValues({
-        'comparisonTableListEnabled': true,
-      });
-
       shoppingServiceApi.setResultFor(
           'getAllProductSpecificationsSets', Promise.resolve({
             sets: SPECS_SETS,
@@ -2565,18 +2561,6 @@
           });
     });
 
-    test('list does not appear when the feature is off', async () => {
-      loadTimeData.overrideValues({
-        'comparisonTableListEnabled': false,
-      });
-
-      const appElement = await createAppElement();
-      await microtasksFinished();
-
-      const listElement = appElement.$.comparisonTableList;
-      assertFalse(isVisible(listElement));
-    });
-
     test('list is hidden if there are no comparison tables', async () => {
       shoppingServiceApi.setResultFor(
           'getAllProductSpecificationsSets', Promise.resolve({sets: []}));
diff --git a/chrome/test/data/webui/lens/side_panel/feedback_toast_test.ts b/chrome/test/data/webui/lens/side_panel/feedback_toast_test.ts
index c0bbc1d..04e05ef 100644
--- a/chrome/test/data/webui/lens/side_panel/feedback_toast_test.ts
+++ b/chrome/test/data/webui/lens/side_panel/feedback_toast_test.ts
@@ -16,10 +16,16 @@
 
 import {TestLensSidePanelBrowserProxy} from './test_side_panel_browser_proxy.js';
 
+// The delay in milliseconds to reshow the feedback toast after it was hidden by
+// another toast. This is only used if the feedback toast was not already
+// dismissed.
+const RESHOW_FEEDBACK_TOAST_DELAY_MS = 4100;
+
 suite('FeedbackToast', () => {
   let testBrowserProxy: TestLensSidePanelBrowserProxy;
   let lensSidePanelElement: LensSidePanelAppElement;
   let callbackRouterRemote: LensSidePanelPageRemote;
+  let reshowFeedbackToastCallback: Function;
 
   function isRendered(el: HTMLElement) {
     // isVisible only checks if the bounding client rect is not empty and
@@ -32,6 +38,10 @@
         'cr-toast')!;
   }
 
+  function getMessageToast(): CrToastElement {
+    return lensSidePanelElement.$.messageToast;
+  }
+
   setup(() => {
     testBrowserProxy = new TestLensSidePanelBrowserProxy();
     SidePanelBrowserProxyImpl.setInstance(testBrowserProxy);
@@ -39,6 +49,21 @@
     // Enable the new feedback feature.
     loadTimeData.overrideValues({'newFeedbackEnabled': true});
 
+
+    // Override setTimeout, and only alter behavior for the text received
+    // timeout. Using MockTimer did not work here, as it interfered with many
+    // other, unrelated timers causing tests to crash.
+    const origSetTimeout = window.setTimeout;
+    window.setTimeout = function(
+        handler: TimerHandler, timeout: number|undefined): number {
+      if (timeout === RESHOW_FEEDBACK_TOAST_DELAY_MS) {
+        const callback = handler as Function;
+        reshowFeedbackToastCallback = callback;
+        return 0;
+      }
+      return origSetTimeout(handler, timeout);
+    };
+
     callbackRouterRemote =
         testBrowserProxy.callbackRouter.$.bindNewPipeAndPassRemote();
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
@@ -110,4 +135,119 @@
     await testBrowserProxy.handler.whenCalled('requestSendFeedback');
     assertFalse(isRendered(getFeedbackToast()));
   });
+
+  test('MessageToastHidesFeedbackToast', async () => {
+    // Show the feedback toast first.
+    callbackRouterRemote.setIsLoadingResults(false);
+    await waitAfterNextRender(lensSidePanelElement);
+    assertTrue(isRendered(getFeedbackToast()));
+
+    // Show a message toast.
+    callbackRouterRemote.showToast('Test message');
+    await waitAfterNextRender(lensSidePanelElement);
+
+    // Feedback toast should be hidden.
+    assertFalse(isRendered(getFeedbackToast()));
+    assertTrue(isRendered(getMessageToast()));
+  });
+
+  test('FeedbackToastReshowsAfterMessageToastHidesAutomatically', async () => {
+    // Show the feedback toast first.
+    callbackRouterRemote.setIsLoadingResults(false);
+    await waitAfterNextRender(lensSidePanelElement);
+    assertTrue(isRendered(getFeedbackToast()));
+
+    // Show a message toast.
+    callbackRouterRemote.showToast('Test message');
+    await waitAfterNextRender(lensSidePanelElement);
+    assertFalse(isRendered(getFeedbackToast()));
+    assertTrue(isRendered(getMessageToast()));
+
+    // Call the timeout.
+    reshowFeedbackToastCallback();
+    await waitAfterNextRender(lensSidePanelElement);
+
+    // Feedback toast should reappear.
+    assertTrue(isRendered(getFeedbackToast()));
+    assertFalse(isRendered(getMessageToast()));
+  });
+
+  test(
+      'FeedbackToastReshowsImmediatelyAfterMessageToastDismissed', async () => {
+        // Show the feedback toast first.
+        callbackRouterRemote.setIsLoadingResults(false);
+        await waitAfterNextRender(lensSidePanelElement);
+        assertTrue(isRendered(getFeedbackToast()));
+
+        // Show a message toast.
+        callbackRouterRemote.showToast('Test message');
+        await waitAfterNextRender(lensSidePanelElement);
+        assertFalse(isRendered(getFeedbackToast()));
+        assertTrue(isRendered(getMessageToast()));
+
+        // Dismiss the message toast.
+        lensSidePanelElement.$.messageToastDismissButton.click();
+        await waitAfterNextRender(lensSidePanelElement);
+
+        // Feedback toast should reappear immediately.
+        assertTrue(isRendered(getFeedbackToast()));
+        assertFalse(isRendered(getMessageToast()));
+      });
+
+  test('FeedbackToastDoesNotReshowIfDismissedByUser', async () => {
+    // Show the feedback toast first.
+    callbackRouterRemote.setIsLoadingResults(false);
+    await waitAfterNextRender(lensSidePanelElement);
+    assertTrue(isRendered(getFeedbackToast()));
+
+    // Click the close button, which should hide the feedback toast.
+    const closeButton =
+        lensSidePanelElement.$.feedbackToast.shadowRoot.querySelector(
+            'cr-icon-button');
+    assertTrue(closeButton !== null);
+    closeButton.click();
+    await waitAfterNextRender(lensSidePanelElement);
+    assertFalse(isRendered(getFeedbackToast()));
+
+    // Show a message toast.
+    callbackRouterRemote.showToast('Test message');
+    await waitAfterNextRender(lensSidePanelElement);
+    assertFalse(isRendered(getFeedbackToast()));
+    assertTrue(isRendered(getMessageToast()));
+
+    // Call the timeout.
+    reshowFeedbackToastCallback();
+    await waitAfterNextRender(lensSidePanelElement);
+
+    // Feedback toast should not reappear.
+    assertFalse(isRendered(getFeedbackToast()));
+  });
+
+  test('FinishingLoadResetsDismissedStateAndShowsFeedbackToast', async () => {
+    // Show the feedback toast first.
+    callbackRouterRemote.setIsLoadingResults(false);
+    await waitAfterNextRender(lensSidePanelElement);
+    assertTrue(isRendered(getFeedbackToast()));
+
+    // Click the close button, which should hide the feedback toast.
+    const closeButton =
+        lensSidePanelElement.$.feedbackToast.shadowRoot.querySelector(
+            'cr-icon-button');
+    assertTrue(closeButton !== null);
+    closeButton.click();
+    await waitAfterNextRender(lensSidePanelElement);
+    assertFalse(isRendered(getFeedbackToast()));
+
+    // Start and finish a new load.
+    callbackRouterRemote.setIsLoadingResults(true);
+    await waitAfterNextRender(lensSidePanelElement);
+    assertFalse(isRendered(getFeedbackToast()));
+
+    callbackRouterRemote.setIsLoadingResults(false);
+    await waitAfterNextRender(lensSidePanelElement);
+
+    // Feedback toast should reappear because the dismissed state was reset on
+    // load finish.
+    assertTrue(isRendered(getFeedbackToast()));
+  });
 });
diff --git a/chrome/updater/enterprise/win/google/generate_group_policy_template_admx.py b/chrome/updater/enterprise/win/google/generate_group_policy_template_admx.py
index 8550b17..b0ae7c7 100755
--- a/chrome/updater/enterprise/win/google/generate_group_policy_template_admx.py
+++ b/chrome/updater/enterprise/win/google/generate_group_policy_template_admx.py
@@ -370,7 +370,64 @@
       <supportedOn ref="Sup_GoogleUpdate1_3_34_3" />
       <enabledValue><decimal value="1" /></enabledValue>
       <disabledValue><decimal value="0" /></disabledValue>
-    </policy>'''
+    </policy>
+    <policy name="Pol_MajorVersionRollout%(AppLegalId)s" class="Machine"
+        displayName="$(string.Pol_MajorVersionRollout)"
+        explainText="$(string.Explain_MajorVersionRollout%(AppLegalId)s)"
+        presentation="$(presentation.Pol_MajorVersionRollout)"
+        key="%(RootPolicyKey)s">
+      <parentCategory ref="Cat_%(AppLegalId)s" />
+      <supportedOn ref="Sup_GoogleUpdate138_0_7200_0" />
+      <elements>
+        <enum id="Part_MajorVersion"
+             valueName="MajorVerionRollout%(AppGuid)s" required="true">
+          <item displayName="$(string.Name_RolloutDefault)">
+            <value>
+              <decimal value="0" />
+            </value>
+          </item>
+          <item displayName="$(string.Name_RolloutSlow)">
+            <value>
+              <decimal value="1" />
+            </value>
+          </item>
+          <item displayName="$(string.Name_RolloutFast)">
+            <value>
+              <decimal value="2" />
+            </value>
+          </item>
+        </enum>
+      </elements>
+    </policy>
+    <policy name="Pol_MinorVersionRollout%(AppLegalId)s" class="Machine"
+        displayName="$(string.Pol_MinorVersionRollout)"
+        explainText="$(string.Explain_MinorVersionRollout%(AppLegalId)s)"
+        presentation="$(presentation.Pol_MinorVersionRollout)"
+        key="%(RootPolicyKey)s">
+      <parentCategory ref="Cat_%(AppLegalId)s" />
+      <supportedOn ref="Sup_GoogleUpdate138_0_7200_0" />
+      <elements>
+        <enum id="Part_MinorVersion"
+             valueName="MinorVerionRollout%(AppGuid)s" required="true">
+          <item displayName="$(string.Name_RolloutDefault)">
+            <value>
+              <decimal value="0" />
+            </value>
+          </item>
+          <item displayName="$(string.Name_RolloutSlow)">
+            <value>
+              <decimal value="1" />
+            </value>
+          </item>
+          <item displayName="$(string.Name_RolloutFast)">
+            <value>
+              <decimal value="2" />
+            </value>
+          </item>
+        </enum>
+      </elements>
+    </policy>
+    '''
 
 ADMX_FOOTER = '</policyDefinitions>'
 
@@ -520,6 +577,7 @@
     ('Sup_GoogleUpdate1_3_34_3', 'At least Google Update 1.3.34.3'),
     ('Sup_GoogleUpdate1_3_35_441', 'At least Google Update 1.3.35.441'),
     ('Sup_GoogleUpdate1_3_35_453', 'At least Google Update 1.3.35.453'),
+    ('Sup_GoogleUpdate138_0_7200_0', 'At least GoogleUpdater 138.0.7200.0'),
     ('Cat_GoogleUpdate', 'Google Update'),
     ('Cat_Preferences', 'Preferences'),
     ('Cat_ProxyServer', 'Proxy Server'),
@@ -541,6 +599,8 @@
     ('Pol_TargetChannel', 'Target Channel override'),
     ('Pol_TargetVersionPrefix', 'Target version prefix override'),
     ('Pol_RollbackToTargetVersion', 'Rollback to Target version'),
+    ('Pol_MajorVersionRollout', 'Major version rollout'),
+    ('Pol_MinorVersionRollout', 'Major version rollout'),
     ('Part_AutoUpdateCheckPeriod', 'Minutes between update checks'),
     ('Part_UpdateCheckSuppressedStartHour',
      'Hour in a day that start to suppress update check'),
@@ -561,10 +621,15 @@
     ('Part_UpdatePolicy', 'Policy'),
     ('Part_TargetChannel', 'Target Channel'),
     ('Part_TargetVersionPrefix', 'Target version prefix'),
+    ('Part_MajorVersion', 'Rollout Policy'),
+    ('Part_MinorVersion', 'Rollout Policy'),
     ('Name_UpdatesEnabled', 'Always allow updates (recommended)'),
     ('Name_ManualUpdatesOnly', 'Manual updates only'),
     ('Name_AutomaticUpdatesOnly', 'Automatic silent updates only'),
     ('Name_UpdatesDisabled', 'Updates disabled'),
+    ('Name_RolloutDefault', 'Participate in gradual rollout (recommended)'),
+    ('Name_RolloutSlow', 'Update only after gradual rollout completes'),
+    ('Name_RolloutFast', 'Update immediately when gradual rollout starts'),
     ('ProxyDisabled_DropDown', 'Never use a proxy'),
     ('ProxyAutoDetect_DropDown', 'Auto detect proxy settings'),
     ('ProxyPacScript_DropDown', 'Use a .pac proxy script'),
@@ -728,6 +793,14 @@
         </textBox>
       </presentation>
       <presentation id="Pol_RollbackToTargetVersion" />
+      <presentation id="Pol_MajorVersionRollout">
+        <dropdownList refId="Part_MajorVersion"
+            defaultItem="0">Policy</dropdownList>
+      </presentation>
+      <presentation id="Pol_MinorVersionRollout">
+        <dropdownList refId="Part_MinorVersion"
+            defaultItem="0">Policy</dropdownList>
+      </presentation>
 '''
 
 ADML_RESOURCE_TABLE_TEMPLATE = '''
@@ -869,6 +942,20 @@
         string_definition_list.append(
             app_rollback_to_target_version_explanation)
 
+        string_definition_list.append(
+            ('Explain_MajorVersionRollout' + app_legal_id,
+             'Specifies when to apply major %s updates that are gradually '
+             'rolling out. Major updates often have fixes, security patches, '
+             'and new features.\n\n'
+             '%s' % (app_name, ADML_DOMAIN_REQUIREMENT_EN)))
+
+        string_definition_list.append(
+            ('Explain_MinorVersionRollout' + app_legal_id,
+             'Specifies when to apply minor %s updates that are gradually '
+             'rolling out. Minor version updates often have fixes and '
+             'security patches, but rarely contain new features.\n\n'
+             '%s' % (app_name, ADML_DOMAIN_REQUIREMENT_EN)))
+
     app_resource_strings = []
     for entry in string_definition_list:
         app_resource_strings.append('      <string id="%s">%s</string>' %
diff --git a/chrome/updater/installer.cc b/chrome/updater/installer.cc
index 15073890..6cf32d63 100644
--- a/chrome/updater/installer.cc
+++ b/chrome/updater/installer.cc
@@ -15,6 +15,7 @@
 #include "base/functional/callback.h"
 #include "base/logging.h"
 #include "base/notreached.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/task/thread_pool.h"
 #include "base/threading/scoped_blocking_call.h"
 #include "base/time/time.h"
@@ -86,6 +87,8 @@
     const std::string& target_channel,
     const std::string& target_version_prefix,
     bool rollback_allowed,
+    std::optional<int> major_version_rollout_policy,
+    std::optional<int> minor_version_rollout_policy,
     bool update_disabled,
     UpdateService::PolicySameVersionUpdate policy_same_version_update,
     scoped_refptr<PersistedData> persisted_data,
@@ -96,6 +99,8 @@
       install_data_index_(install_data_index),
       install_source_(install_source),
       rollback_allowed_(rollback_allowed),
+      major_version_rollout_policy_(major_version_rollout_policy),
+      minor_version_rollout_policy_(minor_version_rollout_policy),
       target_channel_(target_channel),
       target_version_prefix_(target_version_prefix),
       update_disabled_(update_disabled),
@@ -161,6 +166,16 @@
   component.target_version_prefix = target_version_prefix_;
   component.updates_enabled = !update_disabled_;
   component.install_source = install_source_;
+  if (major_version_rollout_policy_) {
+    component.installer_attributes.emplace(
+        "major_version_rollout_policy",
+        base::NumberToString(*major_version_rollout_policy_));
+  }
+  if (minor_version_rollout_policy_) {
+    component.installer_attributes.emplace(
+        "minor_version_rollout_policy",
+        base::NumberToString(*minor_version_rollout_policy_));
+  }
 
   std::move(callback).Run(component);
 }
diff --git a/chrome/updater/installer.h b/chrome/updater/installer.h
index 1a029c09..bcd4873 100644
--- a/chrome/updater/installer.h
+++ b/chrome/updater/installer.h
@@ -104,6 +104,8 @@
             const std::string& target_channel,
             const std::string& target_version_prefix,
             bool rollback_allowed,
+            std::optional<int> major_version_rollout_policy,
+            std::optional<int> minor_version_rollout_policy,
             bool update_disabled,
             UpdateService::PolicySameVersionUpdate policy_same_version_update,
             scoped_refptr<PersistedData> persisted_data,
@@ -162,6 +164,8 @@
   const std::string install_data_index_;
   const std::string install_source_;
   const bool rollback_allowed_;
+  const std::optional<int> major_version_rollout_policy_;
+  const std::optional<int> minor_version_rollout_policy_;
   const std::string target_channel_;
   const std::string target_version_prefix_;
   const bool update_disabled_;
diff --git a/chrome/updater/installer_unittest.cc b/chrome/updater/installer_unittest.cc
index 7e00422..d72c07b 100644
--- a/chrome/updater/installer_unittest.cc
+++ b/chrome/updater/installer_unittest.cc
@@ -44,6 +44,8 @@
   base::MakeRefCounted<Installer>(
       "id", "client_install_data", "install_data_index", "install_source",
       "target_channel", "target_version_prefix", /*rollback_allowed=*/true,
+      /*major_version_rollout_policy=*/1,
+      /*minor_version_rollout_policy=*/2,
       /*update_disabled=*/false,
       UpdateService::PolicySameVersionUpdate::kNotAllowed, metadata,
       crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF)
@@ -67,6 +69,16 @@
 
   // install_data_index is unset because client_install_data was sent.
   EXPECT_EQ(crx.install_data_index, "");
+  ASSERT_NE(crx.installer_attributes.find("major_version_rollout_policy"),
+            crx.installer_attributes.end());
+  ASSERT_NE(crx.installer_attributes.find("minor_version_rollout_policy"),
+            crx.installer_attributes.end());
+  EXPECT_EQ(
+      crx.installer_attributes.find("major_version_rollout_policy")->second,
+      "1");
+  EXPECT_EQ(
+      crx.installer_attributes.find("minor_version_rollout_policy")->second,
+      "2");
 }
 
 #if BUILDFLAG(IS_MAC)
@@ -102,6 +114,8 @@
   base::MakeRefCounted<Installer>(
       "id", "client_install_data", "install_data_index", "install_source",
       "target_channel", "target_version_prefix", /*rollback_allowed=*/true,
+      /*major_version_rollout_policy=*/1,
+      /*minor_version_rollout_policy=*/2,
       /*update_disabled=*/false,
       UpdateService::PolicySameVersionUpdate::kNotAllowed, metadata,
       crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF)
@@ -145,6 +159,8 @@
   base::MakeRefCounted<Installer>(
       "id", "client_install_data", "install_data_index", "install_source",
       "target_channel", "target_version_prefix", /*rollback_allowed=*/true,
+      /*major_version_rollout_policy=*/1,
+      /*minor_version_rollout_policy=*/2,
       /*update_disabled=*/false,
       UpdateService::PolicySameVersionUpdate::kNotAllowed, metadata,
       crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF)
@@ -190,6 +206,8 @@
   base::MakeRefCounted<Installer>(
       "id", "client_install_data", "install_data_index", "install_source",
       "target_channel", "target_version_prefix", /*rollback_allowed=*/true,
+      /*major_version_rollout_policy=*/1,
+      /*minor_version_rollout_policy=*/2,
       /*update_disabled=*/false,
       UpdateService::PolicySameVersionUpdate::kNotAllowed, metadata,
       crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF)
@@ -220,6 +238,8 @@
               "id", "client_install_data", "install_data_index",
               "install_source", "target_channel", "target_version_prefix",
               /*rollback_allowed=*/true,
+              /*major_version_rollout_policy=*/1,
+              /*minor_version_rollout_policy=*/2,
               /*update_disabled=*/false,
               UpdateService::PolicySameVersionUpdate::kNotAllowed, metadata,
               crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF))
diff --git a/chrome/updater/policy/dm_policy_manager.cc b/chrome/updater/policy/dm_policy_manager.cc
index d5eb20c..f264d783 100644
--- a/chrome/updater/policy/dm_policy_manager.cc
+++ b/chrome/updater/policy/dm_policy_manager.cc
@@ -261,6 +261,26 @@
               ROLLBACK_TO_TARGET_VERSION_ENABLED);
 }
 
+std::optional<int> DMPolicyManager::GetMajorVersionRolloutPolicy(
+    const std::string& app_id) const {
+  const auto* app_settings = GetAppSettings(app_id);
+  if (!app_settings || !app_settings->has_major_version_rollout_policy()) {
+    return std::nullopt;
+  }
+
+  return app_settings->major_version_rollout_policy();
+}
+
+std::optional<int> DMPolicyManager::GetMinorVersionRolloutPolicy(
+    const std::string& app_id) const {
+  const auto* app_settings = GetAppSettings(app_id);
+  if (!app_settings || !app_settings->has_minor_version_rollout_policy()) {
+    return std::nullopt;
+  }
+
+  return app_settings->minor_version_rollout_policy();
+}
+
 std::optional<std::vector<std::string>> DMPolicyManager::GetForceInstallApps()
     const {
   std::vector<std::string> force_install_apps;
diff --git a/chrome/updater/policy/dm_policy_manager.h b/chrome/updater/policy/dm_policy_manager.h
index b0a6a64..7cf792d 100644
--- a/chrome/updater/policy/dm_policy_manager.h
+++ b/chrome/updater/policy/dm_policy_manager.h
@@ -46,6 +46,10 @@
       const std::string& app_id) const override;
   std::optional<bool> IsRollbackToTargetVersionAllowed(
       const std::string& app_id) const override;
+  std::optional<int> GetMajorVersionRolloutPolicy(
+      const std::string& app_id) const override;
+  std::optional<int> GetMinorVersionRolloutPolicy(
+      const std::string& app_id) const override;
   std::optional<std::string> GetProxyMode() const override;
   std::optional<std::string> GetProxyPacUrl() const override;
   std::optional<std::string> GetProxyServer() const override;
diff --git a/chrome/updater/policy/mac/managed_preference_policy_manager.mm b/chrome/updater/policy/mac/managed_preference_policy_manager.mm
index 4f96d11a..9888d99e 100644
--- a/chrome/updater/policy/mac/managed_preference_policy_manager.mm
+++ b/chrome/updater/policy/mac/managed_preference_policy_manager.mm
@@ -56,6 +56,10 @@
       const std::string& app_id) const override;
   std::optional<bool> IsRollbackToTargetVersionAllowed(
       const std::string& app_id) const override;
+  std::optional<int> GetMajorVersionRolloutPolicy(
+      const std::string& app_id) const override;
+  std::optional<int> GetMinorVersionRolloutPolicy(
+      const std::string& app_id) const override;
   std::optional<std::string> GetProxyMode() const override;
   std::optional<std::string> GetProxyPacUrl() const override;
   std::optional<std::string> GetProxyServer() const override;
@@ -194,6 +198,22 @@
                : std::nullopt;
 }
 
+std::optional<int> ManagedPreferencePolicyManager::GetMajorVersionRolloutPolicy(
+    const std::string& app_id) const {
+  int update_policy =
+      [impl_ majorVersionRolloutPolicy:base::SysUTF8ToNSString(app_id)];
+  return update_policy == kPolicyNotSet ? std::nullopt
+                                        : std::optional<int>(update_policy);
+}
+
+std::optional<int> ManagedPreferencePolicyManager::GetMinorVersionRolloutPolicy(
+    const std::string& app_id) const {
+  int update_policy =
+      [impl_ minorVersionRolloutPolicy:base::SysUTF8ToNSString(app_id)];
+  return update_policy == kPolicyNotSet ? std::nullopt
+                                        : std::optional<int>(update_policy);
+}
+
 std::optional<std::vector<std::string>>
 ManagedPreferencePolicyManager::GetForceInstallApps() const {
   return std::nullopt;
diff --git a/chrome/updater/policy/mac/managed_preference_policy_manager_impl.h b/chrome/updater/policy/mac/managed_preference_policy_manager_impl.h
index 3de6983..184247e 100644
--- a/chrome/updater/policy/mac/managed_preference_policy_manager_impl.h
+++ b/chrome/updater/policy/mac/managed_preference_policy_manager_impl.h
@@ -61,6 +61,8 @@
 - (nullable NSString*)targetChannel:(nonnull NSString*)appid;
 - (nullable NSString*)targetVersionPrefix:(nonnull NSString*)appid;
 - (int)rollbackToTargetVersion:(nonnull NSString*)appid;
+- (int)majorVersionRolloutPolicy:(nonnull NSString*)appid;
+- (int)minorVersionRolloutPolicy:(nonnull NSString*)appid;
 
 - (nullable NSArray<NSString*>*)appsWithPolicy;
 
diff --git a/chrome/updater/policy/mac/managed_preference_policy_manager_impl.mm b/chrome/updater/policy/mac/managed_preference_policy_manager_impl.mm
index f64537f..14959df 100644
--- a/chrome/updater/policy/mac/managed_preference_policy_manager_impl.mm
+++ b/chrome/updater/policy/mac/managed_preference_policy_manager_impl.mm
@@ -22,6 +22,8 @@
 NSString* kTargetChannelKey = @"TargetChannel";
 NSString* kTargetVersionPrefixKey = @"TargetVersionPrefix";
 NSString* kRollbackToTargetVersionKey = @"RollbackToTargetVersion";
+NSString* kMajorVersionRolloutKey = @"MajorVersionRolloutPolicy";
+NSString* kMinorVersionRolloutKey = @"MinorVersionRolloutPolicy";
 }  // namespace
 
 namespace updater {
@@ -155,6 +157,8 @@
 @property(nonatomic, readonly) int rollbackToTargetVersion;
 @property(nonatomic, readonly, nullable) NSString* targetChannel;
 @property(nonatomic, readonly, nullable) NSString* targetVersionPrefix;
+@property(nonatomic, readonly) int majorVersionRolloutPolicy;
+@property(nonatomic, readonly) int minorVersionRolloutPolicy;
 
 @end
 
@@ -162,6 +166,8 @@
 
 @synthesize updatePolicy = _updatePolicy;
 @synthesize rollbackToTargetVersion = _rollbackToTargetVersion;
+@synthesize majorVersionRolloutPolicy = _majorVersionRolloutPolicy;
+@synthesize minorVersionRolloutPolicy = _minorVersionRolloutPolicy;
 
 - (instancetype)initWithDictionary:(CRUAppPolicyDictionary*)policyDict {
   if (([super init])) {
@@ -173,6 +179,10 @@
         base::apple::ObjCCast<NSString>(policyDict[kTargetVersionPrefixKey]);
     _rollbackToTargetVersion =
         updater::ReadPolicyInteger(policyDict[kRollbackToTargetVersionKey]);
+    _majorVersionRolloutPolicy =
+        updater::ReadPolicyInteger(policyDict[kMajorVersionRolloutKey]);
+    _minorVersionRolloutPolicy =
+        updater::ReadPolicyInteger(policyDict[kMinorVersionRolloutKey]);
   }
 
   return self;
@@ -292,6 +302,22 @@
   return [_appPolicies objectForKey:appid].rollbackToTargetVersion;
 }
 
+- (int)majorVersionRolloutPolicy:(NSString*)appid {
+  appid = appid.lowercaseString;
+  if (![_appPolicies objectForKey:appid]) {
+    return updater::kPolicyNotSet;
+  }
+  return [_appPolicies objectForKey:appid].majorVersionRolloutPolicy;
+}
+
+- (int)minorVersionRolloutPolicy:(NSString*)appid {
+  appid = appid.lowercaseString;
+  if (![_appPolicies objectForKey:appid]) {
+    return updater::kPolicyNotSet;
+  }
+  return [_appPolicies objectForKey:appid].minorVersionRolloutPolicy;
+}
+
 - (NSArray<NSString*>*)appsWithPolicy {
   return [_appPolicies allKeys];
 }
diff --git a/chrome/updater/policy/manager.cc b/chrome/updater/policy/manager.cc
index 4475327..e583417 100644
--- a/chrome/updater/policy/manager.cc
+++ b/chrome/updater/policy/manager.cc
@@ -63,6 +63,10 @@
       const std::string& app_id) const override;
   std::optional<bool> IsRollbackToTargetVersionAllowed(
       const std::string& app_id) const override;
+  std::optional<int> GetMajorVersionRolloutPolicy(
+      const std::string& app_id) const override;
+  std::optional<int> GetMinorVersionRolloutPolicy(
+      const std::string& app_id) const override;
   std::optional<std::string> GetProxyMode() const override;
   std::optional<std::string> GetProxyPacUrl() const override;
   std::optional<std::string> GetProxyServer() const override;
@@ -138,6 +142,16 @@
   return false;
 }
 
+std::optional<int> DefaultValuesPolicyManager::GetMajorVersionRolloutPolicy(
+    const std::string& app_id) const {
+  return std::nullopt;
+}
+
+std::optional<int> DefaultValuesPolicyManager::GetMinorVersionRolloutPolicy(
+    const std::string& app_id) const {
+  return std::nullopt;
+}
+
 std::optional<std::string> DefaultValuesPolicyManager::GetProxyMode() const {
   return std::nullopt;
 }
diff --git a/chrome/updater/policy/manager.h b/chrome/updater/policy/manager.h
index 97e4102..1f1c6c1 100644
--- a/chrome/updater/policy/manager.h
+++ b/chrome/updater/policy/manager.h
@@ -81,11 +81,13 @@
   // Otherwise, returns kPolicyDisabled.
   virtual std::optional<int> GetEffectivePolicyForAppInstalls(
       const std::string& app_id) const = 0;
+
   // Returns kPolicyEnabled if updates of the specified app is allowed.
   // Otherwise, returns one of kPolicyDisabled, kPolicyManualUpdatesOnly, or
   // kPolicyAutomaticUpdatesOnly.
   virtual std::optional<int> GetEffectivePolicyForAppUpdates(
       const std::string& app_id) const = 0;
+
   // Returns the target version prefix for the app.
   // Examples:
   // * "" (or not configured): update to latest version available.
@@ -94,11 +96,27 @@
   // * "55.24.34": update to this specific version only.
   virtual std::optional<std::string> GetTargetVersionPrefix(
       const std::string& app_id) const = 0;
+
   // Returns whether the RollbackToTargetVersion policy has been set for the
   // app. If RollbackToTargetVersion is set, the TargetVersionPrefix policy
   // governs the version to rollback clients with higher versions to.
   virtual std::optional<bool> IsRollbackToTargetVersionAllowed(
       const std::string& app_id) const = 0;
+
+  // Returns one of kPolicyRolloutDefault, kPolicyRolloutFast, or
+  // kPolicyRolloutSlow, indicating the preference for participating in app
+  // gradual rollouts, skipping gradual rollouts, or holding back from gradual
+  // rollouts, respectively. Applies to major revisions of apps only.
+  virtual std::optional<int> GetMajorVersionRolloutPolicy(
+      const std::string& app_id) const = 0;
+
+  // Returns one of kPolicyRolloutDefault, kPolicyRolloutFast, or
+  // kPolicyRolloutSlow, indicating the preference for participating in app
+  // gradual rollouts, skipping gradual rollouts, or holding back from gradual
+  // rollouts, respectively. Applies to minor revisions of apps only.
+  virtual std::optional<int> GetMinorVersionRolloutPolicy(
+      const std::string& app_id) const = 0;
+
   // Returns a proxy mode such as |auto_detect|.
   virtual std::optional<std::string> GetProxyMode() const = 0;
 
diff --git a/chrome/updater/policy/policy_manager.cc b/chrome/updater/policy/policy_manager.cc
index ed3f2be..1b2c1bb 100644
--- a/chrome/updater/policy/policy_manager.cc
+++ b/chrome/updater/policy/policy_manager.cc
@@ -13,6 +13,7 @@
 #include "base/containers/flat_set.h"
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
 #include "base/values.h"
 #include "chrome/updater/policy/manager.h"
@@ -60,6 +61,8 @@
 constexpr char kTargetVersionPrefix[] = "targetversionprefix";
 constexpr char kTargetChannel[] = "targetchannel";
 constexpr char kRollbackToTargetVersion[] = "RollbackToTargetVersion";
+constexpr char kMajorVersionRolloutPrefix[] = "MajorVersionRollout";
+constexpr char kMinorVersionRolloutPrefix[] = "MinorVersionRollout";
 
 }  // namespace
 
@@ -148,42 +151,45 @@
 
 std::optional<int> PolicyManager::GetEffectivePolicyForAppInstalls(
     const std::string& app_id) const {
-  std::string app_value_name(kInstallAppPrefix);
-  app_value_name.append(app_id);
-  std::optional<int> policy = GetIntegerPolicy(app_value_name);
+  std::optional<int> policy =
+      GetIntegerPolicy(base::StrCat({kInstallAppPrefix, app_id}));
   return policy ? policy : GetIntegerPolicy(kInstallAppsDefault);
 }
 
 std::optional<int> PolicyManager::GetEffectivePolicyForAppUpdates(
     const std::string& app_id) const {
-  std::string app_value_name(kUpdateAppPrefix);
-  app_value_name.append(app_id);
-  std::optional<int> policy = GetIntegerPolicy(app_value_name);
+  std::optional<int> policy =
+      GetIntegerPolicy(base::StrCat({kUpdateAppPrefix, app_id}));
   return policy ? policy : GetIntegerPolicy(kUpdateAppsDefault);
 }
 
 std::optional<std::string> PolicyManager::GetTargetChannel(
     const std::string& app_id) const {
-  std::string app_value_name(kTargetChannel);
-  app_value_name.append(app_id);
-  return GetStringPolicy(app_value_name.c_str());
+  return GetStringPolicy(base::StrCat({kTargetChannel, app_id}));
 }
 
 std::optional<std::string> PolicyManager::GetTargetVersionPrefix(
     const std::string& app_id) const {
-  std::string app_value_name(kTargetVersionPrefix);
-  app_value_name.append(app_id);
-  return GetStringPolicy(app_value_name.c_str());
+  return GetStringPolicy(base::StrCat({kTargetVersionPrefix, app_id}));
 }
 
 std::optional<bool> PolicyManager::IsRollbackToTargetVersionAllowed(
     const std::string& app_id) const {
-  std::string app_value_name(kRollbackToTargetVersion);
-  app_value_name.append(app_id);
-  std::optional<int> policy = GetIntegerPolicy(app_value_name);
+  std::optional<int> policy =
+      GetIntegerPolicy(base::StrCat({kRollbackToTargetVersion, app_id}));
   return policy ? std::optional<bool>(policy.value()) : std::nullopt;
 }
 
+std::optional<int> PolicyManager::GetMajorVersionRolloutPolicy(
+    const std::string& app_id) const {
+  return GetIntegerPolicy(base::StrCat({kMajorVersionRolloutPrefix, app_id}));
+}
+
+std::optional<int> PolicyManager::GetMinorVersionRolloutPolicy(
+    const std::string& app_id) const {
+  return GetIntegerPolicy(base::StrCat({kMinorVersionRolloutPrefix, app_id}));
+}
+
 std::optional<std::string> PolicyManager::GetProxyMode() const {
   return GetStringPolicy(kProxyMode);
 }
@@ -211,9 +217,11 @@
       base::ToLowerASCII(kUpdatesSuppressedDurationMin),
   };
   static constexpr const char* kAppPolicyPrefixes[] = {
-      kInstallAppsDefault,     kInstallAppPrefix,    kUpdateAppsDefault,
-      kUpdateAppPrefix,        kTargetVersionPrefix, kTargetChannel,
-      kRollbackToTargetVersion};
+      kInstallAppsDefault,       kInstallAppPrefix,
+      kUpdateAppsDefault,        kUpdateAppPrefix,
+      kTargetVersionPrefix,      kTargetChannel,
+      kRollbackToTargetVersion,  kMajorVersionRolloutPrefix,
+      kMinorVersionRolloutPrefix};
   std::vector<std::string> apps_with_policy;
   std::ranges::for_each(policies_, [&](const auto& policy) {
     const std::string policy_name = policy.first;
diff --git a/chrome/updater/policy/policy_manager.h b/chrome/updater/policy/policy_manager.h
index 00576b5..ff687890 100644
--- a/chrome/updater/policy/policy_manager.h
+++ b/chrome/updater/policy/policy_manager.h
@@ -49,6 +49,10 @@
       const std::string& app_id) const override;
   std::optional<bool> IsRollbackToTargetVersionAllowed(
       const std::string& app_id) const override;
+  std::optional<int> GetMajorVersionRolloutPolicy(
+      const std::string& app_id) const override;
+  std::optional<int> GetMinorVersionRolloutPolicy(
+      const std::string& app_id) const override;
   std::optional<std::string> GetProxyMode() const override;
   std::optional<std::string> GetProxyPacUrl() const override;
   std::optional<std::string> GetProxyServer() const override;
diff --git a/chrome/updater/policy/policy_manager_unittest.cc b/chrome/updater/policy/policy_manager_unittest.cc
index 87ccd69..0e56a227 100644
--- a/chrome/updater/policy/policy_manager_unittest.cc
+++ b/chrome/updater/policy/policy_manager_unittest.cc
@@ -93,6 +93,8 @@
   policies.Set(base::StrCat({"rollbacktotargetversion", kTestAppID}), 1);
   policies.Set(base::StrCat({"install", kTestAppIDForceInstall}),
                kPolicyForceInstallUser);
+  policies.Set(base::StrCat({"majorversionrollout", kTestAppID}), 1);
+  policies.Set(base::StrCat({"minorversionrollout", kTestAppID}), 2);
 
   scoped_refptr<PolicyManagerInterface> policy_manager =
       CreateDictPolicyManager(std::move(policies));
@@ -139,6 +141,11 @@
   EXPECT_FALSE(
       policy_manager->IsRollbackToTargetVersionAllowed("non-exist-app"));
 
+  EXPECT_EQ(policy_manager->GetMajorVersionRolloutPolicy(kTestAppID), 1);
+  EXPECT_EQ(policy_manager->GetMinorVersionRolloutPolicy(kTestAppID), 2);
+  EXPECT_FALSE(policy_manager->GetMajorVersionRolloutPolicy("non-exist-app"));
+  EXPECT_FALSE(policy_manager->GetMajorVersionRolloutPolicy("non-exist-app"));
+
   std::optional<std::vector<std::string>> force_install_apps =
       policy_manager->GetForceInstallApps();
   ASSERT_EQ(force_install_apps.has_value(), !IsSystemInstall());
diff --git a/chrome/updater/policy/service.cc b/chrome/updater/policy/service.cc
index 1d4239f76..e75eb91 100644
--- a/chrome/updater/policy/service.cc
+++ b/chrome/updater/policy/service.cc
@@ -309,6 +309,20 @@
       &PolicyManagerInterface::IsRollbackToTargetVersionAllowed, app_id);
 }
 
+PolicyStatus<int> PolicyService::GetMajorVersionRolloutPolicy(
+    const std::string& app_id) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return QueryAppPolicy(&PolicyManagerInterface::GetMajorVersionRolloutPolicy,
+                        app_id);
+}
+
+PolicyStatus<int> PolicyService::GetMinorVersionRolloutPolicy(
+    const std::string& app_id) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return QueryAppPolicy(&PolicyManagerInterface::GetMajorVersionRolloutPolicy,
+                        app_id);
+}
+
 PolicyStatus<std::string> PolicyService::GetProxyMode() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return QueryPolicy(
diff --git a/chrome/updater/policy/service.h b/chrome/updater/policy/service.h
index a7bfbf1d..2432bea 100644
--- a/chrome/updater/policy/service.h
+++ b/chrome/updater/policy/service.h
@@ -68,6 +68,11 @@
     return conflict_policy_;
   }
 
+  std::optional<T> effective_policy_value() const {
+    return effective_policy_ ? std::optional<T>(effective_policy_->policy)
+                             : std::nullopt;
+  }
+
   explicit operator bool() const { return effective_policy_.has_value(); }
   // Convenience method to extract the effective policy's value.
   const T& policy() const {
@@ -149,6 +154,10 @@
       const std::string& app_id) const;
   PolicyStatus<bool> IsRollbackToTargetVersionAllowed(
       const std::string& app_id) const;
+  PolicyStatus<int> GetMajorVersionRolloutPolicy(
+      const std::string& app_id) const;
+  PolicyStatus<int> GetMinorVersionRolloutPolicy(
+      const std::string& app_id) const;
   PolicyStatus<std::string> GetProxyMode() const;
   PolicyStatus<std::string> GetProxyPacUrl() const;
   PolicyStatus<std::string> GetProxyServer() const;
diff --git a/chrome/updater/policy/service_unittest.cc b/chrome/updater/policy/service_unittest.cc
index bf1b3ba..9a4e665 100644
--- a/chrome/updater/policy/service_unittest.cc
+++ b/chrome/updater/policy/service_unittest.cc
@@ -205,6 +205,30 @@
     target_version_prefixes_[app_id] = std::move(target_version_prefix);
   }
 
+  std::optional<int> GetMajorVersionRolloutPolicy(
+      const std::string& app_id) const override {
+    auto value = major_version_rollout_policies_.find(app_id);
+    return value == major_version_rollout_policies_.end()
+               ? std::nullopt
+               : std::make_optional(value->second);
+  }
+
+  void SetMajorVersionRolloutPolicy(const std::string& app_id, int policy) {
+    major_version_rollout_policies_[app_id] = policy;
+  }
+
+  std::optional<int> GetMinorVersionRolloutPolicy(
+      const std::string& app_id) const override {
+    auto value = minor_version_rollout_policies_.find(app_id);
+    return value == minor_version_rollout_policies_.end()
+               ? std::nullopt
+               : std::make_optional(value->second);
+  }
+
+  void SetMinorVersionRolloutPolicy(const std::string& app_id, int policy) {
+    minor_version_rollout_policies_[app_id] = policy;
+  }
+
   std::optional<std::vector<std::string>> GetForceInstallApps() const override {
     return std::nullopt;
   }
@@ -243,6 +267,8 @@
   std::map<std::string, int> update_policies_;
   std::map<std::string, std::string> channels_;
   std::map<std::string, std::string> target_version_prefixes_;
+  std::map<std::string, int> major_version_rollout_policies_;
+  std::map<std::string, int> minor_version_rollout_policies_;
 };
 
 class PolicyServiceTest : public ::testing::Test {
@@ -288,6 +314,14 @@
       policy_service->IsRollbackToTargetVersionAllowed("test1");
   ASSERT_TRUE(rollback_allowed);
   EXPECT_EQ(rollback_allowed.policy(), false);
+
+  PolicyStatus<int> major_version_rollout_policy =
+      policy_service->GetMajorVersionRolloutPolicy("test1");
+  EXPECT_FALSE(major_version_rollout_policy);
+
+  PolicyStatus<int> minor_version_rollout_policy =
+      policy_service->GetMinorVersionRolloutPolicy("test1");
+  EXPECT_FALSE(minor_version_rollout_policy);
 }
 
 TEST_F(PolicyServiceTest, ValidatePolicyValues) {
diff --git a/chrome/updater/protos/omaha_settings.proto b/chrome/updater/protos/omaha_settings.proto
index 34717240..8e1f7f2 100644
--- a/chrome/updater/protos/omaha_settings.proto
+++ b/chrome/updater/protos/omaha_settings.proto
@@ -60,6 +60,17 @@
   ROLLBACK_TO_TARGET_VERSION_ENABLED = 1;
 }
 
+enum RolloutValue {
+  // Participate in gradual rollout.
+  ROLLOUT_DEFAULT = 0;
+
+  // Update after gradual rollout completes.
+  ROLLOUT_SLOW = 1;
+
+  // Update when gradual rollout begins.
+  ROLLOUT_FAST = 2;
+}
+
 message UpdatesSuppressed {
   optional int64 start_hour = 1;
   optional int64 start_minute = 2;
@@ -149,6 +160,18 @@
   // binaries for the specified channel. If this policy is not set, the default
   // channel will be used.
   optional string target_channel = 8;
+
+  // Major Version Rollout
+  //
+  // If a major update for the application is gradually rollout out, this policy
+  // controls when in the gradual rollout this device will update.
+  optional RolloutValue major_version_rollout_policy = 9;
+
+  // Minor Version Rollout
+  //
+  // If a minor update for the application is gradually rollout out, this policy
+  // controls when in the gradual rollout this device will update.
+  optional RolloutValue minor_version_rollout_policy = 10;
 }
 
 message GcpwSpecificApplicationSettings {
diff --git a/chrome/updater/update_service_impl_impl.cc b/chrome/updater/update_service_impl_impl.cc
index ec6a875..6cd479c85 100644
--- a/chrome/updater/update_service_impl_impl.cc
+++ b/chrome/updater/update_service_impl_impl.cc
@@ -164,6 +164,10 @@
         policy_service->GetTargetChannel(id).policy_or(std::string()),
         policy_service->GetTargetVersionPrefix(id).policy_or(std::string()),
         policy_service->IsRollbackToTargetVersionAllowed(id).policy_or(false),
+        policy_service->GetMajorVersionRolloutPolicy(id)
+            .effective_policy_value(),
+        policy_service->GetMinorVersionRolloutPolicy(id)
+            .effective_policy_value(),
         [&policy_service, &id, &is_foreground, update_blocked] {
           if (update_blocked) {
             return true;
diff --git a/chromeos/ash/components/heatmap/OWNERS b/chromeos/ash/components/heatmap/OWNERS
index f616ccc..2e46272 100644
--- a/chromeos/ash/components/heatmap/OWNERS
+++ b/chromeos/ash/components/heatmap/OWNERS
@@ -1,2 +1 @@
-robsc@google.com
 jiwan@chromium.org
diff --git a/chromeos/ash/components/phonehub/feature_status_provider_impl.cc b/chromeos/ash/components/phonehub/feature_status_provider_impl.cc
index dbf045a..c719779 100644
--- a/chromeos/ash/components/phonehub/feature_status_provider_impl.cc
+++ b/chromeos/ash/components/phonehub/feature_status_provider_impl.cc
@@ -6,7 +6,6 @@
 
 #include <utility>
 
-#include "ash/constants/ash_features.h"
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/task/task_traits.h"
@@ -189,8 +188,7 @@
 }
 
 void FeatureStatusProviderImpl::OnNewDevicesSynced() {
-  if (features::IsPhoneHubOnboardingNotifierRevampEnabled() &&
-      ComputeStatus() == FeatureStatus::kEligiblePhoneButNotSetUp) {
+  if (ComputeStatus() == FeatureStatus::kEligiblePhoneButNotSetUp) {
     CheckEligibleDevicesForNudge();
   }
   UpdateStatus();
diff --git a/chromeos/ash/services/multidevice_setup/account_status_change_delegate_notifier_impl.cc b/chromeos/ash/services/multidevice_setup/account_status_change_delegate_notifier_impl.cc
index 419787320..c0e80d8 100644
--- a/chromeos/ash/services/multidevice_setup/account_status_change_delegate_notifier_impl.cc
+++ b/chromeos/ash/services/multidevice_setup/account_status_change_delegate_notifier_impl.cc
@@ -7,7 +7,6 @@
 #include <set>
 #include <utility>
 
-#include "ash/constants/ash_features.h"
 #include "base/memory/ptr_util.h"
 #include "base/time/clock.h"
 #include "base/time/time.h"
@@ -16,7 +15,6 @@
 #include "chromeos/ash/services/multidevice_setup/host_status_provider_impl.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
-#include "components/session_manager/core/session_manager.h"
 
 namespace ash {
 
@@ -85,7 +83,6 @@
     ~AccountStatusChangeDelegateNotifierImpl() {
   host_status_provider_->RemoveObserver(this);
   oobe_completion_tracker_->RemoveObserver(this);
-  session_manager::SessionManager::Get()->RemoveObserver(this);
 }
 
 void AccountStatusChangeDelegateNotifierImpl::OnDelegateSet() {
@@ -144,12 +141,6 @@
       LoadHostDeviceIdFromEndOfPreviousSession();
   host_status_provider_->AddObserver(this);
   oobe_completion_tracker_->AddObserver(this);
-  session_manager::SessionManager::Get()->AddObserver(this);
-  if (IsInPhoneHubNotificationExperimentGroup()) {
-    // In the object is created after OnSessionStateChanged() is already called,
-    // manually update the timestamp.
-    UpdateSessionStartTimeIfEligible();
-  }
 }
 
 void AccountStatusChangeDelegateNotifierImpl::OnHostStatusChange(
@@ -164,29 +155,6 @@
     delegate()->OnNoLongerNewUser();
 }
 
-void AccountStatusChangeDelegateNotifierImpl::OnSessionStateChanged() {
-  UpdateSessionStartTimeIfEligible();
-}
-
-void AccountStatusChangeDelegateNotifierImpl::
-    UpdateSessionStartTimeIfEligible() {
-  if (session_manager::SessionManager::Get()->IsUserSessionBlocked()) {
-    return;
-  }
-  if (IsInPhoneHubNotificationExperimentGroup()) {
-    pref_service_->SetInt64(kMultiDeviceLastSessionStartTime,
-                            clock_->Now().InMillisecondsSinceUnixEpoch());
-    CheckForNewUserPotentialHostExistsEvent(
-        host_status_provider_->GetHostWithStatus());
-  }
-}
-
-bool AccountStatusChangeDelegateNotifierImpl::
-    IsInPhoneHubNotificationExperimentGroup() {
-  return features::IsPhoneHubOnboardingNotifierRevampEnabled() &&
-         !features::kPhoneHubOnboardingNotifierUseNudge.Get();
-}
-
 void AccountStatusChangeDelegateNotifierImpl::CheckForMultiDeviceEvents(
     const HostStatusProvider::HostStatusWithDevice& host_status_with_device) {
   if (!delegate()) {
@@ -221,7 +189,6 @@
         kVerifiedHostDeviceIdFromMostRecentHostStatusUpdatePrefName, kNoHost);
   }
 
-  CheckForNewUserPotentialHostExistsEvent(host_status_with_device);
   CheckForNoLongerNewUserEvent(host_status_with_device,
                                host_status_before_update);
   CheckForExistingUserHostSwitchedEvent(host_status_with_device,
@@ -230,62 +197,6 @@
       host_status_with_device, verified_host_device_id_before_update);
 }
 
-void AccountStatusChangeDelegateNotifierImpl::
-    CheckForNewUserPotentialHostExistsEvent(
-        const HostStatusProvider::HostStatusWithDevice&
-            host_status_with_device) {
-  if (!features::IsPhoneHubOnboardingNotifierRevampEnabled()) {
-    // We do not notify the user if they already had a chance to go through
-    // setup flow in OOBE.
-    if (pref_service_->GetInt64(kOobeSetupFlowTimestampPrefName) !=
-        kTimestampNotSet) {
-      return;
-    }
-  } else {
-    if (!IsInPhoneHubNotificationExperimentGroup()) {
-      // The user is in group for nudge. Do not show notification.
-      return;
-    }
-  }
-
-  // We only check for new user events if there is no enabled host.
-  if (verified_host_device_id_from_most_recent_update_)
-    return;
-
-  // If the observer has been notified of a potential verified host in the past,
-  // they are not considered a new user.
-  if (pref_service_->GetInt64(kNewUserPotentialHostExistsPrefName) !=
-          kTimestampNotSet ||
-      pref_service_->GetInt64(kExistingUserChromebookAddedPrefName) !=
-          kTimestampNotSet) {
-    return;
-  }
-
-  // kEligibleHostExistsButNoHostSet is the only HostStatus that can describe
-  // a new user.
-  if (host_status_with_device.host_status() !=
-      mojom::HostStatus::kEligibleHostExistsButNoHostSet) {
-    return;
-  }
-
-  if (IsInPhoneHubNotificationExperimentGroup()) {
-    if (pref_service_->GetInt64(kMultiDeviceLastSessionStartTime) !=
-            kTimestampNotSet &&
-        clock_->Now() -
-                base::Time::FromMillisecondsSinceUnixEpoch(
-                    pref_service_->GetInt64(kMultiDeviceLastSessionStartTime)) >
-            features::kMultiDeviceSetupNotificationTimeLimit.Get()) {
-      return;
-    }
-  }
-
-  if (delegate()) {
-    delegate()->OnPotentialHostExistsForNewUser();
-    pref_service_->SetInt64(kNewUserPotentialHostExistsPrefName,
-                            clock_->Now().InMillisecondsSinceUnixEpoch());
-  }
-}
-
 void AccountStatusChangeDelegateNotifierImpl::CheckForNoLongerNewUserEvent(
     const HostStatusProvider::HostStatusWithDevice& host_status_with_device,
     const std::optional<mojom::HostStatus> host_status_before_update) {
diff --git a/chromeos/ash/services/multidevice_setup/account_status_change_delegate_notifier_impl.h b/chromeos/ash/services/multidevice_setup/account_status_change_delegate_notifier_impl.h
index 4103439..42673d0 100644
--- a/chromeos/ash/services/multidevice_setup/account_status_change_delegate_notifier_impl.h
+++ b/chromeos/ash/services/multidevice_setup/account_status_change_delegate_notifier_impl.h
@@ -13,7 +13,6 @@
 #include "chromeos/ash/services/multidevice_setup/host_status_provider.h"
 #include "chromeos/ash/services/multidevice_setup/public/cpp/oobe_completion_tracker.h"
 #include "chromeos/ash/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
-#include "components/session_manager/core/session_manager_observer.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 
@@ -36,8 +35,7 @@
 class AccountStatusChangeDelegateNotifierImpl
     : public AccountStatusChangeDelegateNotifier,
       public HostStatusProvider::Observer,
-      public OobeCompletionTracker::Observer,
-      public session_manager::SessionManagerObserver {
+      public OobeCompletionTracker::Observer {
  public:
   class Factory {
    public:
@@ -105,18 +103,9 @@
   // OobeCompletionTracker::Observer:
   void OnOobeCompleted() override;
 
-  // SessionManagerObserver::
-  void OnSessionStateChanged() override;
-
-  void UpdateSessionStartTimeIfEligible();
-
-  bool IsInPhoneHubNotificationExperimentGroup();
-
   void CheckForMultiDeviceEvents(
       const HostStatusProvider::HostStatusWithDevice& host_status_with_device);
 
-  void CheckForNewUserPotentialHostExistsEvent(
-      const HostStatusProvider::HostStatusWithDevice& host_status_with_device);
   void CheckForNoLongerNewUserEvent(
       const HostStatusProvider::HostStatusWithDevice& host_status_with_device,
       const std::optional<mojom::HostStatus> host_status_before_update);
diff --git a/clank b/clank
index 6a196fc5..cef1155 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 6a196fc5a4b07b4f6d8c64cb7ab20e43bdbeb43b
+Subproject commit cef11550a1facb7d8a76e3d9169d1e0a64adf73a
diff --git a/components/browser_ui/banners/android/java/src/org/chromium/components/browser_ui/banners/SwipableOverlayView.java b/components/browser_ui/banners/android/java/src/org/chromium/components/browser_ui/banners/SwipableOverlayView.java
index 1b742723..567344d 100644
--- a/components/browser_ui/banners/android/java/src/org/chromium/components/browser_ui/banners/SwipableOverlayView.java
+++ b/components/browser_ui/banners/android/java/src/org/chromium/components/browser_ui/banners/SwipableOverlayView.java
@@ -104,12 +104,14 @@
 
     /**
      * Creates a SwipableOverlayView.
+     *
      * @param context Context for acquiring resources.
      * @param attrs Attributes from the XML layout inflation.
      * @param hideOnScroll Whether this view should observe user's gesture and then auto-hide when
-     *                     page is scrolled down.
+     *     page is scrolled down.
      */
-    public SwipableOverlayView(Context context, AttributeSet attrs, boolean hideOnScroll) {
+    public SwipableOverlayView(
+            Context context, @Nullable AttributeSet attrs, boolean hideOnScroll) {
         super(context, attrs);
         mGestureStateListener = hideOnScroll ? createGestureStateListener() : null;
         mGestureState = Gesture.NONE;
@@ -144,7 +146,7 @@
         return mTotalHeight;
     }
 
-    protected void addToParentView(ViewGroup parentView) {
+    protected void addToParentView(@Nullable ViewGroup parentView) {
         if (parentView == null) return;
         if (getParent() == null) {
             parentView.addView(this, createLayoutParams());
diff --git a/components/browser_ui/bottomsheet/android/internal/BUILD.gn b/components/browser_ui/bottomsheet/android/internal/BUILD.gn
index 5ba2f8a..c579f6a5 100644
--- a/components/browser_ui/bottomsheet/android/internal/BUILD.gn
+++ b/components/browser_ui/bottomsheet/android/internal/BUILD.gn
@@ -26,6 +26,7 @@
     "..:manager_java",
     "//base:base_java",
     "//components/browser_ui/desktop_windowing/android:java",
+    "//components/browser_ui/styles/android:java",
     "//components/browser_ui/styles/android:java_resources",
     "//components/browser_ui/widget/android:java",
     "//third_party/androidx:androidx_annotation_annotation_java",
@@ -36,6 +37,7 @@
 }
 
 robolectric_library("junit_tests") {
+  resources_package = "org.chromium.components.browser_ui.bottomsheet"
   sources = [
     "java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImplUnitTest.java",
     "java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetSwipeDetectorTest.java",
@@ -44,9 +46,11 @@
   deps = [
     ":java",
     "../:java",
+    "../:java_resources",
     "//base:base_java",
     "//base:base_junit_test_support",
     "//components/browser_ui/desktop_windowing/android:java",
+    "//components/browser_ui/theme/android:java_resources",
     "//components/browser_ui/widget/android:java",
     "//third_party/junit",
     "//third_party/mockito:mockito_java",
diff --git a/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheet.java b/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheet.java
index 04e5513..b9d67400 100644
--- a/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheet.java
+++ b/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheet.java
@@ -18,6 +18,7 @@
 import android.view.Window;
 import android.widget.FrameLayout;
 
+import androidx.annotation.ColorInt;
 import androidx.annotation.StringRes;
 import androidx.annotation.VisibleForTesting;
 
@@ -35,6 +36,7 @@
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent.HeightMode;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.SheetState;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason;
+import org.chromium.components.browser_ui.styles.SemanticColorUtils;
 import org.chromium.components.browser_ui.widget.animation.CancelAwareAnimatorListener;
 import org.chromium.ui.KeyboardVisibilityDelegate;
 import org.chromium.ui.accessibility.AccessibilityState;
@@ -168,6 +170,7 @@
     private int mAppHeaderHeight;
 
     private int mBottomMargin;
+    private final @ColorInt int mSheetBgColor;
 
     /**
      * A view used to render a shadow behind the sheet and extends outside the bounds of its parent
@@ -230,7 +233,7 @@
 
         mMinHalfFullDistance =
                 getResources().getDimensionPixelSize(R.dimen.bottom_sheet_min_full_half_distance);
-
+        mSheetBgColor = SemanticColorUtils.getSheetBgColor(context);
         mGestureDetector = new BottomSheetSwipeDetector(context, this);
         mIsTouchEnabled = true;
     }
@@ -911,6 +914,12 @@
         return mContainerWidth;
     }
 
+    /** Return the background color of the sheet. */
+    @ColorInt
+    int getSheetBackgroundColor() {
+        return mSheetBgColor;
+    }
+
     /**
      * Sends notifications if the sheet is transitioning from the peeking to half expanded state and
      * from the peeking to fully expanded state. The peek to half events are only sent when the
diff --git a/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImpl.java b/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImpl.java
index eba2c6a..ccb07e3 100644
--- a/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImpl.java
+++ b/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImpl.java
@@ -693,6 +693,16 @@
         return mIsAnchoredToBottomControls;
     }
 
+    @Override
+    public @Nullable Integer getSheetBackgroundColor() {
+        if (mBottomSheet == null
+                || getCurrentSheetContent() == null
+                || !getCurrentSheetContent().hasSolidBackgroundColor()) {
+            return null;
+        }
+        return mBottomSheet.getSheetBackgroundColor();
+    }
+
     // ScrimCoordinator.Observer
     @Override
     public void scrimVisibilityChanged(boolean scrimVisible) {
diff --git a/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImplUnitTest.java b/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImplUnitTest.java
index 8bf137b..f66727b 100644
--- a/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImplUnitTest.java
+++ b/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImplUnitTest.java
@@ -62,6 +62,7 @@
     public void setUp() {
         MockitoAnnotations.openMocks(this);
         Activity activity = buildActivity(Activity.class).setup().get();
+        activity.setTheme(R.style.Theme_BrowserUI_DayNight);
         mWindow = activity.getWindow();
         when(mRoot.getContext()).thenReturn(activity);
         when(mRoot.findViewById(R.id.bottom_sheet)).thenReturn(mBottomSheet);
diff --git a/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetUnitTest.java b/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetUnitTest.java
index d3d2a07..7dd7ebda 100644
--- a/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetUnitTest.java
+++ b/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetUnitTest.java
@@ -44,6 +44,7 @@
     public void setUp() {
         MockitoAnnotations.openMocks(this);
         Activity activity = buildActivity(Activity.class).setup().get();
+        activity.setTheme(R.style.Theme_BrowserUI_DayNight);
         mBottomSheet =
                 (BottomSheet) LayoutInflater.from(activity).inflate(R.layout.bottom_sheet, null);
         mBottomSheet.setSheetContainerForTesting(mSheetContainer);
diff --git a/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetContent.java b/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetContent.java
index 95f87a4..cafa11e 100644
--- a/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetContent.java
+++ b/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetContent.java
@@ -7,14 +7,12 @@
 import android.content.Context;
 import android.view.View;
 
-import androidx.annotation.ColorInt;
 import androidx.annotation.IntDef;
 import androidx.annotation.StringRes;
 
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
-import org.chromium.components.browser_ui.styles.SemanticColorUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -65,25 +63,16 @@
     View getContentView();
 
     /**
-     * Gets the background color for the bottom sheet content, defaulting to the semantic default
-     * background color if no background color is specified by the content. This should return null
-     * if the sheet content is showing tab content / a page preview.
-     */
-    @ColorInt
-    default @Nullable Integer getBackgroundColor() {
-        return SemanticColorUtils.getDefaultBgColor(getContentView().getContext());
-    }
-
-    /**
      * Get the {@link View} that contains the toolbar specific to the content being displayed. If
      * null is returned, the omnibox is used.
      *
      * @return The toolbar view.
      */
-    @Nullable
-    View getToolbarView();
+    @Nullable View getToolbarView();
 
-    /** @return The vertical scroll offset of the content view. */
+    /**
+     * @return The vertical scroll offset of the content view.
+     */
     int getVerticalScrollOffset();
 
     /**
@@ -140,6 +129,14 @@
     }
 
     /**
+     * Returns whether this sheet content has a solid background color. Return false when the sheet
+     * is showing complex content like tab content / a page preview.
+     */
+    default boolean hasSolidBackgroundColor() {
+        return true;
+    }
+
+    /**
      * The height of bottom sheet in PEEK mode. The sheet content that wants to show content as PEEK
      * can override this method and provide a non-negative height. This interface by default
      * supplies {@link HeightMode#DISABLED}.
diff --git a/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetController.java b/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetController.java
index de92866..b9e2b7a5 100644
--- a/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetController.java
+++ b/components/browser_ui/bottomsheet/android/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetController.java
@@ -4,6 +4,7 @@
 
 package org.chromium.components.browser_ui.bottomsheet;
 
+import androidx.annotation.ColorInt;
 import androidx.annotation.IntDef;
 
 import org.chromium.build.annotations.NullMarked;
@@ -215,4 +216,11 @@
      * controls UI.
      */
     boolean isAnchoredToBottomControls();
+
+    /**
+     * Get the current background color for the bottom sheet. If the sheet does not have a solid
+     * background color, this will return null.
+     */
+    @ColorInt
+    @Nullable Integer getSheetBackgroundColor();
 }
diff --git a/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaNotificationController.java b/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaNotificationController.java
index 51eefa85..c2fb02f8 100644
--- a/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaNotificationController.java
+++ b/components/browser_ui/media/android/java/src/org/chromium/components/browser_ui/media/MediaNotificationController.java
@@ -4,6 +4,7 @@
 
 package org.chromium.components.browser_ui.media;
 
+import static org.chromium.build.NullUtil.assertNonNull;
 import static org.chromium.build.NullUtil.assumeNonNull;
 
 import android.app.PendingIntent;
@@ -396,7 +397,7 @@
 
     @VisibleForTesting
     public PendingIntentProvider createPendingIntent(String action) {
-        Intent intent = mDelegate.createServiceIntent().setAction(action);
+        Intent intent = assumeNonNull(mDelegate.createServiceIntent()).setAction(action);
         return PendingIntentProvider.getService(
                 getContext(),
                 0,
@@ -434,7 +435,7 @@
     /** An interface for separating embedder-specific logic. */
     public interface Delegate {
         /** Returns an intent that will start a Service which listens to notification actions. */
-        Intent createServiceIntent();
+        @Nullable Intent createServiceIntent();
 
         /** Returns the name of the embedding app. */
         String getAppName();
@@ -531,7 +532,7 @@
         mService = null;
     }
 
-    public boolean processIntent(Service service, Intent intent) {
+    public boolean processIntent(Service service, @Nullable Intent intent) {
         if (intent == null || mMediaNotificationInfo == null) return false;
 
         if (intent.getAction() == null) {
@@ -639,7 +640,7 @@
             // catch the exception, and `mService` will remain null for us to try again later.
             try {
                 ForegroundServiceUtils.getInstance()
-                        .startForegroundService(mDelegate.createServiceIntent());
+                        .startForegroundService(assertNonNull(mDelegate.createServiceIntent()));
             } catch (RuntimeException e) {
             }
         } else {
diff --git a/components/browser_ui/styles/android/java/res/values/semantic_colors_dynamic.xml b/components/browser_ui/styles/android/java/res/values/semantic_colors_dynamic.xml
index 8e1bff0..21038e0 100644
--- a/components/browser_ui/styles/android/java/res/values/semantic_colors_dynamic.xml
+++ b/components/browser_ui/styles/android/java/res/values/semantic_colors_dynamic.xml
@@ -8,7 +8,6 @@
     <!-- LINT.IfChange -->
     <macro name="default_bg_color">?attr/colorSurface</macro>
     <macro name="default_bg_color_elev_0">?attr/colorSurface</macro>
-    <macro name="default_bg_color_inverse">?attr/colorSurfaceInverse</macro>
 
     <macro name="default_control_color_active">?attr/colorPrimary</macro>
     <macro name="default_control_color_normal">?attr/colorOnSurfaceVariant</macro>
diff --git a/components/commerce/core/commerce_constants.h b/components/commerce/core/commerce_constants.h
index 261de088..03357692 100644
--- a/components/commerce/core/commerce_constants.h
+++ b/components/commerce/core/commerce_constants.h
@@ -13,10 +13,6 @@
 // The host for compare.
 inline constexpr char kChromeUICompareHost[] = "compare";
 
-// The URL for managing compare entities.
-inline constexpr char kChromeUICompareListsUrl[] =
-    "chrome://history/comparisonTables";
-
 // The URL for compare.
 inline constexpr char kChromeUICompareUrl[] = "chrome://compare";
 
diff --git a/components/exo/wayland/BUILD.gn b/components/exo/wayland/BUILD.gn
index 0948ac1..e7a7bdc 100644
--- a/components/exo/wayland/BUILD.gn
+++ b/components/exo/wayland/BUILD.gn
@@ -419,7 +419,7 @@
     "//third_party/wayland-protocols:text_input_extension_protocol",
     "//third_party/wayland-protocols:text_input_protocol",
     "//third_party/wayland-protocols:touchpad_haptics_protocol",
-    "//third_party/wayland-protocols:ui_controls_v1_protocol",
+    "//third_party/wayland-protocols:ui_controls_protocol",
     "//third_party/wayland-protocols:viewporter_protocol",
     "//third_party/wayland-protocols:vsync_feedback_protocol",
     "//third_party/wayland-protocols:vsync_feedback_protocol",
diff --git a/components/input/render_input_router.mojom b/components/input/render_input_router.mojom
index 78d66c5..d4563b9 100644
--- a/components/input/render_input_router.mojom
+++ b/components/input/render_input_router.mojom
@@ -62,12 +62,11 @@
   // Viz needs this to do input handling on it's side.
   StateOnTouchTransfer(TouchTransferState state);
 
-  // Notifies RenderInputRouters corresponding to |frame_sink_ids| on the
+  // Notifies RenderInputRouter corresponding to |frame_sink_id| on the
   // VizCompositor thread of changes to |force_enable_zoom| state for
   // Accessibility.
-  ForceEnableZoomStateChanged(
-    bool force_enable_zoom,
-    array<viz.mojom.FrameSinkId> frame_sink_ids);
+  ForceEnableZoomStateChanged(bool force_enable_zoom,
+                              viz.mojom.FrameSinkId frame_sink_id);
 
   // Stops any ongoing flings for |frame_sink_id| on VizCompositorThread.
   StopFlingingOnViz(viz.mojom.FrameSinkId frame_sink_id);
@@ -94,32 +93,28 @@
 interface RenderInputRouterDelegateClient {
   // Notifies InputEventObservers in the browser of input events being handled
   // on Viz (with InputVizard).
-  NotifyObserversOfInputEvent(viz.mojom.FrameSinkId id,
-                              blink.mojom.Event event,
+  NotifyObserversOfInputEvent(blink.mojom.Event event,
                               bool dispatched_to_renderer);
 
   // Notifies InputEventObservers in the browser of input event acks being
   // handled on Viz (with InputVizard).
-  NotifyObserversOfInputEventAcks(
-      viz.mojom.FrameSinkId id, blink.mojom.InputEventResultSource ack_source,
+  NotifyObserversOfInputEventAcks(blink.mojom.InputEventResultSource ack_source,
       blink.mojom.InputEventResultState ack_result, blink.mojom.Event event);
 
   // Notifies the browser of an invalid input event source being seen on
   // the VizCompositor thread when handling input.
-  OnInvalidInputEventSource(viz.mojom.FrameSinkId id);
+  OnInvalidInputEventSource();
 
   // Sends |DidOverscrollParams| to the browser to allow overscroll effect to
   // request input back if it ends up consuming the input sequence.
   StateOnOverscrollTransfer(
-    viz.mojom.FrameSinkId frame_sink_id,
     blink.mojom.DidOverscrollParams? overscroll);
 
-  // Notifies browser that the renderer (corresponding to |frame_sink_id|) is
-  // responsive after being unresponsive or has turned unresonsive to input
-  // events. For the latter, it also passes over the timestamp when an input
-  // event timed out without getting an ack from the renderer.
+  // Notifies browser that the renderer is responsive after being unresponsive
+  // or has turned unresonsive to input events. For the latter, it also passes
+  // over the timestamp when an input event timed out without getting an ack
+  // from the renderer.
   RendererInputResponsivenessChanged(
-    viz.mojom.FrameSinkId frame_sink_id,
     bool is_responsive,
     mojo_base.mojom.TimeTicks? ack_timeout_ts);
 };
diff --git a/components/lens/lens_features.cc b/components/lens/lens_features.cc
index d251dd4..e6c0f61 100644
--- a/components/lens/lens_features.cc
+++ b/components/lens/lens_features.cc
@@ -556,6 +556,9 @@
         &kLensOverlayEduActionChip, "url-path-forced-allowed-match-patterns",
         "[]"};
 
+const base::FeatureParam<bool> kLensOverlayEduActionChipDisabledByGlic{
+    &kLensOverlayEduActionChip, "disabled-by-glic", true};
+
 std::string GetHomepageURLForLens() {
   return kHomepageURLForLens.Get();
 }
@@ -1187,4 +1190,8 @@
   return kLensOverlayEduHashedDomainBlockFilters.Get();
 }
 
+bool IsLensOverlayEduActionChipDisabledByGlic() {
+  return kLensOverlayEduActionChipDisabledByGlic.Get();
+}
+
 }  // namespace lens::features
diff --git a/components/lens/lens_features.h b/components/lens/lens_features.h
index 175a9b7d..9e3a7ac 100644
--- a/components/lens/lens_features.h
+++ b/components/lens/lens_features.h
@@ -147,6 +147,10 @@
 COMPONENT_EXPORT(LENS_FEATURES)
 extern const base::FeatureParam<bool> kLensOverlayEnableOpenInNewTab;
 
+// Whether the EDU action chip should be disabled by glic.
+COMPONENT_EXPORT(LENS_FEATURES)
+extern const base::FeatureParam<bool> kLensOverlayEduActionChipDisabledByGlic;
+
 // The URL for the Lens home page.
 COMPONENT_EXPORT(LENS_FEATURES)
 extern std::string GetHomepageURLForLens();
@@ -902,5 +906,9 @@
 COMPONENT_EXPORT(LENS_FEATURES)
 extern std::string GetLensOverlayEduHashedDomainBlockFilters();
 
+// Whether EDU action chip should be disabled by glic.
+COMPONENT_EXPORT(LENS_FEATURES)
+bool IsLensOverlayEduActionChipDisabledByGlic();
+
 }  // namespace lens::features
 #endif  // COMPONENTS_LENS_LENS_FEATURES_H_
diff --git a/components/omnibox/browser/autocomplete_controller.cc b/components/omnibox/browser/autocomplete_controller.cc
index ec5c289..1093528 100644
--- a/components/omnibox/browser/autocomplete_controller.cc
+++ b/components/omnibox/browser/autocomplete_controller.cc
@@ -1105,10 +1105,8 @@
   if (omnibox::IsAndroidHub(input_.current_page_classification())) {
     return provider->type() == AutocompleteProvider::TYPE_SEARCH ||
            provider->type() == AutocompleteProvider::TYPE_OPEN_TAB ||
-           (OmniboxFieldTrial::kAndroidHubSearchEnableBookmarkProvider.Get() &&
-            provider->type() == AutocompleteProvider::TYPE_BOOKMARK) ||
-           (OmniboxFieldTrial::kAndroidHubSearchEnableHistoryProvider.Get() &&
-            provider->type() == AutocompleteProvider::TYPE_HISTORY_QUICK);
+           provider->type() == AutocompleteProvider::TYPE_BOOKMARK ||
+           provider->type() == AutocompleteProvider::TYPE_HISTORY_QUICK;
   }
 #endif
 
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h
index 8057d54..8e98fbc 100644
--- a/components/omnibox/browser/omnibox_field_trial.h
+++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -741,20 +741,6 @@
 
 // <- Site Search Starter Pack
 // ---------------------------------------------------------
-// Android Hub Search -->
-//
-// Controls different variations of android hub search including what
-// primitives are included.
-#if BUILDFLAG(IS_ANDROID)
-constexpr base::FeatureParam<bool> kAndroidHubSearchEnableBookmarkProvider{
-    &omnibox::kAndroidHubSearch, "enable_bookmark_provider", true};
-
-constexpr base::FeatureParam<bool> kAndroidHubSearchEnableHistoryProvider{
-    &omnibox::kAndroidHubSearch, "enable_history_provider", true};
-#endif
-
-// <- Android Hub Search
-// ---------------------------------------------------------
 // Power Tools -->
 constexpr base::FeatureParam<size_t> kOmniboxNumNtpZpsRecentSearches{
     &omnibox::kNumNtpZpsRecentSearches, "omnibox_num_ntp_zps_recent_searches",
diff --git a/components/omnibox/common/android/java/src/org/chromium/components/omnibox/OmniboxFeatures.java b/components/omnibox/common/android/java/src/org/chromium/components/omnibox/OmniboxFeatures.java
index 30e42f3..53f589d 100644
--- a/components/omnibox/common/android/java/src/org/chromium/components/omnibox/OmniboxFeatures.java
+++ b/components/omnibox/common/android/java/src/org/chromium/components/omnibox/OmniboxFeatures.java
@@ -110,9 +110,6 @@
     public static final CachedFlag sRetainOmniboxOnFocus =
             newFlag(OmniboxFeatureList.RETAIN_OMNIBOX_ON_FOCUS, FeatureState.ENABLED_IN_TEST);
 
-    public static final CachedFlag sAndroidHubSearch =
-            newFlag(OmniboxFeatureList.ANDROID_HUB_SEARCH, FeatureState.ENABLED_IN_PROD);
-
     public static final CachedFlag sPostDelayedTaskFocusTab =
             newFlag(OmniboxFeatureList.POST_DELAYED_TASK_FOCUS_TAB, FeatureState.ENABLED_IN_PROD);
 
@@ -178,11 +175,6 @@
     public static final BooleanCachedFeatureParam sJumpStartOmniboxCoverRecentlyVisitedPage =
             newBooleanParam(sJumpStartOmnibox, "jump_start_cover_recently_visited_page", false);
 
-    // This parameter allows the user to click enter when on hub search to perform a search on the
-    // listed suggestions or perform a google search on the query if no suggestions are found.
-    public static final BooleanCachedFeatureParam sAndroidHubSearchEnterPerformsSearch =
-            newBooleanParam(sAndroidHubSearch, "enable_press_enter_to_search", true);
-
     // Omnibox Diagnostics
     private static final CachedFlag sDiagnostics =
             newFlag(OmniboxFeatureList.DIAGNOSTICS, FeatureState.DISABLED);
diff --git a/components/omnibox/common/omnibox_feature_configs.cc b/components/omnibox/common/omnibox_feature_configs.cc
index b5e52bb3..4d280b6 100644
--- a/components/omnibox/common/omnibox_feature_configs.cc
+++ b/components/omnibox/common/omnibox_feature_configs.cc
@@ -290,7 +290,7 @@
 
   realbox_unscoped_suggestions =
       base::FeatureParam<bool>(&kSearchAggregatorProvider,
-                               "realbox_unscoped_suggestions", false)
+                               "realbox_unscoped_suggestions", true)
           .Get();
 
   scoring_max_matches_created_per_type =
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc
index fe73bfc2..95a2f434 100644
--- a/components/omnibox/common/omnibox_features.cc
+++ b/components/omnibox/common/omnibox_features.cc
@@ -398,9 +398,6 @@
              "SuppressIntermediateACUpdatesOnLowEndDevices",
              DISABLED);
 
-// (Android only) Show the search feature in the hub.
-BASE_FEATURE(kAndroidHubSearch, "AndroidHubSearch", ENABLED);
-
 // (Android only) Show tab groups via the search feature in the hub.
 BASE_FEATURE(kAndroidHubSearchTabGroups, "AndroidHubSearchTabGroups", DISABLED);
 
@@ -424,7 +421,6 @@
       &kOmniboxElegantTextHeight,
       &kRetainOmniboxOnFocus,
       &kJumpStartOmnibox,
-      &kAndroidHubSearch,
       &kAndroidHubSearchTabGroups,
       &kPostDelayedTaskFocusTab,
       &kOmniboxMobileParityUpdate};
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h
index bdc1b35..017b992 100644
--- a/components/omnibox/common/omnibox_features.h
+++ b/components/omnibox/common/omnibox_features.h
@@ -138,7 +138,6 @@
 BASE_DECLARE_FEATURE(kRetainOmniboxOnFocus);
 BASE_DECLARE_FEATURE(kJumpStartOmnibox);
 BASE_DECLARE_FEATURE(kSuppressIntermediateACUpdatesOnLowEndDevices);
-BASE_DECLARE_FEATURE(kAndroidHubSearch);
 // Delay focusTab to prioritize navigation (https://crbug.com/374852568).
 BASE_DECLARE_FEATURE(kPostDelayedTaskFocusTab);
 BASE_DECLARE_FEATURE(kAndroidHubSearchTabGroups);
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal
index 2cc55d5..abe28fc 160000
--- a/components/optimization_guide/internal
+++ b/components/optimization_guide/internal
@@ -1 +1 @@
-Subproject commit 2cc55d5ca41fa04a1ac7a1c7971a9aba449d01b3
+Subproject commit abe28fc69cad880ec92b198727268aa7fbea55a0
diff --git a/components/payments/content/secure_payment_confirmation_app_factory.cc b/components/payments/content/secure_payment_confirmation_app_factory.cc
index 7c56bec..687ae18 100644
--- a/components/payments/content/secure_payment_confirmation_app_factory.cc
+++ b/components/payments/content/secure_payment_confirmation_app_factory.cc
@@ -150,6 +150,30 @@
     }
   }
 
+  if (!request->payment_entities_logos.empty()) {
+    for (const mojom::PaymentEntityLogoPtr& logo :
+         request->payment_entities_logos) {
+      if (logo.is_null()) {
+        *error_message = errors::kNonNullPaymentEntityLogoRequired;
+        return false;
+      }
+
+      if (!logo->url.is_valid()) {
+        *error_message = errors::kValidLogoUrlRequired;
+        return false;
+      }
+      if (!logo->url.SchemeIsHTTPOrHTTPS() &&
+          !logo->url.SchemeIs(url::kDataScheme)) {
+        *error_message = errors::kValidLogoUrlSchemeRequired;
+        return false;
+      }
+      if (logo->label.empty()) {
+        *error_message = errors::kLogoLabelRequired;
+        return false;
+      }
+    }
+  }
+
   return true;
 }
 
@@ -318,11 +342,47 @@
         return;
       }
 
+      // We currently support two ways to specify logos to be shown on the UX:
+      // the old (experimental) network_info/issuer_info fields, and the new
+      // payment_entities_logos field. Both are flag-guarded, and only one flow
+      // is supported at a time, so to simplify the rest of the logic we
+      // consolidate payment_entities_logos (if set) into
+      // issuer_info/network_info.
+      //
+      // If both flags are turned on (and payment_entities_logos is provided),
+      // then payment_entities_logos will 'win' and overwrite network_info and
+      // issuer_info.
+      //
+      // TODO(crbug.com/417683819): Switch to using an array of logos in
+      // SecurePaymentConfirmationAppFactory, and invert the logic here.
+      mojom::SecurePaymentConfirmationRequestPtr spc_request =
+          method_data->secure_payment_confirmation.Clone();
+      if (base::FeatureList::IsEnabled(
+              blink::features::kSecurePaymentConfirmationUxRefresh) &&
+          !spc_request->payment_entities_logos.empty()) {
+        const mojom::PaymentEntityLogoPtr& first_logo =
+            spc_request->payment_entities_logos[0];
+        spc_request->network_info = mojom::NetworkOrIssuerInformation::New(
+            /*name=*/first_logo->label,
+            /*icon=*/first_logo->url);
+
+        if (spc_request->payment_entities_logos.size() > 1) {
+          const mojom::PaymentEntityLogoPtr& second_logo =
+              spc_request->payment_entities_logos[1];
+          spc_request->issuer_info = mojom::NetworkOrIssuerInformation::New(
+              /*name=*/second_logo->label,
+              /*icon=*/second_logo->url);
+
+        } else {
+          spc_request->issuer_info = nullptr;
+        }
+      }
+
       // Record if the user will be offered an opt-out experience. Technically
       // SPC has not been 'selected' yet in the conceptual PaymentRequest flow,
       // however we know that for SPC it must be the only payment method offered
       // so we are safe to record this now.
-      if (method_data->secure_payment_confirmation->show_opt_out) {
+      if (spc_request->show_opt_out) {
         delegate->SetOptOutOffered();
       }
 
@@ -343,10 +403,9 @@
           base::BindOnce(&SecurePaymentConfirmationAppFactory::
                              OnIsUserVerifyingPlatformAuthenticatorAvailable,
                          weak_ptr_factory_.GetWeakPtr(),
-                         std::make_unique<Request>(
-                             delegate, web_data_service,
-                             method_data->secure_payment_confirmation.Clone(),
-                             std::move(authenticator))));
+                         std::make_unique<Request>(delegate, web_data_service,
+                                                   std::move(spc_request),
+                                                   std::move(authenticator))));
       return;
     }
   }
diff --git a/components/payments/content/secure_payment_confirmation_app_factory_unittest.cc b/components/payments/content/secure_payment_confirmation_app_factory_unittest.cc
index 4013c487..3bb0a6b 100644
--- a/components/payments/content/secure_payment_confirmation_app_factory_unittest.cc
+++ b/components/payments/content/secure_payment_confirmation_app_factory_unittest.cc
@@ -17,6 +17,7 @@
 #include "components/payments/content/mock_payment_app_factory_delegate.h"
 #include "components/payments/content/mock_payment_manifest_web_data_service.h"
 #include "components/payments/core/features.h"
+#include "components/payments/core/native_error_strings.h"
 #include "components/webauthn/core/browser/mock_internal_authenticator.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_browser_context.h"
@@ -121,7 +122,8 @@
   auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
       web_contents_, std::move(method_data));
 
-  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(_, _));
+  EXPECT_CALL(*mock_delegate,
+              OnPaymentAppCreationError(errors::kCredentialIdsRequired, _));
   secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
 }
 
@@ -137,7 +139,8 @@
   auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
       web_contents_, std::move(method_data));
 
-  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(_, _));
+  EXPECT_CALL(*mock_delegate,
+              OnPaymentAppCreationError(errors::kCredentialIdsRequired, _));
   secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
 }
 
@@ -153,7 +156,8 @@
   auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
       web_contents_, std::move(method_data));
 
-  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(_, _));
+  EXPECT_CALL(*mock_delegate,
+              OnPaymentAppCreationError(errors::kChallengeRequired, _));
   secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
 }
 
@@ -169,7 +173,8 @@
   auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
       web_contents_, std::move(method_data));
 
-  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(_, _));
+  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(
+                                  errors::kInstrumentDisplayNameRequired, _));
   secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
 }
 
@@ -185,7 +190,8 @@
   auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
       web_contents_, std::move(method_data));
 
-  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(_, _));
+  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(
+                                  errors::kValidInstrumentIconRequired, _));
   secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
 }
 
@@ -202,7 +208,8 @@
   auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
       web_contents_, std::move(method_data));
 
-  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(_, _));
+  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(
+                                  errors::kValidInstrumentIconRequired, _));
   secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
 }
 
@@ -231,7 +238,8 @@
     // EXPECT_CALL doesn't support <<, so to make it clear which rp_id was being
     // tested in a failure case we use SCOPED_TRACE.
     SCOPED_TRACE(rp_id);
-    EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(_, _));
+    EXPECT_CALL(*mock_delegate,
+                OnPaymentAppCreationError(errors::kRpIdRequired, _));
     secure_payment_confirmation_app_factory_->Create(
         mock_delegate->GetWeakPtr());
   }
@@ -250,7 +258,8 @@
   auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
       web_contents_, std::move(method_data));
 
-  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(_, _));
+  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(
+                                  errors::kPayeeOriginOrPayeeNameRequired, _));
   secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
 }
 
@@ -266,7 +275,8 @@
   auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
       web_contents_, std::move(method_data));
 
-  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(_, _));
+  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(
+                                  errors::kPayeeOriginOrPayeeNameRequired, _));
   secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
 }
 
@@ -283,7 +293,8 @@
   auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
       web_contents_, std::move(method_data));
 
-  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(_, _));
+  EXPECT_CALL(*mock_delegate,
+              OnPaymentAppCreationError(errors::kPayeeOriginMustBeHttps, _));
   secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
 }
 
@@ -303,7 +314,8 @@
   auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
       web_contents_, std::move(method_data));
 
-  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(_, _));
+  EXPECT_CALL(*mock_delegate,
+              OnPaymentAppCreationError(errors::kNetworkNameRequired, _));
   secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
 }
 
@@ -322,7 +334,8 @@
 
   auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
       web_contents_, std::move(method_data));
-  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(_, _));
+  EXPECT_CALL(*mock_delegate,
+              OnPaymentAppCreationError(errors::kValidNetworkIconRequired, _));
   secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
 }
 
@@ -341,7 +354,8 @@
 
   auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
       web_contents_, std::move(method_data));
-  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(_, _));
+  EXPECT_CALL(*mock_delegate,
+              OnPaymentAppCreationError(errors::kValidNetworkIconRequired, _));
   secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
 }
 
@@ -361,7 +375,8 @@
   auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
       web_contents_, std::move(method_data));
 
-  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(_, _));
+  EXPECT_CALL(*mock_delegate,
+              OnPaymentAppCreationError(errors::kIssuerNameRequired, _));
   secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
 }
 
@@ -380,7 +395,8 @@
 
   auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
       web_contents_, std::move(method_data));
-  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(_, _));
+  EXPECT_CALL(*mock_delegate,
+              OnPaymentAppCreationError(errors::kValidIssuerIconRequired, _));
   secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
 }
 
@@ -399,10 +415,115 @@
 
   auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
       web_contents_, std::move(method_data));
-  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(_, _));
+  EXPECT_CALL(*mock_delegate,
+              OnPaymentAppCreationError(errors::kValidIssuerIconRequired, _));
   secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
 }
 
+// Test that parsing a SecurePaymentConfirmationRequest with a null
+// PaymentEntityLogo fails.
+TEST_F(SecurePaymentConfirmationAppFactoryTest,
+       SecureConfirmationPaymentRequest_NullPaymentEntityLogo) {
+  auto method_data = mojom::PaymentMethodData::New();
+  method_data->supported_method = "secure-payment-confirmation";
+  mojom::SecurePaymentConfirmationRequestPtr spc_request =
+      CreateSecurePaymentConfirmationRequest();
+  spc_request->payment_entities_logos.push_back(nullptr);
+  method_data->secure_payment_confirmation = std::move(spc_request);
+
+  auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
+      web_contents_, std::move(method_data));
+
+  EXPECT_CALL(
+      *mock_delegate,
+      OnPaymentAppCreationError(errors::kNonNullPaymentEntityLogoRequired, _));
+  secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
+}
+
+// Test that parsing a SecurePaymentConfirmationRequest with a PaymentEntityLogo
+// that has an empty url fails.
+TEST_F(SecurePaymentConfirmationAppFactoryTest,
+       SecureConfirmationPaymentRequest_EmptyPaymentEntityLogoUrl) {
+  auto method_data = mojom::PaymentMethodData::New();
+  method_data->supported_method = "secure-payment-confirmation";
+  mojom::SecurePaymentConfirmationRequestPtr spc_request =
+      CreateSecurePaymentConfirmationRequest();
+  spc_request->payment_entities_logos.push_back(
+      mojom::PaymentEntityLogo::New(GURL(), "Label"));
+  method_data->secure_payment_confirmation = std::move(spc_request);
+
+  auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
+      web_contents_, std::move(method_data));
+
+  EXPECT_CALL(*mock_delegate,
+              OnPaymentAppCreationError(errors::kValidLogoUrlRequired, _));
+  secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
+}
+
+// Test that parsing a SecurePaymentConfirmationRequest with a PaymentEntityLogo
+// that has an invalid url fails.
+TEST_F(SecurePaymentConfirmationAppFactoryTest,
+       SecureConfirmationPaymentRequest_InvalidPaymentEntityLogoUrl) {
+  auto method_data = mojom::PaymentMethodData::New();
+  method_data->supported_method = "secure-payment-confirmation";
+  mojom::SecurePaymentConfirmationRequestPtr spc_request =
+      CreateSecurePaymentConfirmationRequest();
+  spc_request->payment_entities_logos.push_back(
+      mojom::PaymentEntityLogo::New(GURL("thisisnotaurl"), "Label"));
+  method_data->secure_payment_confirmation = std::move(spc_request);
+
+  auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
+      web_contents_, std::move(method_data));
+
+  EXPECT_CALL(*mock_delegate,
+              OnPaymentAppCreationError(errors::kValidLogoUrlRequired, _));
+  secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
+}
+
+// Test that parsing a SecurePaymentConfirmationRequest with a PaymentEntityLogo
+// that has a url with a disallowed scheme fails.
+TEST_F(SecurePaymentConfirmationAppFactoryTest,
+       SecureConfirmationPaymentRequest_DisallowedSchemePaymentEntityLogoUrl) {
+  auto method_data = mojom::PaymentMethodData::New();
+  method_data->supported_method = "secure-payment-confirmation";
+  mojom::SecurePaymentConfirmationRequestPtr spc_request =
+      CreateSecurePaymentConfirmationRequest();
+  spc_request->payment_entities_logos.push_back(mojom::PaymentEntityLogo::New(
+      GURL("blob://blob.foo.com/logo.png"), "Label"));
+  method_data->secure_payment_confirmation = std::move(spc_request);
+
+  auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
+      web_contents_, std::move(method_data));
+
+  EXPECT_CALL(*mock_delegate, OnPaymentAppCreationError(
+                                  errors::kValidLogoUrlSchemeRequired, _));
+  secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
+}
+
+// Test that parsing a SecurePaymentConfirmationRequest with a PaymentEntityLogo
+// that has an empty label fails.
+TEST_F(SecurePaymentConfirmationAppFactoryTest,
+       SecureConfirmationPaymentRequest_EmptyPaymentEntityLogoLabel) {
+  auto method_data = mojom::PaymentMethodData::New();
+  method_data->supported_method = "secure-payment-confirmation";
+  mojom::SecurePaymentConfirmationRequestPtr spc_request =
+      CreateSecurePaymentConfirmationRequest();
+  spc_request->payment_entities_logos.push_back(
+      mojom::PaymentEntityLogo::New(GURL("https://entity.example/icon.png"),
+                                    /*label=*/""));
+  method_data->secure_payment_confirmation = std::move(spc_request);
+
+  auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
+      web_contents_, std::move(method_data));
+
+  EXPECT_CALL(*mock_delegate,
+              OnPaymentAppCreationError(errors::kLogoLabelRequired, _));
+  secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
+}
+
+// TODO(crbug.com/417683819): Add tests verifying that paymentEntitiesLogos is
+// correctly converted into icons to be downloaded.
+
 class SecurePaymentConfirmationAppFactoryUsingCredentialStoreAPIsTest
     : public SecurePaymentConfirmationAppFactoryTest {
  public:
diff --git a/components/payments/core/native_error_strings.cc b/components/payments/core/native_error_strings.cc
index 62d3731..c41ef6d1 100644
--- a/components/payments/core/native_error_strings.cc
+++ b/components/payments/core/native_error_strings.cc
@@ -266,5 +266,22 @@
     "The \"secure-payment-confirmation\" method requires a valid URL in the "
     "\"issuerInfo.icon\" field.";
 
+const char kNonNullPaymentEntityLogoRequired[] =
+    "The \"secure-payment-confirmation\" method requires that each entry in "
+    "\"paymentEntitiesLogos\" is non-null.";
+
+extern const char kValidLogoUrlRequired[] =
+    "The \"secure-payment-confirmation\" method requires that each entry in "
+    "\"paymentEntitiesLogos\" has a valid URL in the \"url\" field.";
+
+extern const char kValidLogoUrlSchemeRequired[] =
+    "The \"secure-payment-confirmation\" method requires that each entry in "
+    "\"paymentEntitiesLogos\" has a URL whose scheme is one of \"https\", "
+    "\"http\", or \"data\" in the \"url\" field.";
+
+extern const char kLogoLabelRequired[] =
+    "The \"secure-payment-confirmation\" method requires that each entry in "
+    "\"paymentEntitiesLogos\" has a non-empty \"label\" field.";
+
 }  // namespace errors
 }  // namespace payments
diff --git a/components/payments/core/native_error_strings.h b/components/payments/core/native_error_strings.h
index de8c1ef6..6c44d83d 100644
--- a/components/payments/core/native_error_strings.h
+++ b/components/payments/core/native_error_strings.h
@@ -305,6 +305,24 @@
 // was not a valid URL in the "secure-payment-confirmation" method.
 extern const char kValidIssuerIconRequired[];
 
+// Used when a logo in the paymentEntitiesLogo list is null. A well-behaving
+// renderer cannot end up in this situation, but we must handle it gracefully as
+// renderers cannot be trusted.
+extern const char kNonNullPaymentEntityLogoRequired[];
+
+// Used when a logo in the paymentEntitiesLogo list had a non-valid URL in its
+// url field in the "secure-payment-confirmation" method.
+extern const char kValidLogoUrlRequired[];
+
+// Used when a logo in the paymentEntitiesLogo list had a URL in its url field
+// whose scheme was not one of "https", "http", or "data" in the
+// "secure-payment-confirmation" method.
+extern const char kValidLogoUrlSchemeRequired[];
+
+// Used when a logo in the paymentEntitiesLogo list had an empty label field in
+// the "secure-payment-confirmation" method.
+extern const char kLogoLabelRequired[];
+
 }  // namespace errors
 }  // namespace payments
 
diff --git a/components/permissions/android/java/src/org/chromium/components/permissions/AndroidPermissionRequester.java b/components/permissions/android/java/src/org/chromium/components/permissions/AndroidPermissionRequester.java
index 757aefe..d48e338 100644
--- a/components/permissions/android/java/src/org/chromium/components/permissions/AndroidPermissionRequester.java
+++ b/components/permissions/android/java/src/org/chromium/components/permissions/AndroidPermissionRequester.java
@@ -308,7 +308,7 @@
     public static void showMissingPermissionDialog(
             WindowAndroid windowAndroid,
             String message,
-            Consumer<PropertyModel> onPositiveButtonClicked,
+            Consumer<@Nullable PropertyModel> onPositiveButtonClicked,
             Runnable onCancelled) {
         final ModalDialogManager modalDialogManager = windowAndroid.getModalDialogManager();
         assert modalDialogManager != null : "ModalDialogManager is null";
diff --git a/components/viz/host/BUILD.gn b/components/viz/host/BUILD.gn
index 2f6b8750..a3b2a3e 100644
--- a/components/viz/host/BUILD.gn
+++ b/components/viz/host/BUILD.gn
@@ -37,6 +37,7 @@
 
   deps = [
     "//base",
+    "//components/input",
     "//gpu/ipc/client",
     "//gpu/ipc/common",
     "//services/viz/privileged/mojom",
diff --git a/components/viz/host/DEPS b/components/viz/host/DEPS
index 5074cb6..25676c5 100644
--- a/components/viz/host/DEPS
+++ b/components/viz/host/DEPS
@@ -3,6 +3,7 @@
 include_rules = [
   "+components/discardable_memory/public/mojom",
   "+components/input/render_input_router.mojom.h",
+  "+components/input/utils.h",
   "+gpu/command_buffer/client",
   "+gpu/command_buffer/common",
   "+gpu/config",
diff --git a/components/viz/host/host_frame_sink_manager.cc b/components/viz/host/host_frame_sink_manager.cc
index 6edcf11..c81e547 100644
--- a/components/viz/host/host_frame_sink_manager.cc
+++ b/components/viz/host/host_frame_sink_manager.cc
@@ -16,6 +16,7 @@
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
+#include "components/input/utils.h"
 #include "components/viz/common/performance_hint_utils.h"
 #include "components/viz/common/surfaces/surface_info.h"
 #include "components/viz/host/renderer_settings_creation.h"
@@ -51,6 +52,11 @@
   frame_sink_manager_remote_.set_disconnect_handler(base::BindOnce(
       &HostFrameSinkManager::OnConnectionLost, base::Unretained(this)));
 
+  if (input::InputUtils::IsTransferInputToVizSupported()) {
+    frame_sink_manager_->SetupRendererInputRouterDelegateRegistry(
+        rir_delegate_registry_.BindNewPipeAndPassReceiver());
+  }
+
   if (connection_was_lost_) {
     RegisterAfterConnectionLoss();
     connection_was_lost_ = false;
@@ -309,13 +315,15 @@
 }
 
 void HostFrameSinkManager::SetupRenderInputRouterDelegateConnection(
-    base::UnguessableToken grouping_id,
-    mojo::PendingRemote<input::mojom::RenderInputRouterDelegateClient>
+    const FrameSinkId& frame_sink_id,
+    mojo::PendingAssociatedRemote<input::mojom::RenderInputRouterDelegateClient>
         rir_delegate_client_remote,
-    mojo::PendingReceiver<input::mojom::RenderInputRouterDelegate>
+    mojo::PendingAssociatedReceiver<input::mojom::RenderInputRouterDelegate>
         rir_delegate_receiver) {
-  frame_sink_manager_->SetupRenderInputRouterDelegateConnection(
-      grouping_id, std::move(rir_delegate_client_remote),
+  CHECK(input::InputUtils::IsTransferInputToVizSupported());
+
+  rir_delegate_registry_->SetupRenderInputRouterDelegateConnection(
+      frame_sink_id, std::move(rir_delegate_client_remote),
       std::move(rir_delegate_receiver));
 }
 
@@ -387,6 +395,7 @@
   // frame_sink_manager_remote_.reset() to avoid dangling ptr.
   frame_sink_manager_ = nullptr;
   frame_sink_manager_remote_.reset();
+  rir_delegate_registry_.reset();
 
   metrics_recorder_remote_.reset();
 
diff --git a/components/viz/host/host_frame_sink_manager.h b/components/viz/host/host_frame_sink_manager.h
index 52f93c6..cbb4c12 100644
--- a/components/viz/host/host_frame_sink_manager.h
+++ b/components/viz/host/host_frame_sink_manager.h
@@ -208,17 +208,18 @@
                            std::unique_ptr<CopyOutputRequest> request,
                            bool capture_exact_surface_id = false);
 
-  // Setup the connection between the Browser (at WebContentsImpl level) and the
-  // VizCompositor thread (at InputManager level) to allow transferring
+  // Setup the connection between the Browser (at RenderWidgetHost level) and
+  // the VizCompositor thread (at InputManager level) to allow transferring
   // information from Viz to the Browser and vice versa. Viz can inform Browser
   // about inputs that it process on VizCompositor thread, and Browser can
   // inform Viz about |TouchTransferState| to start processing input events for
   // a sequence.
   void SetupRenderInputRouterDelegateConnection(
-      base::UnguessableToken grouping_id,
-      mojo::PendingRemote<input::mojom::RenderInputRouterDelegateClient>
+      const FrameSinkId& frame_sink_id,
+      mojo::PendingAssociatedRemote<
+          input::mojom::RenderInputRouterDelegateClient>
           rir_delegate_client_remote,
-      mojo::PendingReceiver<input::mojom::RenderInputRouterDelegate>
+      mojo::PendingAssociatedReceiver<input::mojom::RenderInputRouterDelegate>
           rir_delegate_receiver);
 
   // Notifies the VizCompositor thread (at InputManager level) about block state
@@ -371,6 +372,8 @@
           destination_token,
       std::unique_ptr<CopyOutputResult> copy_output_result) override;
 
+  mojo::Remote<mojom::RendererInputRouterDelegateRegistry>
+      rir_delegate_registry_;
   // Connections to/from FrameSinkManagerImpl.
   mojo::Remote<mojom::FrameSinkManager> frame_sink_manager_remote_;
   // This will point to |frame_sink_manager_remote_| if using mojo or it may
diff --git a/components/viz/service/display/display_scheduler.cc b/components/viz/service/display/display_scheduler.cc
index 263df80..7195dc7 100644
--- a/components/viz/service/display/display_scheduler.cc
+++ b/components/viz/service/display/display_scheduler.cc
@@ -387,7 +387,7 @@
   // here the 0.8 constant is chosen to bias rounding up.
   int deadline_max_pending_swaps =
       (total_time_nanos + 0.8 * interval_nanos) / interval_nanos;
-  return std::clamp(deadline_max_pending_swaps, 0, param_max_pending_swaps);
+  return std::clamp(deadline_max_pending_swaps, 1, param_max_pending_swaps);
 }
 
 void DisplayScheduler::SetNeedsOneBeginFrame(bool needs_draw) {
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
index a93d044..774bec5 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -1250,15 +1250,10 @@
   test_api_receiver_.Bind(std::move(receiver));
 }
 
-void FrameSinkManagerImpl::SetupRenderInputRouterDelegateConnection(
-    const base::UnguessableToken& grouping_id,
-    mojo::PendingRemote<input::mojom::RenderInputRouterDelegateClient>
-        rir_delegate_client_remote,
-    mojo::PendingReceiver<input::mojom::RenderInputRouterDelegate>
-        rir_delegate_receiver) {
-  input_manager_->SetupRenderInputRouterDelegateConnection(
-      grouping_id, std::move(rir_delegate_client_remote),
-      std::move(rir_delegate_receiver));
+void FrameSinkManagerImpl::SetupRendererInputRouterDelegateRegistry(
+    mojo::PendingReceiver<mojom::RendererInputRouterDelegateRegistry>
+        receiver) {
+  input_manager_->SetupRendererInputRouterDelegateRegistry(std::move(receiver));
 }
 
 void FrameSinkManagerImpl::NotifyRendererBlockStateChanged(
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.h b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
index 4bff8c9..3ebefa4 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.h
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
@@ -186,12 +186,9 @@
       override;
   void EnableFrameSinkManagerTestApi(
       mojo::PendingReceiver<mojom::FrameSinkManagerTestApi> receiver) override;
-  void SetupRenderInputRouterDelegateConnection(
-      const base::UnguessableToken& grouping_id,
-      mojo::PendingRemote<input::mojom::RenderInputRouterDelegateClient>
-          rir_delegate_client_remote,
-      mojo::PendingReceiver<input::mojom::RenderInputRouterDelegate>
-          rir_delegate_receiver) override;
+  void SetupRendererInputRouterDelegateRegistry(
+      mojo::PendingReceiver<mojom::RendererInputRouterDelegateRegistry>
+          receiver) override;
   void NotifyRendererBlockStateChanged(
       bool blocked,
       const std::vector<FrameSinkId>& render_input_routers) override;
diff --git a/components/viz/service/input/DEPS b/components/viz/service/input/DEPS
index 145c84a..3c939b6 100644
--- a/components/viz/service/input/DEPS
+++ b/components/viz/service/input/DEPS
@@ -2,7 +2,7 @@
 
 include_rules = [
   "+components/viz/service/frame_sinks",
-  "+mojo/public/cpp/bindings/receiver_set.h",
+  "+mojo/public/cpp/bindings/associated_receiver_set.h",
   "+ui/events",
 ]
 
diff --git a/components/viz/service/input/android_state_transfer_handler.cc b/components/viz/service/input/android_state_transfer_handler.cc
index 100f72a..0551d10 100644
--- a/components/viz/service/input/android_state_transfer_handler.cc
+++ b/components/viz/service/input/android_state_transfer_handler.cc
@@ -51,19 +51,12 @@
 
   EmitPendingTransfersHistogram();
 
-  // TODO(crbug.com/383323530): Convert it to CHECK once we are using
-  // AssociatedRemotes for passing state from Browser to Viz.
   const bool state_received_out_of_order =
       (!pending_transferred_states_.empty() &&
        (state->down_time_ms <
         pending_transferred_states_.back().transfer_state->down_time_ms));
-  if (state_received_out_of_order) {
-    TRACE_EVENT_INSTANT("viz", "OutOfOrderTransferStateDropped");
-    // Drop out of order state received.
-    // It is possible since the state transfers coming from different web
-    // contents come over different mojo pipes.
-    return;
-  }
+
+  CHECK(!state_received_out_of_order);
 
   MaybeDropEventsFromEarlierSequences(state);
 
diff --git a/components/viz/service/input/input_manager.cc b/components/viz/service/input/input_manager.cc
index 37c5b36..e057482 100644
--- a/components/viz/service/input/input_manager.cc
+++ b/components/viz/service/input/input_manager.cc
@@ -213,7 +213,7 @@
 
   // |rir_delegate| should outlive |render_input_router|.
   auto rir_delegate = std::make_unique<RenderInputRouterDelegateImpl>(
-      it->second, *this, frame_sink_id, grouping_id);
+      it->second, *this, frame_sink_id);
 
   // Sets up RenderInputRouter.
   auto render_input_router = std::make_unique<input::RenderInputRouter>(
@@ -446,46 +446,13 @@
   return std::move(rirs);
 }
 
-void InputManager::NotifyObserversOfInputEvent(
-    const FrameSinkId& frame_sink_id,
-    const base::UnguessableToken& grouping_id,
-    std::unique_ptr<blink::WebCoalescedInputEvent> event,
-    bool dispatched_to_renderer) {
-  rir_delegate_remote_map_.at(grouping_id)
-      ->NotifyObserversOfInputEvent(frame_sink_id, std::move(event),
-                                    dispatched_to_renderer);
-}
-
-void InputManager::NotifyObserversOfInputEventAcks(
-    const FrameSinkId& frame_sink_id,
-    const base::UnguessableToken& grouping_id,
-    blink::mojom::InputEventResultSource ack_source,
-    blink::mojom::InputEventResultState ack_result,
-    std::unique_ptr<blink::WebCoalescedInputEvent> event) {
-  rir_delegate_remote_map_.at(grouping_id)
-      ->NotifyObserversOfInputEventAcks(frame_sink_id, ack_source, ack_result,
-                                        std::move(event));
-}
-
-void InputManager::OnInvalidInputEventSource(
-    const FrameSinkId& frame_sink_id,
-    const base::UnguessableToken& grouping_id) {
-  rir_delegate_remote_map_.at(grouping_id)
-      ->OnInvalidInputEventSource(frame_sink_id);
-}
-
-void InputManager::RendererInputResponsivenessChanged(
-    const FrameSinkId& frame_sink_id,
-    const base::UnguessableToken& grouping_id,
-    bool is_responsive,
-    std::optional<base::TimeTicks> ack_timeout_ts) {
-  auto itr = rir_delegate_remote_map_.find(grouping_id);
+input::mojom::RenderInputRouterDelegateClient*
+InputManager::GetRIRDelegateClientRemote(const FrameSinkId& frame_sink_id) {
+  auto itr = rir_delegate_remote_map_.find(frame_sink_id);
   if (itr == rir_delegate_remote_map_.end()) {
-    return;
+    return nullptr;
   }
-
-  itr->second->RendererInputResponsivenessChanged(frame_sink_id, is_responsive,
-                                                  std::move(ack_timeout_ts));
+  return itr->second.get();
 }
 
 std::optional<bool> InputManager::IsDelegatedInkHovering(
@@ -499,12 +466,6 @@
       ->delegated_ink_metadata->is_hovering();
 }
 
-void InputManager::DidOverscroll(const FrameSinkId& frame_sink_id,
-                                 const base::UnguessableToken& grouping_id,
-                                 blink::mojom::DidOverscrollParamsPtr params) {
-  rir_delegate_remote_map_.at(grouping_id)
-      ->StateOnOverscrollTransfer(frame_sink_id, std::move(params));
-}
 
 void InputManager::StateOnTouchTransfer(
     input::mojom::TouchTransferStatePtr state) {
@@ -554,12 +515,10 @@
 
 void InputManager::ForceEnableZoomStateChanged(
     bool force_enable_zoom,
-    const std::vector<FrameSinkId>& frame_sink_ids) {
-  for (auto& frame_sink_id : frame_sink_ids) {
-    auto itr = rir_map_.find(frame_sink_id);
-    if (itr != rir_map_.end()) {
-      itr->second->SetForceEnableZoom(force_enable_zoom);
-    }
+    const FrameSinkId& frame_sink_id) {
+  auto itr = rir_map_.find(frame_sink_id);
+  if (itr != rir_map_.end()) {
+    itr->second->SetForceEnableZoom(force_enable_zoom);
   }
 }
 
@@ -606,18 +565,23 @@
 #endif
 }
 
-void InputManager::SetupRenderInputRouterDelegateConnection(
-    const base::UnguessableToken& grouping_id,
-    mojo::PendingRemote<input::mojom::RenderInputRouterDelegateClient>
-        rir_delegate_remote,
-    mojo::PendingReceiver<input::mojom::RenderInputRouterDelegate>
-        rir_delegate_receiver) {
-  TRACE_EVENT("viz", "InputManager::SetupRenderInputRouterDelegateConnection");
+void InputManager::SetupRendererInputRouterDelegateRegistry(
+    mojo::PendingReceiver<mojom::RendererInputRouterDelegateRegistry>
+        receiver) {
+  TRACE_EVENT("viz", "InputManager::SetupRendererInputRouterDelegateRegistry");
+  registry_receiver_.Bind(std::move(receiver));
+}
 
-  rir_delegate_remote_map_[grouping_id].Bind(std::move(rir_delegate_remote));
-  rir_delegate_remote_map_[grouping_id].set_disconnect_handler(
+void InputManager::SetupRenderInputRouterDelegateConnection(
+    const FrameSinkId& frame_sink_id,
+    mojo::PendingAssociatedRemote<input::mojom::RenderInputRouterDelegateClient>
+        rir_delegate_remote,
+    mojo::PendingAssociatedReceiver<input::mojom::RenderInputRouterDelegate>
+        rir_delegate_receiver) {
+  rir_delegate_remote_map_[frame_sink_id].Bind(std::move(rir_delegate_remote));
+  rir_delegate_remote_map_[frame_sink_id].set_disconnect_handler(
       base::BindOnce(&InputManager::OnRIRDelegateClientDisconnected,
-                     base::Unretained(this), grouping_id));
+                     base::Unretained(this), frame_sink_id));
 
   rir_delegate_receivers_.Add(this, std::move(rir_delegate_receiver));
 }
@@ -744,8 +708,8 @@
 }
 
 void InputManager::OnRIRDelegateClientDisconnected(
-    const base::UnguessableToken& grouping_id) {
-  rir_delegate_remote_map_.erase(grouping_id);
+    const FrameSinkId& frame_sink_id) {
+  rir_delegate_remote_map_.erase(frame_sink_id);
 }
 
 #if BUILDFLAG(IS_ANDROID)
diff --git a/components/viz/service/input/input_manager.h b/components/viz/service/input/input_manager.h
index 57849b6..67061a7 100644
--- a/components/viz/service/input/input_manager.h
+++ b/components/viz/service/input/input_manager.h
@@ -20,7 +20,7 @@
 #include "components/viz/service/input/render_input_router_delegate_impl.h"
 #include "components/viz/service/input/render_input_router_support_base.h"
 #include "gpu/ipc/common/surface_handle.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/associated_receiver_set.h"
 
 #if BUILDFLAG(IS_ANDROID)
 #include "components/input/android/input_receiver_data.h"
@@ -62,7 +62,8 @@
 #endif
       public RenderInputRouterSupportBase::Delegate,
       public RenderInputRouterDelegateImpl::Delegate,
-      public input::mojom::RenderInputRouterDelegate {
+      public input::mojom::RenderInputRouterDelegate,
+      public mojom::RendererInputRouterDelegateRegistry {
  public:
   explicit InputManager(FrameSinkManagerImpl* frame_sink_manager);
 
@@ -115,37 +116,16 @@
   // RenderInputRouterDelegateImpl::Delegate implementation.
   std::unique_ptr<input::RenderInputRouterIterator>
   GetEmbeddedRenderInputRouters(const FrameSinkId& id) override;
-  void NotifyObserversOfInputEvent(
-      const FrameSinkId& frame_sink_id,
-      const base::UnguessableToken& grouping_id,
-      std::unique_ptr<blink::WebCoalescedInputEvent> event,
-      bool dispatched_to_renderer) override;
-  void NotifyObserversOfInputEventAcks(
-      const FrameSinkId& frame_sink_id,
-      const base::UnguessableToken& grouping_id,
-      blink::mojom::InputEventResultSource ack_source,
-      blink::mojom::InputEventResultState ack_result,
-      std::unique_ptr<blink::WebCoalescedInputEvent> event) override;
-  void OnInvalidInputEventSource(
-      const FrameSinkId& frame_sink_id,
-      const base::UnguessableToken& grouping_id) override;
-  void RendererInputResponsivenessChanged(
-      const FrameSinkId& frame_sink_id,
-      const base::UnguessableToken& grouping_id,
-      bool is_responsive,
-      std::optional<base::TimeTicks> ack_timeout_ts) override;
+  input::mojom::RenderInputRouterDelegateClient* GetRIRDelegateClientRemote(
+      const FrameSinkId& frame_sink_id) override;
   std::optional<bool> IsDelegatedInkHovering(
       const FrameSinkId& frame_sink_id) override;
-  void DidOverscroll(const FrameSinkId& frame_sink_id,
-                     const base::UnguessableToken& grouping_id,
-                     blink::mojom::DidOverscrollParamsPtr params) override;
   GpuServiceImpl* GetGpuService() override;
 
   // input::mojom::RenderInputRouterDelegate implementation.
   void StateOnTouchTransfer(input::mojom::TouchTransferStatePtr state) override;
-  void ForceEnableZoomStateChanged(
-      bool force_enable_zoom,
-      const std::vector<FrameSinkId>& frame_sink_ids) override;
+  void ForceEnableZoomStateChanged(bool force_enable_zoom,
+                                   const FrameSinkId& frame_sink_id) override;
   void StopFlingingOnViz(const FrameSinkId& frame_sink_id) override;
   void RestartInputEventAckTimeoutIfNecessary(
       const FrameSinkId& frame_sink_id) override;
@@ -154,12 +134,17 @@
   void ResetGestureDetection(
       const FrameSinkId& root_widget_frame_sink_id) override;
 
+  // mojom::RendererInputRouterDelegateRegistry implementation.
   void SetupRenderInputRouterDelegateConnection(
-      const base::UnguessableToken& grouping_id,
-      mojo::PendingRemote<input::mojom::RenderInputRouterDelegateClient>
-          rir_delegate_client_remote,
-      mojo::PendingReceiver<input::mojom::RenderInputRouterDelegate>
-          rir_delegate_receiver);
+      const FrameSinkId& frame_sink_id,
+      mojo::PendingAssociatedRemote<
+          input::mojom::RenderInputRouterDelegateClient> rir_delegate_remote,
+      mojo::PendingAssociatedReceiver<input::mojom::RenderInputRouterDelegate>
+          rir_delegate_receiver) override;
+
+  void SetupRendererInputRouterDelegateRegistry(
+      mojo::PendingReceiver<mojom::RendererInputRouterDelegateRegistry>
+          receiver);
 
   void NotifyRendererBlockStateChanged(bool blocked,
                                        const std::vector<FrameSinkId>& rirs);
@@ -187,8 +172,7 @@
       input::RenderInputRouter* rir,
       const FrameSinkId& frame_sink_id);
 
-  void OnRIRDelegateClientDisconnected(
-      const base::UnguessableToken& grouping_id);
+  void OnRIRDelegateClientDisconnected(const FrameSinkId& frame_sink_id);
 
   void SetupRenderInputRouter(
       input::RenderInputRouter* render_input_router,
@@ -234,14 +218,19 @@
   base::flat_map<FrameSinkId, std::unique_ptr<input::RenderInputRouter>>
       rir_map_;
 
+  mojo::Receiver<mojom::RendererInputRouterDelegateRegistry> registry_receiver_{
+      this};
+
   // Keeps track of RIRDelegateClient connections, which are between
-  // WebContentsImpl (in the Browser) and InputManager (in Viz) using a
-  // CompositorFrameSink grouping_id sent from the browser. This interface is
-  // used by Viz to update browser's state of input event handling in Viz.
-  base::flat_map</*grouping_id=*/base::UnguessableToken,
-                 mojo::Remote<input::mojom::RenderInputRouterDelegateClient>>
+  // RenderWidgetHosts (in the Browser) and InputManager (in Viz) using the
+  // FrameSinkId associated with the RenderWidgetHost sent from the browser.
+  // This interface is used by Viz to update browser's state of input event
+  // handling in Viz.
+  base::flat_map<
+      FrameSinkId,
+      mojo::AssociatedRemote<input::mojom::RenderInputRouterDelegateClient>>
       rir_delegate_remote_map_;
-  mojo::ReceiverSet<input::mojom::RenderInputRouterDelegate>
+  mojo::AssociatedReceiverSet<input::mojom::RenderInputRouterDelegate>
       rir_delegate_receivers_;
 
   raw_ptr<FrameSinkManagerImpl> frame_sink_manager_;
diff --git a/components/viz/service/input/render_input_router_delegate_impl.cc b/components/viz/service/input/render_input_router_delegate_impl.cc
index 05fa958..5b008f24 100644
--- a/components/viz/service/input/render_input_router_delegate_impl.cc
+++ b/components/viz/service/input/render_input_router_delegate_impl.cc
@@ -28,12 +28,10 @@
 RenderInputRouterDelegateImpl::RenderInputRouterDelegateImpl(
     scoped_refptr<input::RenderWidgetHostInputEventRouter> rwhier,
     Delegate& delegate,
-    const FrameSinkId& frame_sink_id,
-    const base::UnguessableToken& grouping_id)
+    const FrameSinkId& frame_sink_id)
     : rwhier_(std::move(rwhier)),
       delegate_(delegate),
-      frame_sink_id_(frame_sink_id),
-      grouping_id_(grouping_id) {
+      frame_sink_id_(frame_sink_id) {
   TRACE_EVENT_INSTANT(
       "input", "RenderInputRouterDelegateImpl::RenderInputRouterDelegateImpl",
       "frame_sink_id", frame_sink_id);
@@ -93,9 +91,9 @@
   auto web_coalesced_event =
       std::make_unique<blink::WebCoalescedInputEvent>(event, ui::LatencyInfo());
 
-  delegate_->NotifyObserversOfInputEvent(frame_sink_id_, grouping_id_,
-                                         std::move(web_coalesced_event),
-                                         dispatched_to_renderer);
+  delegate_->GetRIRDelegateClientRemote(frame_sink_id_)
+      ->NotifyObserversOfInputEvent(std::move(web_coalesced_event),
+                                    dispatched_to_renderer);
 }
 
 void RenderInputRouterDelegateImpl::NotifyObserversOfInputEventAcks(
@@ -108,9 +106,9 @@
   auto web_coalesced_event =
       std::make_unique<blink::WebCoalescedInputEvent>(event, ui::LatencyInfo());
 
-  delegate_->NotifyObserversOfInputEventAcks(frame_sink_id_, grouping_id_,
-                                             ack_source, ack_result,
-                                             std::move(web_coalesced_event));
+  delegate_->GetRIRDelegateClientRemote(frame_sink_id_)
+      ->NotifyObserversOfInputEventAcks(ack_source, ack_result,
+                                        std::move(web_coalesced_event));
 }
 
 bool RenderInputRouterDelegateImpl::IsInitializedAndNotDead() {
@@ -127,7 +125,8 @@
 }
 
 void RenderInputRouterDelegateImpl::OnInvalidInputEventSource() {
-  delegate_->OnInvalidInputEventSource(frame_sink_id_, grouping_id_);
+  delegate_->GetRIRDelegateClientRemote(frame_sink_id_)
+      ->OnInvalidInputEventSource();
 }
 
 std::unique_ptr<PeakGpuMemoryTracker>
@@ -152,8 +151,12 @@
     return;
   }
   is_responsive_ = false;
-  delegate_->RendererInputResponsivenessChanged(
-      frame_sink_id_, grouping_id_, is_responsive_, std::move(ack_timeout_ts));
+  auto* remote = delegate_->GetRIRDelegateClientRemote(frame_sink_id_);
+  if (!remote) {
+    return;
+  }
+  remote->RendererInputResponsivenessChanged(is_responsive_,
+                                             std::move(ack_timeout_ts));
 }
 
 void RenderInputRouterDelegateImpl::RendererIsResponsive() {
@@ -161,8 +164,11 @@
     return;
   }
   is_responsive_ = true;
-  delegate_->RendererInputResponsivenessChanged(frame_sink_id_, grouping_id_,
-                                                is_responsive_, std::nullopt);
+  auto* remote = delegate_->GetRIRDelegateClientRemote(frame_sink_id_);
+  if (!remote) {
+    return;
+  }
+  remote->RendererInputResponsivenessChanged(is_responsive_, std::nullopt);
 }
 
 void RenderInputRouterDelegateImpl::DidOverscroll(
@@ -173,7 +179,8 @@
   // |RenderInputRouterSupportAndroid::GestureEventAck| which calls in
   // StopFlingingIfNecessary, so the decision to stop any fling due to
   // overscroll is handled within the Viz process.
-  delegate_->DidOverscroll(frame_sink_id_, grouping_id_, std::move(params));
+  delegate_->GetRIRDelegateClientRemote(frame_sink_id_)
+      ->StateOnOverscrollTransfer(std::move(params));
 }
 
 }  // namespace viz
diff --git a/components/viz/service/input/render_input_router_delegate_impl.h b/components/viz/service/input/render_input_router_delegate_impl.h
index 8ce42ae..4b576ee 100644
--- a/components/viz/service/input/render_input_router_delegate_impl.h
+++ b/components/viz/service/input/render_input_router_delegate_impl.h
@@ -9,12 +9,12 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "components/input/event_with_latency_info.h"
+#include "components/input/render_input_router.mojom.h"
 #include "components/input/render_input_router_delegate.h"
 #include "components/input/render_input_router_iterator.h"
 #include "components/viz/common/resources/peak_gpu_memory_tracker.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "components/viz/service/viz_service_export.h"
-#include "third_party/blink/public/common/input/web_coalesced_input_event.h"
 
 namespace input {
 class RenderWidgetHostViewInput;
@@ -36,38 +36,17 @@
    public:
     virtual std::unique_ptr<input::RenderInputRouterIterator>
     GetEmbeddedRenderInputRouters(const FrameSinkId& id) = 0;
-    virtual void NotifyObserversOfInputEvent(
-        const FrameSinkId& frame_sink_id,
-        const base::UnguessableToken& grouping_id,
-        std::unique_ptr<blink::WebCoalescedInputEvent> event,
-        bool dispatched_to_renderer) = 0;
-    virtual void NotifyObserversOfInputEventAcks(
-        const FrameSinkId& frame_sink_id,
-        const base::UnguessableToken& grouping_id,
-        blink::mojom::InputEventResultSource ack_source,
-        blink::mojom::InputEventResultState ack_result,
-        std::unique_ptr<blink::WebCoalescedInputEvent> event) = 0;
-    virtual void OnInvalidInputEventSource(
-        const FrameSinkId& frame_sink_id,
-        const base::UnguessableToken& grouping_id) = 0;
-    virtual void RendererInputResponsivenessChanged(
-        const FrameSinkId& frame_sink_id,
-        const base::UnguessableToken& grouping_id,
-        bool is_responsive,
-        std::optional<base::TimeTicks> ack_timeout_ts) = 0;
+    virtual input::mojom::RenderInputRouterDelegateClient*
+    GetRIRDelegateClientRemote(const FrameSinkId& frame_sink_id) = 0;
     virtual std::optional<bool> IsDelegatedInkHovering(
         const FrameSinkId& frame_sink_id) = 0;
-    virtual void DidOverscroll(const FrameSinkId& frame_sink_id,
-                               const base::UnguessableToken& grouping_id,
-                               blink::mojom::DidOverscrollParamsPtr params) = 0;
     virtual GpuServiceImpl* GetGpuService() = 0;
   };
 
   RenderInputRouterDelegateImpl(
       scoped_refptr<input::RenderWidgetHostInputEventRouter> rwhier,
       Delegate& delegate,
-      const FrameSinkId& frame_sink_id,
-      const base::UnguessableToken& grouping_id);
+      const FrameSinkId& frame_sink_id);
 
   ~RenderInputRouterDelegateImpl() override;
 
@@ -117,7 +96,6 @@
   scoped_refptr<input::RenderWidgetHostInputEventRouter> rwhier_;
   raw_ref<Delegate> delegate_;
   const FrameSinkId frame_sink_id_;
-  const base::UnguessableToken grouping_id_;
 };
 
 }  // namespace viz
diff --git a/components/viz/test/test_frame_sink_manager.h b/components/viz/test/test_frame_sink_manager.h
index d3700d5..df110e53 100644
--- a/components/viz/test/test_frame_sink_manager.h
+++ b/components/viz/test/test_frame_sink_manager.h
@@ -91,12 +91,9 @@
   void EnableFrameSinkManagerTestApi(
       mojo::PendingReceiver<mojom::FrameSinkManagerTestApi> receiver) override {
   }
-  void SetupRenderInputRouterDelegateConnection(
-      const base::UnguessableToken& grouping_id,
-      mojo::PendingRemote<input::mojom::RenderInputRouterDelegateClient>
-          rir_delegate_client_remote,
-      mojo::PendingReceiver<input::mojom::RenderInputRouterDelegate>
-          rir_delegate_receiver) override {}
+  void SetupRendererInputRouterDelegateRegistry(
+      mojo::PendingReceiver<mojom::RendererInputRouterDelegateRegistry>
+          receiver) override {}
   void NotifyRendererBlockStateChanged(
       bool blocked,
       const std::vector<FrameSinkId>& render_input_routers) override {}
diff --git a/components/webapps/isolated_web_apps/iwa_key_distribution_info_provider.cc b/components/webapps/isolated_web_apps/iwa_key_distribution_info_provider.cc
index 8a973b2..8426108 100644
--- a/components/webapps/isolated_web_apps/iwa_key_distribution_info_provider.cc
+++ b/components/webapps/isolated_web_apps/iwa_key_distribution_info_provider.cc
@@ -201,7 +201,9 @@
 }
 
 void IwaKeyDistributionInfoProvider::SetUp(
+    bool is_on_demand_supported,
     QueueOnDemandUpdateCallback callback) {
+  is_on_demand_supported_ = is_on_demand_supported;
   queue_on_demand_update_ = callback;
 }
 
@@ -299,7 +301,7 @@
 
 base::OneShotEvent&
 IwaKeyDistributionInfoProvider::OnMaybeDownloadedComponentDataReady() {
-  if (!queue_on_demand_update_) {
+  if (!is_on_demand_supported_) {
     return AlreadySignalled();
   }
 
@@ -408,6 +410,7 @@
 void IwaKeyDistributionInfoProvider::MaybeQueueComponentUpdate() {
   CHECK(maybe_queue_component_update_posted_);
   CHECK(any_data_ready_.is_signaled());
+  CHECK(is_on_demand_supported_);
   CHECK(queue_on_demand_update_);
 
   if (!data_ || data_->is_preloaded) {
diff --git a/components/webapps/isolated_web_apps/iwa_key_distribution_info_provider.h b/components/webapps/isolated_web_apps/iwa_key_distribution_info_provider.h
index 7fe3246..459c4aa 100644
--- a/components/webapps/isolated_web_apps/iwa_key_distribution_info_provider.h
+++ b/components/webapps/isolated_web_apps/iwa_key_distribution_info_provider.h
@@ -111,7 +111,7 @@
 
   // Sets up the `IwaKeyDistributionInfoProvider`, i.e. adds the capability to
   // schedule on demand callbacks.
-  void SetUp(QueueOnDemandUpdateCallback callback);
+  void SetUp(bool is_on_demand_supported, QueueOnDemandUpdateCallback callback);
 
   // Asynchronously loads new component data and replaces the current `data_`
   // upon success and if `component_version` is greater than the stored one, and
@@ -188,6 +188,7 @@
   base::OneShotEvent maybe_downloaded_data_ready_;
 
   bool maybe_queue_component_update_posted_ = false;
+  bool is_on_demand_supported_ = false;
 
   QueueOnDemandUpdateCallback queue_on_demand_update_;
 
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 933abcca..6d414af 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1902,6 +1902,8 @@
     "renderer_host/mixed_content_checker.h",
     "renderer_host/mixed_content_navigation_throttle.cc",
     "renderer_host/mixed_content_navigation_throttle.h",
+    "renderer_host/mojo_render_input_router_delegate_impl.cc",
+    "renderer_host/mojo_render_input_router_delegate_impl.h",
     "renderer_host/navigation_controller_delegate.h",
     "renderer_host/navigation_controller_impl.cc",
     "renderer_host/navigation_controller_impl.h",
diff --git a/content/browser/devtools/protocol/storage_handler.cc b/content/browser/devtools/protocol/storage_handler.cc
index 563ef15..6127e1a 100644
--- a/content/browser/devtools/protocol/storage_handler.cc
+++ b/content/browser/devtools/protocol/storage_handler.cc
@@ -1667,7 +1667,6 @@
     SharedStorageRuntimeManager::SharedStorageObserverInterface::AccessMethod
         method,
     int operation_id,
-    int worklet_ordinal_id,
     const base::UnguessableToken& worklet_devtools_token,
     GlobalRenderFrameHostId main_frame_id,
     const std::string& owner_origin) {
diff --git a/content/browser/devtools/protocol/storage_handler.h b/content/browser/devtools/protocol/storage_handler.h
index d428463..0b98bef 100644
--- a/content/browser/devtools/protocol/storage_handler.h
+++ b/content/browser/devtools/protocol/storage_handler.h
@@ -242,7 +242,6 @@
       SharedStorageRuntimeManager::SharedStorageObserverInterface::AccessMethod
           method,
       int operation_id,
-      int worklet_ordinal_id,
       const base::UnguessableToken& worklet_devtools_token,
       GlobalRenderFrameHostId main_frame_id,
       const std::string& owner_origin) override;
diff --git a/content/browser/picture_in_picture/document_picture_in_picture_navigation_throttle.cc b/content/browser/picture_in_picture/document_picture_in_picture_navigation_throttle.cc
index 1a194290..87189a8 100644
--- a/content/browser/picture_in_picture/document_picture_in_picture_navigation_throttle.cc
+++ b/content/browser/picture_in_picture/document_picture_in_picture_navigation_throttle.cc
@@ -14,30 +14,32 @@
 namespace content {
 
 // static
-std::unique_ptr<DocumentPictureInPictureNavigationThrottle>
-DocumentPictureInPictureNavigationThrottle::MaybeCreateThrottleFor(
-    NavigationHandle* handle) {
+void DocumentPictureInPictureNavigationThrottle::MaybeCreateAndAdd(
+    NavigationThrottleRegistry& registry) {
   // We prevent the main frame of document picture-in-picture windows from doing
   // cross-document navigation.
-  if (!handle->IsInMainFrame() || handle->IsSameDocument() ||
-      !handle->GetWebContents() ||
-      !handle->GetWebContents()->GetPictureInPictureOptions().has_value()) {
-    return nullptr;
+  NavigationHandle& handle = registry.GetNavigationHandle();
+  if (!handle.IsInMainFrame() || handle.IsSameDocument() ||
+      !handle.GetWebContents() ||
+      !handle.GetWebContents()->GetPictureInPictureOptions().has_value()) {
+    return;
   }
   // Allow a command-line flag to opt-out of navigation throttling.
   if (base::FeatureList::IsEnabled(
           media::kDocumentPictureInPictureNavigation)) {
-    return nullptr;
+    return;
   }
-  return std::make_unique<DocumentPictureInPictureNavigationThrottle>(
-      base::PassKey<DocumentPictureInPictureNavigationThrottle>(), handle);
+  registry.AddThrottle(
+      std::make_unique<DocumentPictureInPictureNavigationThrottle>(
+          base::PassKey<DocumentPictureInPictureNavigationThrottle>(),
+          registry));
 }
 
 DocumentPictureInPictureNavigationThrottle::
     DocumentPictureInPictureNavigationThrottle(
         base::PassKey<DocumentPictureInPictureNavigationThrottle>,
-        NavigationHandle* handle)
-    : NavigationThrottle(handle) {}
+        NavigationThrottleRegistry& registry)
+    : NavigationThrottle(registry) {}
 
 DocumentPictureInPictureNavigationThrottle::
     ~DocumentPictureInPictureNavigationThrottle() = default;
diff --git a/content/browser/picture_in_picture/document_picture_in_picture_navigation_throttle.h b/content/browser/picture_in_picture/document_picture_in_picture_navigation_throttle.h
index 481b42289..9813a54 100644
--- a/content/browser/picture_in_picture/document_picture_in_picture_navigation_throttle.h
+++ b/content/browser/picture_in_picture/document_picture_in_picture_navigation_throttle.h
@@ -5,8 +5,6 @@
 #ifndef CONTENT_BROWSER_PICTURE_IN_PICTURE_DOCUMENT_PICTURE_IN_PICTURE_NAVIGATION_THROTTLE_H_
 #define CONTENT_BROWSER_PICTURE_IN_PICTURE_DOCUMENT_PICTURE_IN_PICTURE_NAVIGATION_THROTTLE_H_
 
-#include <memory>
-
 #include "base/types/pass_key.h"
 #include "content/public/browser/navigation_throttle.h"
 
@@ -17,12 +15,11 @@
 // to navigate.
 class DocumentPictureInPictureNavigationThrottle : public NavigationThrottle {
  public:
-  static std::unique_ptr<DocumentPictureInPictureNavigationThrottle>
-  MaybeCreateThrottleFor(NavigationHandle* handle);
+  static void MaybeCreateAndAdd(NavigationThrottleRegistry& registry);
 
   DocumentPictureInPictureNavigationThrottle(
       base::PassKey<DocumentPictureInPictureNavigationThrottle>,
-      NavigationHandle* handle);
+      NavigationThrottleRegistry& registry);
   DocumentPictureInPictureNavigationThrottle(
       const DocumentPictureInPictureNavigationThrottle&) = delete;
   DocumentPictureInPictureNavigationThrottle& operator=(
diff --git a/content/browser/preloading/prefetch/contamination_delay_navigation_throttle.cc b/content/browser/preloading/prefetch/contamination_delay_navigation_throttle.cc
index 8cd0997..b3033a7 100644
--- a/content/browser/preloading/prefetch/contamination_delay_navigation_throttle.cc
+++ b/content/browser/preloading/prefetch/contamination_delay_navigation_throttle.cc
@@ -4,11 +4,22 @@
 
 #include "content/browser/preloading/prefetch/contamination_delay_navigation_throttle.h"
 
+#include "content/browser/preloading/prefetch/prefetch_features.h"
 #include "content/browser/renderer_host/navigation_request.h"
 #include "content/public/browser/navigation_handle.h"
 
 namespace content {
 
+// static
+void ContaminationDelayNavigationThrottle::MaybeCreateAndAdd(
+    NavigationThrottleRegistry& registry) {
+  if (base::FeatureList::IsEnabled(
+          features::kPrefetchStateContaminationMitigation)) {
+    registry.AddThrottle(
+        std::make_unique<ContaminationDelayNavigationThrottle>(registry));
+  }
+}
+
 ContaminationDelayNavigationThrottle::~ContaminationDelayNavigationThrottle() =
     default;
 
diff --git a/content/browser/preloading/prefetch/contamination_delay_navigation_throttle.h b/content/browser/preloading/prefetch/contamination_delay_navigation_throttle.h
index 18daab8..999b7e2 100644
--- a/content/browser/preloading/prefetch/contamination_delay_navigation_throttle.h
+++ b/content/browser/preloading/prefetch/contamination_delay_navigation_throttle.h
@@ -15,6 +15,8 @@
 // commit would otherwise reveal information about those checks.
 class ContaminationDelayNavigationThrottle : public NavigationThrottle {
  public:
+  static void MaybeCreateAndAdd(NavigationThrottleRegistry& registry);
+
   using NavigationThrottle::NavigationThrottle;
   ~ContaminationDelayNavigationThrottle() override;
 
diff --git a/content/browser/preloading/prerender/prerender_navigation_throttle.cc b/content/browser/preloading/prerender/prerender_navigation_throttle.cc
index 67a8e23..172ff2a 100644
--- a/content/browser/preloading/prerender/prerender_navigation_throttle.cc
+++ b/content/browser/preloading/prerender/prerender_navigation_throttle.cc
@@ -58,21 +58,20 @@
 
 }  // namespace
 
-PrerenderNavigationThrottle::~PrerenderNavigationThrottle() = default;
-
 // static
-std::unique_ptr<PrerenderNavigationThrottle>
-PrerenderNavigationThrottle::MaybeCreateThrottleFor(
-    NavigationHandle* navigation_handle) {
-  auto* navigation_request = NavigationRequest::From(navigation_handle);
+void PrerenderNavigationThrottle::MaybeCreateAndAdd(
+    NavigationThrottleRegistry& registry) {
+  auto* navigation_request =
+      NavigationRequest::From(&registry.GetNavigationHandle());
   FrameTreeNode* frame_tree_node = navigation_request->frame_tree_node();
   if (frame_tree_node->GetFrameType() == FrameType::kPrerenderMainFrame) {
-    return base::WrapUnique(
-        new PrerenderNavigationThrottle(navigation_request));
+    registry.AddThrottle(
+        base::WrapUnique(new PrerenderNavigationThrottle(registry)));
   }
-  return nullptr;
 }
 
+PrerenderNavigationThrottle::~PrerenderNavigationThrottle() = default;
+
 const char* PrerenderNavigationThrottle::GetNameForLogging() {
   return "PrerenderNavigationThrottle";
 }
@@ -88,10 +87,13 @@
 }
 
 PrerenderNavigationThrottle::PrerenderNavigationThrottle(
-    NavigationRequest* navigation_request)
-    : NavigationThrottle(navigation_request),
+    NavigationThrottleRegistry& registry)
+    : NavigationThrottle(registry),
       prerender_host_(static_cast<PrerenderHost*>(
-          navigation_request->frame_tree_node()->frame_tree().delegate())) {
+          NavigationRequest::From(&registry.GetNavigationHandle())
+              ->frame_tree_node()
+              ->frame_tree()
+              .delegate())) {
   CHECK(prerender_host_);
 
   // This throttle is responsible for setting the initial navigation id on the
@@ -102,7 +104,8 @@
     // will later cancel the navigation in Will*Request(). Just do nothing
     // until then.
   } else {
-    prerender_host_->SetInitialNavigation(navigation_request);
+    prerender_host_->SetInitialNavigation(
+        NavigationRequest::From(&registry.GetNavigationHandle()));
   }
 }
 
diff --git a/content/browser/preloading/prerender/prerender_navigation_throttle.h b/content/browser/preloading/prerender/prerender_navigation_throttle.h
index 09805eed..83e13ea 100644
--- a/content/browser/preloading/prerender/prerender_navigation_throttle.h
+++ b/content/browser/preloading/prerender/prerender_navigation_throttle.h
@@ -9,7 +9,6 @@
 
 namespace content {
 
-class NavigationRequest;
 class PrerenderHost;
 enum class PrerenderFinalStatus;
 
@@ -22,10 +21,9 @@
 // - Cross-origin navigation from a prerendered page
 class PrerenderNavigationThrottle : public NavigationThrottle {
  public:
-  ~PrerenderNavigationThrottle() override;
+  static void MaybeCreateAndAdd(NavigationThrottleRegistry& registry);
 
-  static std::unique_ptr<PrerenderNavigationThrottle> MaybeCreateThrottleFor(
-      NavigationHandle* navigation_handle);
+  ~PrerenderNavigationThrottle() override;
 
   // NavigationThrottle
   const char* GetNameForLogging() override;
@@ -34,7 +32,7 @@
   ThrottleCheckResult WillProcessResponse() override;
 
  private:
-  explicit PrerenderNavigationThrottle(NavigationRequest* navigation_request);
+  explicit PrerenderNavigationThrottle(NavigationThrottleRegistry& registry);
 
   ThrottleCheckResult WillStartOrRedirectRequest(bool is_redirection);
 
diff --git a/content/browser/preloading/prerender/prerender_subframe_navigation_throttle.cc b/content/browser/preloading/prerender/prerender_subframe_navigation_throttle.cc
index c8501d8c..47ff78f 100644
--- a/content/browser/preloading/prerender/prerender_subframe_navigation_throttle.cc
+++ b/content/browser/preloading/prerender/prerender_subframe_navigation_throttle.cc
@@ -17,28 +17,29 @@
 namespace content {
 
 // static
-std::unique_ptr<PrerenderSubframeNavigationThrottle>
-PrerenderSubframeNavigationThrottle::MaybeCreateThrottleFor(
-    NavigationHandle* navigation_handle) {
-  auto* navigation_request = NavigationRequest::From(navigation_handle);
+void PrerenderSubframeNavigationThrottle::MaybeCreateAndAdd(
+    NavigationThrottleRegistry& registry) {
+  auto* navigation_request =
+      NavigationRequest::From(&registry.GetNavigationHandle());
   FrameTreeNode* frame_tree_node = navigation_request->frame_tree_node();
   if (frame_tree_node->IsMainFrame() ||
       !frame_tree_node->frame_tree().is_prerendering()) {
-    return nullptr;
+    return;
   }
 
-  return base::WrapUnique(
-      new PrerenderSubframeNavigationThrottle(navigation_handle));
+  registry.AddThrottle(
+      base::WrapUnique(new PrerenderSubframeNavigationThrottle(registry)));
 }
 
 PrerenderSubframeNavigationThrottle::PrerenderSubframeNavigationThrottle(
-    NavigationHandle* nav_handle)
-    : NavigationThrottle(nav_handle),
-      prerender_root_ftn_id_(NavigationRequest::From(nav_handle)
-                                 ->frame_tree_node()
-                                 ->frame_tree()
-                                 .root()
-                                 ->frame_tree_node_id()) {}
+    NavigationThrottleRegistry& registry)
+    : NavigationThrottle(registry),
+      prerender_root_ftn_id_(
+          NavigationRequest::From(&registry.GetNavigationHandle())
+              ->frame_tree_node()
+              ->frame_tree()
+              .root()
+              ->frame_tree_node_id()) {}
 
 PrerenderSubframeNavigationThrottle::~PrerenderSubframeNavigationThrottle() =
     default;
@@ -61,8 +62,9 @@
 PrerenderSubframeNavigationThrottle::WillProcessResponse() {
   auto* navigation_request = NavigationRequest::From(navigation_handle());
   FrameTreeNode* frame_tree_node = navigation_request->frame_tree_node();
-  if (!frame_tree_node->frame_tree().is_prerendering())
+  if (!frame_tree_node->frame_tree().is_prerendering()) {
     return NavigationThrottle::PROCEED;
+  }
 
   // TODO(crbug.com/40222993): Delay until activation instead of cancellation.
   if (navigation_handle()->IsDownload()) {
@@ -80,8 +82,9 @@
   // Don't run cross-origin subframe navigation check for non-renderable
   // contents like 204/205 as their GetOriginToCommit() is invalid. In this
   // case, we can safely proceed with navigation without deferring it.
-  if (!navigation_request->response_should_be_rendered())
+  if (!navigation_request->response_should_be_rendered()) {
     return PROCEED;
+  }
 
   // Defer cross-origin subframe navigation until page activation. The check is
   // added here, because this is the first place that the throttle can properly
@@ -123,8 +126,9 @@
   // prerendering frame tree that this subframe navigation started in.
   auto* finished_navigation = NavigationRequest::From(nav_handle);
   if (finished_navigation->prerender_frame_tree_node_id() !=
-      prerender_root_ftn_id_)
+      prerender_root_ftn_id_) {
     return;
+  }
 
   // The activation is finished. There is no need to listen to the WebContents
   // anymore.
@@ -133,12 +137,14 @@
   // If the finished navigation did not commit, do not Resume(). We expect that
   // the prerendered page and therefore the subframe navigation will eventually
   // be cancelled.
-  if (!finished_navigation->HasCommitted())
+  if (!finished_navigation->HasCommitted()) {
     return;
+  }
 
   // Resume the subframe navigation.
-  if (!is_deferred_)
+  if (!is_deferred_) {
     return;
+  }
   is_deferred_ = false;
   Resume();
   // Resume() may have deleted `this`.
@@ -197,8 +203,9 @@
   CHECK(!frame_tree_node->IsMainFrame());
 
   // Proceed if the page isn't in the prerendering state.
-  if (!frame_tree_node->frame_tree().is_prerendering())
+  if (!frame_tree_node->frame_tree().is_prerendering()) {
     return NavigationThrottle::PROCEED;
+  }
 
   // Defer cross-origin subframe navigation until page activation.
   // Using url::Origin::Create() to check same-origin might not be
@@ -212,8 +219,9 @@
   // through the NavigationThrottle, so it's not a problem here
   RenderFrameHostImpl* rfhi = frame_tree_node->frame_tree().GetMainFrame();
   const url::Origin& main_origin = rfhi->GetLastCommittedOrigin();
-  if (!main_origin.IsSameOriginWith(navigation_handle()->GetURL()))
+  if (!main_origin.IsSameOriginWith(navigation_handle()->GetURL())) {
     return DeferOrCancelCrossOriginSubframeNavigation(*frame_tree_node);
+  }
 
   return NavigationThrottle::PROCEED;
 }
diff --git a/content/browser/preloading/prerender/prerender_subframe_navigation_throttle.h b/content/browser/preloading/prerender/prerender_subframe_navigation_throttle.h
index 2ade680..9e08e02 100644
--- a/content/browser/preloading/prerender/prerender_subframe_navigation_throttle.h
+++ b/content/browser/preloading/prerender/prerender_subframe_navigation_throttle.h
@@ -23,12 +23,11 @@
  public:
   ~PrerenderSubframeNavigationThrottle() override;
 
-  static std::unique_ptr<PrerenderSubframeNavigationThrottle>
-  MaybeCreateThrottleFor(NavigationHandle* navigation_handle);
+  static void MaybeCreateAndAdd(NavigationThrottleRegistry& registry);
 
  private:
   explicit PrerenderSubframeNavigationThrottle(
-      NavigationHandle* navigation_handle);
+          NavigationThrottleRegistry& registry);
 
   // NavigationThrottle
   const char* GetNameForLogging() override;
diff --git a/content/browser/renderer_host/ancestor_throttle.cc b/content/browser/renderer_host/ancestor_throttle.cc
index 861a31a..b8da850 100644
--- a/content/browser/renderer_host/ancestor_throttle.cc
+++ b/content/browser/renderer_host/ancestor_throttle.cc
@@ -94,11 +94,10 @@
 }  // namespace
 
 // static
-std::unique_ptr<NavigationThrottle> AncestorThrottle::MaybeCreateThrottleFor(
-    NavigationHandle* handle) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+void AncestorThrottle::CreateAndAdd(NavigationThrottleRegistry& registry) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  return base::WrapUnique(new AncestorThrottle(handle));
+  registry.AddThrottle(base::WrapUnique(new AncestorThrottle(registry)));
 }
 
 AncestorThrottle::~AncestorThrottle() {}
@@ -164,8 +163,8 @@
   return "AncestorThrottle";
 }
 
-AncestorThrottle::AncestorThrottle(NavigationHandle* handle)
-    : NavigationThrottle(handle) {}
+AncestorThrottle::AncestorThrottle(NavigationThrottleRegistry& registry)
+    : NavigationThrottle(registry) {}
 
 void AncestorThrottle::ParseXFrameOptionsError(
     const net::HttpResponseHeaders* headers,
diff --git a/content/browser/renderer_host/ancestor_throttle.h b/content/browser/renderer_host/ancestor_throttle.h
index bf4aaee..de03d39 100644
--- a/content/browser/renderer_host/ancestor_throttle.h
+++ b/content/browser/renderer_host/ancestor_throttle.h
@@ -20,14 +20,12 @@
 }
 
 namespace content {
-class NavigationHandle;
 
 // An AncestorThrottle is responsible for enforcing a resource's embedding
 // rules, and blocking requests which violate them.
 class CONTENT_EXPORT AncestorThrottle : public NavigationThrottle {
  public:
-  static std::unique_ptr<NavigationThrottle> MaybeCreateThrottleFor(
-      NavigationHandle* handle);
+  static void CreateAndAdd(NavigationThrottleRegistry& registry);
 
   AncestorThrottle(const AncestorThrottle&) = delete;
   AncestorThrottle& operator=(const AncestorThrottle&) = delete;
@@ -47,7 +45,7 @@
   FRIEND_TEST_ALL_PREFIXES(AncestorThrottleTest,
                            IgnoreWhenFrameAncestorsPresent);
 
-  explicit AncestorThrottle(NavigationHandle* handle);
+  explicit AncestorThrottle(NavigationThrottleRegistry& registry);
   NavigationThrottle::ThrottleCheckResult ProcessResponseImpl(
       LoggingDisposition logging,
       bool is_response_check);
diff --git a/content/browser/renderer_host/blocked_scheme_navigation_throttle.cc b/content/browser/renderer_host/blocked_scheme_navigation_throttle.cc
index 58ab425..810f4900 100644
--- a/content/browser/renderer_host/blocked_scheme_navigation_throttle.cc
+++ b/content/browser/renderer_host/blocked_scheme_navigation_throttle.cc
@@ -32,22 +32,24 @@
           url, blink::StorageKey::CreateFirstParty(url::Origin::Create(url)));
   return file_system_url.is_valid();
 }
-}
+}  // namespace
 
 BlockedSchemeNavigationThrottle::BlockedSchemeNavigationThrottle(
-    NavigationHandle* navigation_handle)
-    : NavigationThrottle(navigation_handle) {}
+    NavigationThrottleRegistry& registry)
+    : NavigationThrottle(registry) {}
 
 BlockedSchemeNavigationThrottle::~BlockedSchemeNavigationThrottle() {}
 
 NavigationThrottle::ThrottleCheckResult
 BlockedSchemeNavigationThrottle::WillStartRequest() {
   NavigationRequest* request = NavigationRequest::From(navigation_handle());
-  if (!request->GetURL().SchemeIs(url::kFileSystemScheme))
+  if (!request->GetURL().SchemeIs(url::kFileSystemScheme)) {
     return PROCEED;
+  }
 
-  if (base::FeatureList::IsEnabled(blink::features::kFileSystemUrlNavigation))
+  if (base::FeatureList::IsEnabled(blink::features::kFileSystemUrlNavigation)) {
     return PROCEED;
+  }
 
   RenderFrameHost* top_frame =
       request->frame_tree_node()->frame_tree().root()->current_frame_host();
@@ -75,8 +77,9 @@
 NavigationThrottle::ThrottleCheckResult
 BlockedSchemeNavigationThrottle::WillProcessResponse() {
   NavigationRequest* request = NavigationRequest::From(navigation_handle());
-  if (request->IsDownload())
+  if (request->IsDownload()) {
     return PROCEED;
+  }
 
   RenderFrameHost* top_frame =
       request->frame_tree_node()->frame_tree().root()->current_frame_host();
@@ -92,30 +95,29 @@
 }
 
 // static
-std::unique_ptr<NavigationThrottle>
-BlockedSchemeNavigationThrottle::CreateThrottleForNavigation(
-    NavigationHandle* navigation_handle) {
-  NavigationRequest* request = NavigationRequest::From(navigation_handle);
+void BlockedSchemeNavigationThrottle::MaybeCreateAndAdd(
+    NavigationThrottleRegistry& registry) {
+  NavigationHandle& handle = registry.GetNavigationHandle();
   // Create throttles when going to blocked schemes via renderer-initiated
   // navigations (which are cross-document in the main frame). Note that history
   // navigations can bypass this, because the blocked scheme must have
   // originally committed in a permitted case (e.g., omnibox navigation).
-  if (request->IsInMainFrame() && request->IsRendererInitiated() &&
-      !request->IsSameDocument() &&
-      !NavigationTypeUtils::IsHistory(
-          request->common_params().navigation_type) &&
-      (request->GetURL().SchemeIs(url::kDataScheme) ||
-       request->GetURL().SchemeIs(url::kFileSystemScheme)) &&
+  if (handle.IsInMainFrame() && handle.IsRendererInitiated() &&
+      !handle.IsSameDocument() && !handle.IsHistory() &&
+      (handle.GetURL().SchemeIs(url::kDataScheme) ||
+       handle.GetURL().SchemeIs(url::kFileSystemScheme)) &&
       !base::FeatureList::IsEnabled(
           features::kAllowContentInitiatedDataUrlNavigations)) {
-    return std::make_unique<BlockedSchemeNavigationThrottle>(request);
+    registry.AddThrottle(
+        std::make_unique<BlockedSchemeNavigationThrottle>(registry));
+    return;
   }
   // Block all renderer initiated navigations to filesystem: URLs except for
   // when explicitly allowed by the embedder. These won't load anyway since no
   // URL Loader exists for them, but the throttle lets us add a message to the
   // console.
   RenderFrameHost* current_frame_host =
-      request->frame_tree_node()->current_frame_host();
+      NavigationRequest::From(&handle)->frame_tree_node()->current_frame_host();
   BrowserContext* browser_context = current_frame_host->GetBrowserContext();
   // A navigation is permitted if the relevant feature flag is enabled, the
   // request origin is equivalent to the initiator origin, and the embedder
@@ -123,24 +125,25 @@
   bool is_navigation_allowed =
       base::FeatureList::IsEnabled(
           blink::features::kFileSystemUrlNavigationForChromeAppsOnly) &&
-      (url::Origin::Create(request->GetURL()) ==
-       request->GetInitiatorOrigin()) &&
+      (url::Origin::Create(handle.GetURL()) == handle.GetInitiatorOrigin()) &&
       GetContentClient()->browser()->IsFileSystemURLNavigationAllowed(
-          browser_context, request->GetURL());
+          browser_context, handle.GetURL());
   if (!is_navigation_allowed &&
       !base::FeatureList::IsEnabled(
           blink::features::kFileSystemUrlNavigation) &&
-      request->IsRendererInitiated() &&
-      request->GetURL().SchemeIs(url::kFileSystemScheme)) {
-    return std::make_unique<BlockedSchemeNavigationThrottle>(request);
+      handle.IsRendererInitiated() &&
+      handle.GetURL().SchemeIs(url::kFileSystemScheme)) {
+    registry.AddThrottle(
+        std::make_unique<BlockedSchemeNavigationThrottle>(registry));
+    return;
   }
   // Block any external mounted files.
   if (!base::FeatureList::IsEnabled(
           blink::features::kFileSystemUrlNavigation) &&
-      IsExternalMountedFile(request->GetURL())) {
-    return std::make_unique<BlockedSchemeNavigationThrottle>(request);
+      IsExternalMountedFile(handle.GetURL())) {
+    registry.AddThrottle(
+        std::make_unique<BlockedSchemeNavigationThrottle>(registry));
   }
-  return nullptr;
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/blocked_scheme_navigation_throttle.h b/content/browser/renderer_host/blocked_scheme_navigation_throttle.h
index a4ebb68f..cb759cb2 100644
--- a/content/browser/renderer_host/blocked_scheme_navigation_throttle.h
+++ b/content/browser/renderer_host/blocked_scheme_navigation_throttle.h
@@ -5,8 +5,6 @@
 #ifndef CONTENT_BROWSER_RENDERER_HOST_BLOCKED_SCHEME_NAVIGATION_THROTTLE_H_
 #define CONTENT_BROWSER_RENDERER_HOST_BLOCKED_SCHEME_NAVIGATION_THROTTLE_H_
 
-#include <memory>
-
 #include "content/public/browser/navigation_throttle.h"
 
 namespace content {
@@ -15,7 +13,8 @@
 // (currently data: and filesystem:).
 class BlockedSchemeNavigationThrottle : public NavigationThrottle {
  public:
-  explicit BlockedSchemeNavigationThrottle(NavigationHandle* navigation_handle);
+  explicit BlockedSchemeNavigationThrottle(
+      NavigationThrottleRegistry& registry);
 
   BlockedSchemeNavigationThrottle(const BlockedSchemeNavigationThrottle&) =
       delete;
@@ -29,8 +28,7 @@
   ThrottleCheckResult WillProcessResponse() override;
   const char* GetNameForLogging() override;
 
-  static std::unique_ptr<NavigationThrottle> CreateThrottleForNavigation(
-      NavigationHandle* navigation_handle);
+  static void MaybeCreateAndAdd(NavigationThrottleRegistry& registry);
 };
 
 }  // namespace content
diff --git a/content/browser/renderer_host/isolated_web_app_throttle.cc b/content/browser/renderer_host/isolated_web_app_throttle.cc
index b6158e1..71e7c46 100644
--- a/content/browser/renderer_host/isolated_web_app_throttle.cc
+++ b/content/browser/renderer_host/isolated_web_app_throttle.cc
@@ -72,23 +72,23 @@
 }  // namespace
 
 // static
-std::unique_ptr<IsolatedWebAppThrottle>
-IsolatedWebAppThrottle::MaybeCreateThrottleFor(NavigationHandle* handle) {
-  BrowserContext* browser_context = NavigationRequest::From(handle)
-                                        ->frame_tree_node()
-                                        ->navigator()
-                                        .controller()
-                                        .GetBrowserContext();
+void IsolatedWebAppThrottle::MaybeCreateAndAdd(
+    NavigationThrottleRegistry& registry) {
+  BrowserContext* browser_context =
+      NavigationRequest::From(&registry.GetNavigationHandle())
+          ->frame_tree_node()
+          ->navigator()
+          .controller()
+          .GetBrowserContext();
 
   if (AreIsolatedWebAppsEnabled(browser_context)) {
-    return std::make_unique<IsolatedWebAppThrottle>(handle);
+    registry.AddThrottle(std::make_unique<IsolatedWebAppThrottle>(registry));
   }
-  return nullptr;
 }
 
 IsolatedWebAppThrottle::IsolatedWebAppThrottle(
-    NavigationHandle* navigation_handle)
-    : NavigationThrottle(navigation_handle) {}
+    NavigationThrottleRegistry& registry)
+    : NavigationThrottle(registry) {}
 
 IsolatedWebAppThrottle::~IsolatedWebAppThrottle() = default;
 
diff --git a/content/browser/renderer_host/isolated_web_app_throttle.h b/content/browser/renderer_host/isolated_web_app_throttle.h
index 7f58c01d..5362b554 100644
--- a/content/browser/renderer_host/isolated_web_app_throttle.h
+++ b/content/browser/renderer_host/isolated_web_app_throttle.h
@@ -19,10 +19,10 @@
   using NavigationThrottle::ThrottleAction;
   using NavigationThrottle::ThrottleCheckResult;
 
-  static std::unique_ptr<IsolatedWebAppThrottle> MaybeCreateThrottleFor(
-      NavigationHandle* handle);
+  static void MaybeCreateAndAdd(
+      NavigationThrottleRegistry& registry);
 
-  explicit IsolatedWebAppThrottle(NavigationHandle* navigation_handle);
+  explicit IsolatedWebAppThrottle(NavigationThrottleRegistry& registry);
   ~IsolatedWebAppThrottle() override;
   IsolatedWebAppThrottle() = delete;
   IsolatedWebAppThrottle(const IsolatedWebAppThrottle&) = delete;
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 61454ad..d1e8e97 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -309,6 +309,8 @@
       return "REQUEST_CANCELLED";
     case blink::mojom::MediaStreamRequestResult::START_TIMEOUT:
       return "START_TIMEOUT";
+    case blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED_BY_USER:
+      return "PERMISSION_DENIED_BY_USER";
     case blink::mojom::MediaStreamRequestResult::NUM_MEDIA_REQUEST_RESULTS:
       break;  // Not a valid enum value.
   }
diff --git a/content/browser/renderer_host/media/media_stream_metrics.cc b/content/browser/renderer_host/media/media_stream_metrics.cc
index 6792809..a8e1dd19 100644
--- a/content/browser/renderer_host/media/media_stream_metrics.cc
+++ b/content/browser/renderer_host/media/media_stream_metrics.cc
@@ -35,7 +35,8 @@
   kDeviceInUse = 16,
   kRequestCancelled = 17,
   kStartTimeout = 18,
-  kMaxValue = kStartTimeout
+  kPermissionDeniedByUser = 19,
+  kMaxValue = kPermissionDeniedByUser
 };
 
 MediaStreamRequestResult2 MapResultToResult2(
@@ -80,8 +81,10 @@
       return MediaStreamRequestResult2::kRequestCancelled;
     case MediaStreamRequestResult::START_TIMEOUT:
       return MediaStreamRequestResult2::kStartTimeout;
+    case MediaStreamRequestResult::PERMISSION_DENIED_BY_USER:
+      return MediaStreamRequestResult2::kPermissionDeniedByUser;
     case MediaStreamRequestResult::NUM_MEDIA_REQUEST_RESULTS:
-      break;
+      break;  // Not a valid enum value.
   }
   NOTREACHED();
 }
diff --git a/content/browser/renderer_host/mixed_content_navigation_throttle.cc b/content/browser/renderer_host/mixed_content_navigation_throttle.cc
index bc228001..9865263 100644
--- a/content/browser/renderer_host/mixed_content_navigation_throttle.cc
+++ b/content/browser/renderer_host/mixed_content_navigation_throttle.cc
@@ -20,15 +20,15 @@
 namespace content {
 
 // static
-std::unique_ptr<NavigationThrottle>
-MixedContentNavigationThrottle::CreateThrottleForNavigation(
-    NavigationHandle* navigation_handle) {
-  return std::make_unique<MixedContentNavigationThrottle>(navigation_handle);
+void MixedContentNavigationThrottle::CreateAndAdd(
+    NavigationThrottleRegistry& registry) {
+  registry.AddThrottle(
+      std::make_unique<MixedContentNavigationThrottle>(registry));
 }
 
 MixedContentNavigationThrottle::MixedContentNavigationThrottle(
-    NavigationHandle* navigation_handle)
-    : NavigationThrottle(navigation_handle) {}
+    NavigationThrottleRegistry& registry)
+    : NavigationThrottle(registry) {}
 
 MixedContentNavigationThrottle::~MixedContentNavigationThrottle() {}
 
diff --git a/content/browser/renderer_host/mixed_content_navigation_throttle.h b/content/browser/renderer_host/mixed_content_navigation_throttle.h
index 31fb6eaf..0e68345 100644
--- a/content/browser/renderer_host/mixed_content_navigation_throttle.h
+++ b/content/browser/renderer_host/mixed_content_navigation_throttle.h
@@ -5,8 +5,6 @@
 #ifndef CONTENT_BROWSER_RENDERER_HOST_MIXED_CONTENT_NAVIGATION_THROTTLE_H_
 #define CONTENT_BROWSER_RENDERER_HOST_MIXED_CONTENT_NAVIGATION_THROTTLE_H_
 
-#include <set>
-
 #include "base/gtest_prod_util.h"
 #include "content/browser/renderer_host/mixed_content_checker.h"
 #include "content/common/content_export.h"
@@ -29,10 +27,9 @@
 // https://w3c.github.io/webappsec-mixed-content/
 class MixedContentNavigationThrottle : public NavigationThrottle {
  public:
-  static std::unique_ptr<NavigationThrottle> CreateThrottleForNavigation(
-      NavigationHandle* navigation_handle);
+  static void CreateAndAdd(NavigationThrottleRegistry& registry);
 
-  MixedContentNavigationThrottle(NavigationHandle* navigation_handle);
+  explicit MixedContentNavigationThrottle(NavigationThrottleRegistry& registry);
 
   MixedContentNavigationThrottle(const MixedContentNavigationThrottle&) =
       delete;
diff --git a/content/browser/renderer_host/mojo_render_input_router_delegate_impl.cc b/content/browser/renderer_host/mojo_render_input_router_delegate_impl.cc
new file mode 100644
index 0000000..aefef51
--- /dev/null
+++ b/content/browser/renderer_host/mojo_render_input_router_delegate_impl.cc
@@ -0,0 +1,72 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/renderer_host/mojo_render_input_router_delegate_impl.h"
+
+#include "components/viz/host/host_frame_sink_manager.h"
+#include "content/browser/compositor/surface_utils.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+
+namespace content {
+
+MojoRenderInputRouterDelegateImpl::MojoRenderInputRouterDelegateImpl(
+    RenderWidgetHostImpl* host)
+    : host_(*host) {}
+
+MojoRenderInputRouterDelegateImpl::~MojoRenderInputRouterDelegateImpl() =
+    default;
+
+void MojoRenderInputRouterDelegateImpl::
+    SetupRenderInputRouterDelegateConnection() {
+  rir_delegate_client_receiver_.reset();
+  rir_delegate_remote_.reset();
+  GetHostFrameSinkManager()->SetupRenderInputRouterDelegateConnection(
+      host_->GetFrameSinkId(),
+      rir_delegate_client_receiver_.BindNewEndpointAndPassRemote(),
+      rir_delegate_remote_.BindNewEndpointAndPassReceiver());
+}
+
+input::mojom::RenderInputRouterDelegate*
+MojoRenderInputRouterDelegateImpl::GetRenderInputRouterDelegateRemote() {
+  if (!rir_delegate_remote_) {
+    return nullptr;
+  }
+  return rir_delegate_remote_.get();
+}
+
+void MojoRenderInputRouterDelegateImpl::NotifyObserversOfInputEvent(
+    std::unique_ptr<blink::WebCoalescedInputEvent> event,
+    bool dispatched_to_renderer) {
+  host_->NotifyObserversOfInputEvent(event->Event(), dispatched_to_renderer);
+}
+
+void MojoRenderInputRouterDelegateImpl::NotifyObserversOfInputEventAcks(
+    blink::mojom::InputEventResultSource ack_source,
+    blink::mojom::InputEventResultState ack_result,
+    std::unique_ptr<blink::WebCoalescedInputEvent> event) {
+  host_->NotifyObserversOfInputEventAcks(ack_source, ack_result,
+                                         event->Event());
+}
+
+void MojoRenderInputRouterDelegateImpl::OnInvalidInputEventSource() {
+  host_->OnInvalidInputEventSource();
+}
+
+void MojoRenderInputRouterDelegateImpl::StateOnOverscrollTransfer(
+    blink::mojom::DidOverscrollParamsPtr params) {
+  host_->DidOverscroll(std::move(params));
+}
+
+void MojoRenderInputRouterDelegateImpl::RendererInputResponsivenessChanged(
+    bool is_responsive,
+    std::optional<base::TimeTicks> ack_timeout_ts) {
+  if (is_responsive) {
+    host_->RendererIsResponsive();
+  } else {
+    CHECK(ack_timeout_ts.has_value());
+    host_->OnInputEventAckTimeout(*ack_timeout_ts);
+  }
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/mojo_render_input_router_delegate_impl.h b/content/browser/renderer_host/mojo_render_input_router_delegate_impl.h
new file mode 100644
index 0000000..ae5a492
--- /dev/null
+++ b/content/browser/renderer_host/mojo_render_input_router_delegate_impl.h
@@ -0,0 +1,81 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_MOJO_RENDER_INPUT_ROUTER_DELEGATE_IMPL_H_
+#define CONTENT_BROWSER_RENDERER_HOST_MOJO_RENDER_INPUT_ROUTER_DELEGATE_IMPL_H_
+
+#include <memory>
+
+#include "base/memory/scoped_refptr.h"
+#include "components/input/render_input_router.mojom.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
+#include "third_party/blink/public/common/input/web_coalesced_input_event.h"
+#include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h"
+
+namespace content {
+
+class RenderWidgetHostImpl;
+
+// This class is owned by RenderWidgetHostImpl and its lifetime is directly tied
+// to the RenderWidgetHostImpl instance that creates it. This class encapsulates
+// the mojo-specific communication logic for syncing input handling related
+// state, acting as an intermediary between the RenderWidgetHostImpl (on the
+// CrBrowserMain thread) and the InputManager (on the VizCompositorThread). See
+// mojo interfaces `RenderInputRouterDelegate` and
+// `RenderInputRouterDelegateClient` for relevant state syncing methods.
+class MojoRenderInputRouterDelegateImpl
+    : public input::mojom::RenderInputRouterDelegateClient {
+ public:
+  explicit MojoRenderInputRouterDelegateImpl(RenderWidgetHostImpl* host);
+
+  ~MojoRenderInputRouterDelegateImpl() override;
+
+  // Sets up RenderInputRouterDelegate mojo connections with InputManager on
+  // the VizCompositorThread for input handling with InputVizard.
+  void SetupRenderInputRouterDelegateConnection();
+
+  // Get remote for making calls to RenderInputRouterDelegate interface. Returns
+  // nullptr if the remote is not bound yet. The mojo connection is setup when
+  // layer tree frame sinks from renderer are being requested (see
+  // RenderWidgetHostImpl::CreateFrameSink). This connection is setup before
+  // input handling starts on VizCompositorThread for its corresponding
+  // `frame_sink_id`.
+  input::mojom::RenderInputRouterDelegate* GetRenderInputRouterDelegateRemote();
+
+  // input::mojom::RenderInputRouterDelegateClient overrides.
+  void NotifyObserversOfInputEvent(
+      std::unique_ptr<blink::WebCoalescedInputEvent> event,
+      bool dispatched_to_renderer) override;
+  void NotifyObserversOfInputEventAcks(
+      blink::mojom::InputEventResultSource ack_source,
+      blink::mojom::InputEventResultState ack_result,
+      std::unique_ptr<blink::WebCoalescedInputEvent> event) override;
+  void OnInvalidInputEventSource() override;
+  void StateOnOverscrollTransfer(
+      blink::mojom::DidOverscrollParamsPtr params) override;
+  void RendererInputResponsivenessChanged(
+      bool is_responsive,
+      std::optional<base::TimeTicks> ack_timeout_ts) override;
+
+  void SetRenderInputRouterDelegateRemoteForTesting(
+      mojo::PendingAssociatedRemote<input::mojom::RenderInputRouterDelegate>
+          remote) {
+    rir_delegate_remote_.Bind(std::move(remote));
+  }
+
+ private:
+  mojo::AssociatedReceiver<input::mojom::RenderInputRouterDelegateClient>
+      rir_delegate_client_receiver_{this};
+  mojo::AssociatedRemote<input::mojom::RenderInputRouterDelegate>
+      rir_delegate_remote_;
+
+  // It is safe to use `raw_ref` here since RenderWidgetHostImpl owns this class
+  // and is bound to outlive |this|.
+  raw_ref<RenderWidgetHostImpl> host_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_MOJO_RENDER_INPUT_ROUTER_DELEGATE_IMPL_H_
diff --git a/content/browser/renderer_host/navigation_throttle_runner.cc b/content/browser/renderer_host/navigation_throttle_runner.cc
index 58da2608..94ff95c 100644
--- a/content/browser/renderer_host/navigation_throttle_runner.cc
+++ b/content/browser/renderer_host/navigation_throttle_runner.cc
@@ -13,7 +13,6 @@
 #include "build/build_config.h"
 #include "content/browser/devtools/devtools_instrumentation.h"
 #include "content/browser/preloading/prefetch/contamination_delay_navigation_throttle.h"
-#include "content/browser/preloading/prefetch/prefetch_features.h"
 #include "content/browser/preloading/prerender/prerender_navigation_throttle.h"
 #include "content/browser/preloading/prerender/prerender_subframe_navigation_throttle.h"
 #include "content/browser/renderer_host/ancestor_throttle.h"
@@ -223,44 +222,34 @@
   // Check for renderer-inititated main frame navigations to blocked URL schemes
   // (data, filesystem). This is done early as it may block the main frame
   // navigation altogether.
-  MaybeAddThrottle(
-      BlockedSchemeNavigationThrottle::CreateThrottleForNavigation(request));
+  BlockedSchemeNavigationThrottle::MaybeCreateAndAdd(*this);
 
 #if !BUILDFLAG(IS_ANDROID)
   // Prevent cross-document navigations from document picture-in-picture
   // windows.
-  MaybeAddThrottle(
-      DocumentPictureInPictureNavigationThrottle::MaybeCreateThrottleFor(
-          request));
+  DocumentPictureInPictureNavigationThrottle::MaybeCreateAndAdd(*this);
 #endif  // !BUILDFLAG(IS_ANDROID)
 
-  MaybeAddThrottle(AncestorThrottle::MaybeCreateThrottleFor(request));
+  AncestorThrottle::CreateAndAdd(*this);
 
   // Check for mixed content. This is done after the AncestorThrottle and the
   // FormSubmissionThrottle so that when folks block mixed content with a CSP
   // policy, they don't get a warning. They'll still get a warning in the
   // console about CSP blocking the load.
-  AddThrottle(
-      MixedContentNavigationThrottle::CreateThrottleForNavigation(request));
+  MixedContentNavigationThrottle::CreateAndAdd(*this);
 
-  if (base::FeatureList::IsEnabled(
-          features::kPrefetchStateContaminationMitigation)) {
-    // Delay response processing for certain prefetch responses where it might
-    // otherwise reveal information about cross-site state.
-    AddThrottle(
-        std::make_unique<ContaminationDelayNavigationThrottle>(request));
-  }
+  // Delay response processing for certain prefetch responses where it might
+  // otherwise reveal information about cross-site state.
+  ContaminationDelayNavigationThrottle::MaybeCreateAndAdd(*this);
 
   // Block certain requests that are not permitted for prerendering.
-  MaybeAddThrottle(
-      PrerenderNavigationThrottle::MaybeCreateThrottleFor(request));
+  PrerenderNavigationThrottle::MaybeCreateAndAdd(*this);
 
   // Defer cross-origin subframe loading during prerendering state.
-  MaybeAddThrottle(
-      PrerenderSubframeNavigationThrottle::MaybeCreateThrottleFor(request));
+  PrerenderSubframeNavigationThrottle::MaybeCreateAndAdd(*this);
 
   // Prevent navigations to/from Isolated Web Apps.
-  MaybeAddThrottle(IsolatedWebAppThrottle::MaybeCreateThrottleFor(request));
+  IsolatedWebAppThrottle::MaybeCreateAndAdd(*this);
 
   devtools_instrumentation::CreateAndAddNavigationThrottles(*this);
 
@@ -333,8 +322,7 @@
       SubframeHistoryNavigationThrottle::MaybeCreateThrottleFor(request));
 
   // Defer cross-origin about:srcdoc subframe loading during prerendering state.
-  MaybeAddThrottle(
-      PrerenderSubframeNavigationThrottle::MaybeCreateThrottleFor(request));
+  PrerenderSubframeNavigationThrottle::MaybeCreateAndAdd(*this);
 
   // Defer subframe navigation in bfcached page.
   MaybeAddThrottle(
diff --git a/content/browser/renderer_host/render_widget_host_delegate.cc b/content/browser/renderer_host/render_widget_host_delegate.cc
index 0b57828..c75785d 100644
--- a/content/browser/renderer_host/render_widget_host_delegate.cc
+++ b/content/browser/renderer_host/render_widget_host_delegate.cc
@@ -187,11 +187,6 @@
   return true;
 }
 
-input::mojom::RenderInputRouterDelegate*
-RenderWidgetHostDelegate::GetRenderInputRouterDelegateRemote() {
-  return nullptr;
-}
-
 #if BUILDFLAG(IS_ANDROID)
 float RenderWidgetHostDelegate::GetCurrentTouchSequenceYOffset() {
   return 0.f;
diff --git a/content/browser/renderer_host/render_widget_host_delegate.h b/content/browser/renderer_host/render_widget_host_delegate.h
index a54a0de..09eadc0 100644
--- a/content/browser/renderer_host/render_widget_host_delegate.h
+++ b/content/browser/renderer_host/render_widget_host_delegate.h
@@ -374,10 +374,6 @@
   // Notifies when an input event is ignored.
   virtual void OnInputIgnored(const blink::WebInputEvent& event) {}
 
-  // Get remote for making calls to RenderInputRouterDelegate interface.
-  virtual input::mojom::RenderInputRouterDelegate*
-  GetRenderInputRouterDelegateRemote();
-
 #if BUILDFLAG(IS_ANDROID)
   // Get the y value by which the touch sequence is offsetted by. For e.g.
   // visible top controls will result in a non zero offset to be added to touch
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 52f7728..252edf0bb 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1503,7 +1503,7 @@
 
 void RenderWidgetHostImpl::NotifyVizOfPageVisibilityUpdates() {
   if (auto* delegate_remote =
-          delegate()->GetRenderInputRouterDelegateRemote()) {
+          mojo_rir_delegate_impl_.GetRenderInputRouterDelegateRemote()) {
     delegate_remote->NotifyVisibilityChanged(frame_sink_id_, is_hidden_);
   }
 }
@@ -1514,7 +1514,8 @@
   }
   // Notifies RenderInputRouters on both browser and VizCompositor to restart
   // their input event ack timers.
-  if (auto* remote = delegate()->GetRenderInputRouterDelegateRemote()) {
+  if (auto* remote =
+          mojo_rir_delegate_impl_.GetRenderInputRouterDelegateRemote()) {
     remote->RestartInputEventAckTimeoutIfNecessary(GetFrameSinkId());
   }
   GetRenderInputRouter()->RestartInputEventAckTimeoutIfNecessary();
@@ -3632,6 +3633,11 @@
       std::move(compositor_frame_sink_client), std::move(viz_rir_client_remote),
       GetRenderInputRouter()->GetForceEnableZoom());
 
+  if (input::InputUtils::IsTransferInputToVizSupported()) {
+    // Handles setting up GPU mojo endpoint connections for
+    // RenderInputRouterDelegate[Client] interfaces.
+    mojo_rir_delegate_impl_.SetupRenderInputRouterDelegateConnection();
+  }
   MaybeDispatchBufferedFrameSinkRequest();
 }
 
@@ -3739,6 +3745,10 @@
 }
 
 void RenderWidgetHostImpl::SetForceEnableZoom(bool enabled) {
+  if (auto* remote =
+          mojo_rir_delegate_impl_.GetRenderInputRouterDelegateRemote()) {
+    remote->ForceEnableZoomStateChanged(enabled, frame_sink_id_);
+  }
   GetRenderInputRouter()->SetForceEnableZoom(enabled);
 }
 
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 0bc94f22..f24d020 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -43,6 +43,7 @@
 #include "content/browser/renderer_host/agent_scheduling_group_host.h"
 #include "content/browser/renderer_host/frame_token_message_queue.h"
 #include "content/browser/renderer_host/input/touch_emulator_impl.h"
+#include "content/browser/renderer_host/mojo_render_input_router_delegate_impl.h"
 #include "content/browser/renderer_host/render_frame_metadata_provider_impl.h"
 #include "content/browser/renderer_host/render_widget_host_delegate.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
@@ -420,6 +421,9 @@
   void SetView(RenderWidgetHostViewBase* view);
 
   RenderWidgetHostDelegate* delegate() const { return delegate_; }
+  MojoRenderInputRouterDelegateImpl* mojo_rir_delegate() {
+    return &mojo_rir_delegate_impl_;
+  }
 
   // Bind the provided widget interfaces.
   void BindWidgetInterfaces(
@@ -1246,6 +1250,11 @@
   // True if |Destroy()| has been called.
   bool destroyed_ = false;
 
+  // Handles mojo connections for RenderInputRouterDelegate[Client] interface to
+  // allow sycing information between the Browser and the GPU process for input
+  // handling with InputVizard.
+  MojoRenderInputRouterDelegateImpl mojo_rir_delegate_impl_{this};
+
   // Our delegate, which wants to know mainly about keyboard events.
   // It will remain non-null until DetachDelegate() is called.
   raw_ptr<RenderWidgetHostDelegate, FlakyDanglingUntriaged> delegate_;
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index df4f06d9..a9642fcf 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -1378,7 +1378,8 @@
     bool browser_would_have_handled) {
   TRACE_EVENT("input", "RenderWidgetHostViewAndroid::StateOnTouchTransfer");
   CHECK(host());
-  auto* remote = host()->delegate()->GetRenderInputRouterDelegateRemote();
+  auto* remote =
+      host()->mojo_rir_delegate()->GetRenderInputRouterDelegateRemote();
   const float y_offset_pix =
       host()->delegate()->GetCurrentTouchSequenceYOffset();
   remote->StateOnTouchTransfer(input::mojom::TouchTransferState::New(
@@ -1564,8 +1565,9 @@
     } else if (event.GetAction() == ui::MotionEvent::Action::DOWN) {
       // Stop any ongoing fling on VizCompositorThread if the new input sequence
       // is going to be handled on the Browser.
-      if (auto* remote =
-              host()->delegate()->GetRenderInputRouterDelegateRemote()) {
+      if (auto* remote = host()
+                             ->mojo_rir_delegate()
+                             ->GetRenderInputRouterDelegateRemote()) {
         remote->StopFlingingOnViz(host()->GetFrameSinkId());
       }
     }
@@ -1621,7 +1623,8 @@
     if (!host()) {
       return;
     }
-    auto* remote = host()->delegate()->GetRenderInputRouterDelegateRemote();
+    auto* remote =
+        host()->mojo_rir_delegate()->GetRenderInputRouterDelegateRemote();
     remote->ResetGestureDetection(GetFrameSinkId());
     return;
   }
diff --git a/content/browser/renderer_host/render_widget_host_view_android_unittest.cc b/content/browser/renderer_host/render_widget_host_view_android_unittest.cc
index e167adc..0b52cdb8b 100644
--- a/content/browser/renderer_host/render_widget_host_view_android_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android_unittest.cc
@@ -117,9 +117,9 @@
   MockMojoRenderInputRouterDelegate() = default;
   ~MockMojoRenderInputRouterDelegate() override = default;
 
-  mojo::PendingRemote<input::mojom::RenderInputRouterDelegate>
+  mojo::PendingAssociatedRemote<input::mojom::RenderInputRouterDelegate>
   GetPendingRemote() {
-    return receiver_.BindNewPipeAndPassRemote();
+    return receiver_.BindNewEndpointAndPassDedicatedRemote();
   }
 
   MOCK_METHOD1(StateOnTouchTransfer,
@@ -129,7 +129,7 @@
                     const viz::FrameSinkId& frame_sink_id));
   MOCK_METHOD2(ForceEnableZoomStateChanged,
                void(bool force_enable_zoom,
-                    const std::vector<viz::FrameSinkId>& frame_sink_ids));
+                    const viz::FrameSinkId& frame_sink_id));
   MOCK_METHOD1(StopFlingingOnViz, void(const viz::FrameSinkId& frame_sink_id));
   MOCK_METHOD1(RestartInputEventAckTimeoutIfNecessary,
                void(const viz::FrameSinkId& frame_sink_id));
@@ -139,7 +139,8 @@
                void(const viz::FrameSinkId& frame_sink_id));
 
  private:
-  mojo::Receiver<input::mojom::RenderInputRouterDelegate> receiver_{this};
+  mojo::AssociatedReceiver<input::mojom::RenderInputRouterDelegate> receiver_{
+      this};
 };
 
 class RenderWidgetHostViewAndroidTest : public RenderViewHostImplTestHarness {
@@ -529,8 +530,10 @@
   rwhva->SetInputTransferHandlerForTesting(handler);
 
   MockMojoRenderInputRouterDelegate rir_delegate;
-  delegate()->set_render_input_router_delegate_remote(
-      rir_delegate.GetPendingRemote());
+  rwhva->host()
+      ->mojo_rir_delegate()
+      ->SetRenderInputRouterDelegateRemoteForTesting(
+          rir_delegate.GetPendingRemote());
 
   EXPECT_CALL(*handler, IsTouchSequencePotentiallyActiveOnViz())
       .WillOnce(Return(true));
@@ -550,8 +553,10 @@
   rwhva->SetInputTransferHandlerForTesting(handler);
 
   MockMojoRenderInputRouterDelegate rir_delegate;
-  delegate()->set_render_input_router_delegate_remote(
-      rir_delegate.GetPendingRemote());
+  rwhva->host()
+      ->mojo_rir_delegate()
+      ->SetRenderInputRouterDelegateRemoteForTesting(
+          rir_delegate.GetPendingRemote());
 
   gfx::Point point(/*x=*/100, /*y=*/100);
   ui::MotionEventAndroid::Pointer p(0, point.x(), point.y(), 10, 0, 0, 0, 0, 0);
diff --git a/content/browser/shared_storage/shared_storage_browsertest.cc b/content/browser/shared_storage/shared_storage_browsertest.cc
index 7827687..50a7a4b8 100644
--- a/content/browser/shared_storage/shared_storage_browsertest.cc
+++ b/content/browser/shared_storage/shared_storage_browsertest.cc
@@ -727,8 +727,7 @@
 
   ExpectOperationFinishedInfosObserved(
       {{base::TimeDelta(), AccessMethod::kRun, /*operation_id=*/0,
-        /*worklet_ordinal_id=*/0, GetFirstWorkletHostDevToolsToken(),
-        MainFrameId(), origin_str}});
+        GetFirstWorkletHostDevToolsToken(), MainFrameId(), origin_str}});
 }
 
 IN_PROC_BROWSER_TEST_P(SharedStorageBrowserTest,
@@ -1024,8 +1023,7 @@
 
   ExpectOperationFinishedInfosObserved(
       {{base::TimeDelta(), AccessMethod::kRun, /*operation_id=*/0,
-        /*worklet_ordinal_id=*/0, GetFirstWorkletHostDevToolsToken(),
-        MainFrameId(), origin_str}});
+        GetFirstWorkletHostDevToolsToken(), MainFrameId(), origin_str}});
 }
 
 IN_PROC_BROWSER_TEST_P(
@@ -1122,11 +1120,9 @@
 
   ExpectOperationFinishedInfosObserved(
       {{base::TimeDelta(), AccessMethod::kRun, /*operation_id=*/0,
-        /*worklet_ordinal_id=*/0, GetFirstWorkletHostDevToolsToken(),
-        MainFrameId(), origin_str},
+        GetFirstWorkletHostDevToolsToken(), MainFrameId(), origin_str},
        {base::TimeDelta(), AccessMethod::kRun, /*operation_id=*/1,
-        /*worklet_ordinal_id=*/0, GetFirstWorkletHostDevToolsToken(),
-        MainFrameId(), origin_str}});
+        GetFirstWorkletHostDevToolsToken(), MainFrameId(), origin_str}});
 }
 
 IN_PROC_BROWSER_TEST_P(
@@ -1608,7 +1604,7 @@
 
   ExpectOperationFinishedInfosObserved(
       {{base::TimeDelta(), AccessMethod::kRun, /*operation_id=*/0,
-        /*worklet_ordinal_id=*/0, GetFirstWorkletHostDevToolsToken(),
+        GetFirstWorkletHostDevToolsToken(),
         /*main_frame_id=*/GlobalRenderFrameHostId(), origin_str}});
 }
 
@@ -1750,7 +1746,7 @@
 
   ExpectOperationFinishedInfosObserved(
       {{base::TimeDelta(), AccessMethod::kSelectURL, /*operation_id=*/0,
-        /*worklet_ordinal_id=*/0, GetFirstWorkletHostDevToolsToken(),
+        GetFirstWorkletHostDevToolsToken(),
         /*main_frame_id=*/GlobalRenderFrameHostId(), origin_str}});
 }
 
@@ -9800,11 +9796,9 @@
 
   ExpectOperationFinishedInfosObserved(
       {{base::TimeDelta(), AccessMethod::kRun, /*operation_id=*/0,
-        /*worklet_ordinal_id=*/0, cached_worklet_devtools_tokens[0],
-        MainFrameId(), origin_str},
+        cached_worklet_devtools_tokens[0], MainFrameId(), origin_str},
        {base::TimeDelta(), AccessMethod::kRun, /*operation_id=*/0,
-        /*worklet_ordinal_id=*/1, cached_worklet_devtools_tokens[1],
-        MainFrameId(), origin_str}});
+        cached_worklet_devtools_tokens[1], MainFrameId(), origin_str}});
 }
 
 IN_PROC_BROWSER_TEST_P(
diff --git a/content/browser/shared_storage/shared_storage_fenced_frame_browsertest.cc b/content/browser/shared_storage/shared_storage_fenced_frame_browsertest.cc
index 4eaabb1..03d48b0b0 100644
--- a/content/browser/shared_storage/shared_storage_fenced_frame_browsertest.cc
+++ b/content/browser/shared_storage/shared_storage_fenced_frame_browsertest.cc
@@ -3096,8 +3096,7 @@
              GetFirstWorkletHostDevToolsToken())});
     expected_finished_infos.push_back(
         {base::TimeDelta(), AccessMethod::kSelectURL, /*operation_id=*/call,
-         /*worklet_ordinal_id=*/0, GetFirstWorkletHostDevToolsToken(),
-         MainFrameId(), origin_str});
+         GetFirstWorkletHostDevToolsToken(), MainFrameId(), origin_str});
   }
   expected_accesses.push_back(
       {AccessScope::kWindow, AccessMethod::kSelectURL, MainFrameId(),
@@ -3112,8 +3111,7 @@
            /*worklet_ordinal_id=*/0, GetFirstWorkletHostDevToolsToken())});
   expected_finished_infos.push_back(
       {base::TimeDelta(), AccessMethod::kSelectURL, /*operation_id=*/call_limit,
-       /*worklet_ordinal_id=*/0, GetFirstWorkletHostDevToolsToken(),
-       MainFrameId(), origin_str});
+       GetFirstWorkletHostDevToolsToken(), MainFrameId(), origin_str});
   for (int call = 0; call < call_limit; call++) {
     expected_accesses.push_back(
         {AccessScope::kWindow, AccessMethod::kSelectURL, MainFrameId(),
@@ -3131,7 +3129,7 @@
              /*worklet_ordinal_id=*/0, GetFirstWorkletHostDevToolsToken())});
     expected_finished_infos.push_back(
         {base::TimeDelta(), AccessMethod::kSelectURL,
-         /*operation_id=*/call_limit + 1 + call, /*worklet_ordinal_id=*/0,
+         /*operation_id=*/call_limit + 1 + call,
          GetFirstWorkletHostDevToolsToken(), MainFrameId(), origin_str});
   }
 
@@ -3263,8 +3261,7 @@
              cached_worklet_devtools_tokens[call])});
     expected_finished_infos.push_back(
         {base::TimeDelta(), AccessMethod::kSelectURL, /*operation_id=*/0,
-         /*worklet_ordinal_id=*/call, cached_worklet_devtools_tokens[call],
-         MainFrameId(), origin_str});
+         cached_worklet_devtools_tokens[call], MainFrameId(), origin_str});
   }
   origin_str = https_server()->GetOrigin("b.test").Serialize();
   expected_accesses.push_back(
@@ -3289,7 +3286,6 @@
            cached_worklet_devtools_tokens[call_limit])});
   expected_finished_infos.push_back(
       {base::TimeDelta(), AccessMethod::kSelectURL, /*operation_id=*/0,
-       /*worklet_ordinal_id=*/call_limit,
        cached_worklet_devtools_tokens[call_limit], MainFrameId(), origin_str});
   for (int call = 0; call < call_limit; call++) {
     host = base::StrCat({"subdomain", base::NumberToString(call), ".b.test"});
@@ -3318,7 +3314,6 @@
              cached_worklet_devtools_tokens[call_limit + 1 + call])});
     expected_finished_infos.push_back(
         {base::TimeDelta(), AccessMethod::kSelectURL, /*operation_id=*/0,
-         /*worklet_ordinal_id=*/call_limit + 1 + call,
          cached_worklet_devtools_tokens[call_limit + 1 + call], MainFrameId(),
          origin_str});
   }
diff --git a/content/browser/shared_storage/shared_storage_runtime_manager.cc b/content/browser/shared_storage/shared_storage_runtime_manager.cc
index 8149a7d..213f1db 100644
--- a/content/browser/shared_storage/shared_storage_runtime_manager.cc
+++ b/content/browser/shared_storage/shared_storage_runtime_manager.cc
@@ -153,7 +153,6 @@
     base::TimeDelta execution_time,
     SharedStorageObserverInterface::AccessMethod method,
     int operation_id,
-    int worklet_ordinal_id,
     const base::UnguessableToken& worklet_devtools_token,
     GlobalRenderFrameHostId main_frame_id,
     const std::string& owner_origin) {
@@ -171,8 +170,8 @@
     // however, that there may be a discrepancy between `execution_time` and
     // `finished_time - start-time`.
     observer.OnSharedStorageWorkletOperationExecutionFinished(
-        now, execution_time, method, operation_id, worklet_ordinal_id,
-        worklet_devtools_token, main_frame_id, owner_origin);
+        now, execution_time, method, operation_id, worklet_devtools_token,
+        main_frame_id, owner_origin);
   }
 }
 
diff --git a/content/browser/shared_storage/shared_storage_runtime_manager.h b/content/browser/shared_storage/shared_storage_runtime_manager.h
index 7476747..3c789a7 100644
--- a/content/browser/shared_storage/shared_storage_runtime_manager.h
+++ b/content/browser/shared_storage/shared_storage_runtime_manager.h
@@ -78,13 +78,11 @@
     virtual void OnSharedStorageSelectUrlConfigPopulated(
         const std::optional<FencedFrameConfig>& config) = 0;
 
-    // TODO(crbug.com/401011862): Remove `worklet_ordinal_id` parameter.
     virtual void OnSharedStorageWorkletOperationExecutionFinished(
         base::Time finished_time,
         base::TimeDelta execution_time,
         AccessMethod method,
         int operation_id,
-        int worklet_ordinal_id,
         const base::UnguessableToken& worklet_devtools_token,
         GlobalRenderFrameHostId main_frame_id,
         const std::string& owner_origin) = 0;
@@ -123,12 +121,10 @@
       const std::string& owner_origin,
       const SharedStorageEventParams& params);
 
-  // TODO(crbug.com/401011862): Remove `worklet_ordinal_id` parameter.
   void NotifyWorkletOperationExecutionFinished(
       base::TimeDelta execution_time,
       SharedStorageObserverInterface::AccessMethod method,
       int operation_id,
-      int worklet_ordinal_id,
       const base::UnguessableToken& worklet_devtools_token,
       GlobalRenderFrameHostId main_frame_id,
       const std::string& owner_origin);
@@ -190,10 +186,9 @@
 
   base::ObserverList<SharedStorageObserverInterface> observers_;
 
-  // A monotonically increasing ID assigned to each SharedStorageWorkletHost.
-  // This ID is assigned during construction of the SharedStorageWorkletHost.
-  // TODO(crbug.com/401011862): Use the worklet IDs generated in DevTools
-  // reporting.
+  // A monotonically increasing number assigned to each
+  // SharedStorageWorkletHost. This ordinal is assigned during construction of
+  // the SharedStorageWorkletHost.
   int next_worklet_ordinal_id_ = 0;
 };
 
diff --git a/content/browser/shared_storage/shared_storage_worklet_host.cc b/content/browser/shared_storage/shared_storage_worklet_host.cc
index 1ac4689..b90bca104 100644
--- a/content/browser/shared_storage/shared_storage_worklet_host.cc
+++ b/content/browser/shared_storage/shared_storage_worklet_host.cc
@@ -1423,8 +1423,8 @@
 
   shared_storage_runtime_manager_->NotifyWorkletOperationExecutionFinished(
       base::TimeTicks::Now() - run_start_time, AccessMethod::kRun, operation_id,
-      worklet_ordinal_id_, GetWorkletDevToolsToken(),
-      GetMainFrameIdIfAvailable(), shared_storage_origin_.Serialize());
+      GetWorkletDevToolsToken(), GetMainFrameIdIfAvailable(),
+      shared_storage_origin_.Serialize());
 
   base::UmaHistogramLongTimes(
       "Storage.SharedStorage.Document.Timing.Run.ExecutedInWorklet",
@@ -1557,8 +1557,8 @@
 
   shared_storage_runtime_manager_->NotifyWorkletOperationExecutionFinished(
       base::TimeTicks::Now() - select_url_start_time, AccessMethod::kSelectURL,
-      operation_id, worklet_ordinal_id_, GetWorkletDevToolsToken(),
-      GetMainFrameIdIfAvailable(), shared_storage_origin_.Serialize());
+      operation_id, GetWorkletDevToolsToken(), GetMainFrameIdIfAvailable(),
+      shared_storage_origin_.Serialize());
 
   base::UmaHistogramLongTimes(
       "Storage.SharedStorage.Document.Timing.SelectURL.ExecutedInWorklet",
diff --git a/content/browser/shared_storage/test_shared_storage_observer.cc b/content/browser/shared_storage/test_shared_storage_observer.cc
index 81fe832..da8a9ee 100644
--- a/content/browser/shared_storage/test_shared_storage_observer.cc
+++ b/content/browser/shared_storage/test_shared_storage_observer.cc
@@ -98,14 +98,12 @@
     base::TimeDelta execution_time,
     AccessMethod method,
     int operation_id,
-    int worklet_ordinal_id,
     const base::UnguessableToken& worklet_devtools_token,
     GlobalRenderFrameHostId main_frame_id,
     std::string owner_origin)
     : execution_time(execution_time),
       method(method),
       operation_id(operation_id),
-      worklet_ordinal_id(worklet_ordinal_id),
       worklet_devtools_token(worklet_devtools_token),
       main_frame_id(std::move(main_frame_id)),
       owner_origin(std::move(owner_origin)) {}
@@ -161,13 +159,12 @@
         base::TimeDelta execution_time,
         AccessMethod method,
         int operation_id,
-        int worklet_ordinal_id,
         const base::UnguessableToken& worklet_devtools_token,
         GlobalRenderFrameHostId main_frame_id,
         const std::string& owner_origin) {
-  operation_finished_infos_.emplace_back(
-      execution_time, method, operation_id, worklet_ordinal_id,
-      worklet_devtools_token, main_frame_id, owner_origin);
+  operation_finished_infos_.emplace_back(execution_time, method, operation_id,
+                                         worklet_devtools_token, main_frame_id,
+                                         owner_origin);
 }
 
 void TestSharedStorageObserver::ExpectAccessObserved(
@@ -198,7 +195,6 @@
                 const TestSharedStorageObserver::OperationFinishedInfo& rhs) {
   // Do not compare `execution_time` when checking for equality in tests.
   return lhs.method == rhs.method && lhs.operation_id == rhs.operation_id &&
-         lhs.worklet_ordinal_id == rhs.worklet_ordinal_id &&
          lhs.worklet_devtools_token == rhs.worklet_devtools_token &&
          lhs.main_frame_id == rhs.main_frame_id &&
          lhs.owner_origin == rhs.owner_origin;
@@ -210,7 +206,6 @@
   os << "{ Execution Time: " << info.execution_time.InMicroseconds()
      << "; Access Method: " << SerializeMethod(info.method)
      << "; Operation ID: " << info.operation_id
-     << "; Worklet Ordinal ID: " << info.worklet_ordinal_id
      << "; Worklet Devtools Token: " << info.worklet_devtools_token
      << "; Main Frame ID: " << info.main_frame_id
      << "; Owner Origin: " << info.owner_origin << " }";
diff --git a/content/browser/shared_storage/test_shared_storage_observer.h b/content/browser/shared_storage/test_shared_storage_observer.h
index 2bfe6d0..ed5cb83 100644
--- a/content/browser/shared_storage/test_shared_storage_observer.h
+++ b/content/browser/shared_storage/test_shared_storage_observer.h
@@ -38,7 +38,6 @@
     base::TimeDelta execution_time;
     AccessMethod method;
     int operation_id;
-    int worklet_ordinal_id;
     base::UnguessableToken worklet_devtools_token;
     GlobalRenderFrameHostId main_frame_id;
     std::string owner_origin;
@@ -46,7 +45,6 @@
     OperationFinishedInfo(base::TimeDelta execution_time,
                           AccessMethod method,
                           int operation_id,
-                          int worklet_ordinal_id,
                           const base::UnguessableToken& worklet_devtools_token,
                           GlobalRenderFrameHostId main_frame_id,
                           std::string owner_origin);
@@ -81,7 +79,6 @@
       base::TimeDelta execution_time,
       AccessMethod method,
       int operation_id,
-      int worklet_ordinal_id,
       const base::UnguessableToken& worklet_devtools_token,
       GlobalRenderFrameHostId main_frame_id,
       const std::string& owner_origin) override;
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index e5795154..f3204a3 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1434,10 +1434,6 @@
     SharedStorageBudgetCharger::CreateForWebContents(this);
   }
 
-  if (input::InputUtils::IsTransferInputToVizSupported()) {
-    SetupRenderInputRouterDelegateConnection();
-  }
-
   if (base::FeatureList::IsEnabled(
           fingerprinting_protection_interventions::features::kCanvasNoise)) {
     renderer_preferences_.canvas_noise_token =
@@ -1445,22 +1441,6 @@
   }
 }
 
-void WebContentsImpl::SetupRenderInputRouterDelegateConnection() {
-  // Handles setting up GPU mojo endpoint connections. In general, the number of
-  // retries for setting up these mojo connections is capped by the maximum
-  // number of attempts to restart the GPU process, see
-  // GpuProcessHost::GetFallbackCrashLimit().
-  rir_delegate_client_receiver_.reset();
-  rir_delegate_remote_.reset();
-  GetHostFrameSinkManager()->SetupRenderInputRouterDelegateConnection(
-      compositor_frame_sink_grouping_id_,
-      rir_delegate_client_receiver_.BindNewPipeAndPassRemote(),
-      rir_delegate_remote_.BindNewPipeAndPassReceiver());
-  rir_delegate_client_receiver_.set_disconnect_handler(
-      base::BindOnce(&WebContentsImpl::SetupRenderInputRouterDelegateConnection,
-                     weak_factory_.GetWeakPtr()));
-}
-
 WebContentsImpl::~WebContentsImpl() {
   TRACE_EVENT0("content", "WebContentsImpl::~WebContentsImpl");
   WebContentsOfBrowserContext::Detach(*this);
@@ -3847,10 +3827,6 @@
         }
       }
     }
-    // Notify VizCompositor thread of force_enable_zoom state changes.
-    if (auto* remote = GetRenderInputRouterDelegateRemote()) {
-      remote->ForceEnableZoomStateChanged(force_enable_zoom_, frame_sink_ids);
-    }
   }
 #endif
 
@@ -7537,82 +7513,6 @@
   return touch_emulator_.get();
 }
 
-void WebContentsImpl::NotifyObserversOfInputEvent(
-    const viz::FrameSinkId& frame_sink_id,
-    std::unique_ptr<blink::WebCoalescedInputEvent> event,
-    bool dispatched_to_renderer) {
-  auto iter = created_widgets_.find(frame_sink_id);
-  // This adds a safeguard against race condition where a RenderWidgetHostImpl
-  // is being destroyed & removed from |created_widgets_|, but Viz may still
-  // send a mojo call referencing it.
-  if (iter == created_widgets_.end()) {
-    return;
-  }
-  iter->second->NotifyObserversOfInputEvent(event->Event(),
-                                            dispatched_to_renderer);
-}
-
-void WebContentsImpl::NotifyObserversOfInputEventAcks(
-    const viz::FrameSinkId& frame_sink_id,
-    blink::mojom::InputEventResultSource ack_source,
-    blink::mojom::InputEventResultState ack_result,
-    std::unique_ptr<blink::WebCoalescedInputEvent> event) {
-  auto iter = created_widgets_.find(frame_sink_id);
-  // This adds a safeguard against race condition where a RenderWidgetHostImpl
-  // is being destroyed & removed from |created_widgets_|, but Viz may still
-  // send a mojo call referencing it.
-  if (iter == created_widgets_.end()) {
-    return;
-  }
-  iter->second->NotifyObserversOfInputEventAcks(ack_source, ack_result,
-                                                event->Event());
-}
-
-void WebContentsImpl::OnInvalidInputEventSource(
-    const viz::FrameSinkId& frame_sink_id) {
-  auto iter = created_widgets_.find(frame_sink_id);
-  // This adds a safeguard against race condition where a RenderWidgetHostImpl
-  // is being destroyed & removed from |created_widgets_|, but Viz may still
-  // send a mojo call referencing it.
-  if (iter == created_widgets_.end()) {
-    return;
-  }
-  iter->second->OnInvalidInputEventSource();
-}
-
-void WebContentsImpl::StateOnOverscrollTransfer(
-    const viz::FrameSinkId& frame_sink_id,
-    blink::mojom::DidOverscrollParamsPtr params) {
-  auto iter = created_widgets_.find(frame_sink_id);
-  // This adds a safeguard against race condition where a RenderWidgetHostImpl
-  // is being destroyed & removed from |created_widgets_|, but Viz may still
-  // send a mojo call referencing it.
-  if (iter == created_widgets_.end()) {
-    return;
-  }
-  iter->second->DidOverscroll(std::move(params));
-}
-
-void WebContentsImpl::RendererInputResponsivenessChanged(
-    const viz::FrameSinkId& frame_sink_id,
-    bool is_responsive,
-    std::optional<base::TimeTicks> ack_timeout_ts) {
-  auto iter = created_widgets_.find(frame_sink_id);
-  // This adds a safeguard against race condition where a RenderWidgetHostImpl
-  // is being destroyed & removed from |created_widgets_|, but Viz may still
-  // send a mojo call referencing it.
-  if (iter == created_widgets_.end()) {
-    return;
-  }
-
-  if (is_responsive) {
-    iter->second->RendererIsResponsive();
-  } else {
-    CHECK(ack_timeout_ts.has_value());
-    iter->second->OnInputEventAckTimeout(*ack_timeout_ts);
-  }
-}
-
 void WebContentsImpl::DidNavigateMainFramePreCommit(
     NavigationHandle* navigation_handle,
     bool navigation_is_within_page) {
@@ -12068,14 +11968,6 @@
 #endif
 }
 
-input::mojom::RenderInputRouterDelegate*
-WebContentsImpl::GetRenderInputRouterDelegateRemote() {
-  if (!rir_delegate_remote_) {
-    return nullptr;
-  }
-  return rir_delegate_remote_.get();
-}
-
 #if BUILDFLAG(IS_ANDROID)
 float WebContentsImpl::GetCurrentTouchSequenceYOffset() {
   ui::ViewAndroid* view_android = GetNativeView();
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 478c9df..183643a2 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -31,7 +31,6 @@
 #include "base/types/pass_key.h"
 #include "build/build_config.h"
 #include "components/download/public/common/download_url_parameters.h"
-#include "components/input/render_input_router.mojom.h"
 #include "components/input/render_widget_host_input_event_router.h"
 #include "content/browser/media/audio_stream_monitor.h"
 #include "content/browser/media/forwarding_audio_stream_factory.h"
@@ -215,8 +214,7 @@
       public ui::NativeThemeObserver,
       public ui::ColorProviderSourceObserver,
       public SlowWebPreferenceCacheObserver,
-      public input::RenderWidgetHostInputEventRouter::Delegate,
-      public input::mojom::RenderInputRouterDelegateClient {
+      public input::RenderWidgetHostInputEventRouter::Delegate {
  public:
   class FriendWrapper;
 
@@ -1202,8 +1200,6 @@
   gfx::mojom::DelegatedInkPointRenderer* GetDelegatedInkRenderer(
       ui::Compositor* compositor) override;
   void OnInputIgnored(const blink::WebInputEvent& event) override;
-  input::mojom::RenderInputRouterDelegate* GetRenderInputRouterDelegateRemote()
-      override;
 #if BUILDFLAG(IS_ANDROID)
   float GetCurrentTouchSequenceYOffset() override;
 #endif
@@ -1289,26 +1285,6 @@
   //  RenderWidgetHostInputEventRouter::Delegate -------------------------------
   input::TouchEmulator* GetTouchEmulator(bool create_if_necessary) override;
 
-  // input::mojom::RenderInputRouterDelegateClient -----------------------------
-  void NotifyObserversOfInputEvent(
-      const viz::FrameSinkId& frame_sink_id,
-      std::unique_ptr<blink::WebCoalescedInputEvent> event,
-      bool dispatched_to_renderer) override;
-  void NotifyObserversOfInputEventAcks(
-      const viz::FrameSinkId& frame_sink_id,
-      blink::mojom::InputEventResultSource ack_source,
-      blink::mojom::InputEventResultState ack_result,
-      std::unique_ptr<blink::WebCoalescedInputEvent> event) override;
-  void OnInvalidInputEventSource(
-      const viz::FrameSinkId& frame_sink_id) override;
-  void StateOnOverscrollTransfer(
-      const viz::FrameSinkId& frame_sink_id,
-      blink::mojom::DidOverscrollParamsPtr params) override;
-  void RendererInputResponsivenessChanged(
-      const viz::FrameSinkId& frame_sink_id,
-      bool is_responsive,
-      std::optional<base::TimeTicks> ack_timeout_ts) override;
-
   // Invoked before a form repost warning is shown.
   void NotifyBeforeFormRepostWarningShow() override;
 
@@ -2233,10 +2209,6 @@
   // JavascriptDialogManager.
   void CancelDialogManagerDialogs(bool reset_state);
 
-  // Sets up RenderInputRouterDelegate mojo connections with InputManager on
-  // the VizCompositorThread for input handling with InputVizard.
-  void SetupRenderInputRouterDelegateConnection();
-
   // See GetPartitionedPopinEmbedderOrigin for details.
   GURL GetPartitionedPopinEmbedderOriginImpl() const;
 
@@ -2753,11 +2725,6 @@
   // input event routing with InputVizard.
   const base::UnguessableToken compositor_frame_sink_grouping_id_;
 
-  mojo::Receiver<input::mojom::RenderInputRouterDelegateClient>
-      rir_delegate_client_receiver_{this};
-
-  mojo::Remote<input::mojom::RenderInputRouterDelegate> rir_delegate_remote_;
-
   // Indicates if the instance is hosted in a preview window.
   // This will be set in Init() and will be reset in WillActivatePreviewPage().
   bool is_in_preview_mode_ = false;
diff --git a/content/test/mock_render_widget_host_delegate.cc b/content/test/mock_render_widget_host_delegate.cc
index f482796b..137299b 100644
--- a/content/test/mock_render_widget_host_delegate.cc
+++ b/content/test/mock_render_widget_host_delegate.cc
@@ -105,14 +105,6 @@
 void MockRenderWidgetHostDelegate::OnInputIgnored(
     const blink::WebInputEvent& event) {}
 
-input::mojom::RenderInputRouterDelegate*
-MockRenderWidgetHostDelegate::GetRenderInputRouterDelegateRemote() {
-  if (!rir_delegate_remote_.is_bound()) {
-    return nullptr;
-  }
-  return rir_delegate_remote_.get();
-}
-
 input::TouchEmulator* MockRenderWidgetHostDelegate::GetTouchEmulator(
     bool create_if_necessary) {
   NOTIMPLEMENTED();
diff --git a/content/test/mock_render_widget_host_delegate.h b/content/test/mock_render_widget_host_delegate.h
index 5817de9..c04ca2f 100644
--- a/content/test/mock_render_widget_host_delegate.h
+++ b/content/test/mock_render_widget_host_delegate.h
@@ -44,10 +44,6 @@
       KeyboardEventProcessingResult result) {
     pre_handle_keyboard_event_result_ = result;
   }
-  void set_render_input_router_delegate_remote(
-      mojo::PendingRemote<input::mojom::RenderInputRouterDelegate> remote) {
-    rir_delegate_remote_.Bind(std::move(remote));
-  }
 
   void CreateInputEventRouter();
 
@@ -78,8 +74,6 @@
   gfx::mojom::DelegatedInkPointRenderer* GetDelegatedInkRenderer(
       ui::Compositor* compositor) override;
   void OnInputIgnored(const blink::WebInputEvent& event) override;
-  input::mojom::RenderInputRouterDelegate* GetRenderInputRouterDelegateRemote()
-      override;
 
   //  RenderWidgetHostInputEventRouter::Delegate
   input::TouchEmulator* GetTouchEmulator(bool create_if_necessary) override;
@@ -96,7 +90,6 @@
   raw_ptr<RenderWidgetHostImpl, DanglingUntriaged> focused_widget_ = nullptr;
   KeyboardEventProcessingResult pre_handle_keyboard_event_result_ =
       KeyboardEventProcessingResult::NOT_HANDLED;
-  mojo::Remote<input::mojom::RenderInputRouterDelegate> rir_delegate_remote_;
   StubRenderViewHostDelegateView rvh_delegate_view_;
   VisibleTimeRequestTrigger visible_time_request_trigger_;
 };
diff --git a/content/test/test_select_url_fenced_frame_config_observer_impl.cc b/content/test/test_select_url_fenced_frame_config_observer_impl.cc
index db9fd41..a932736 100644
--- a/content/test/test_select_url_fenced_frame_config_observer_impl.cc
+++ b/content/test/test_select_url_fenced_frame_config_observer_impl.cc
@@ -64,7 +64,6 @@
         base::TimeDelta execution_time,
         AccessMethod method,
         int operation_id,
-        int worklet_ordinal_id,
         const base::UnguessableToken& worklet_devtools_token,
         GlobalRenderFrameHostId main_frame_id,
         const std::string& owner_origin) {}
diff --git a/content/test/test_select_url_fenced_frame_config_observer_impl.h b/content/test/test_select_url_fenced_frame_config_observer_impl.h
index 5a15c1b4..f31338d 100644
--- a/content/test/test_select_url_fenced_frame_config_observer_impl.h
+++ b/content/test/test_select_url_fenced_frame_config_observer_impl.h
@@ -38,7 +38,6 @@
       base::TimeDelta execution_time,
       AccessMethod method,
       int operation_id,
-      int worklet_ordinal_id,
       const base::UnguessableToken& worklet_devtools_token,
       GlobalRenderFrameHostId main_frame_id,
       const std::string& owner_origin) override;
diff --git a/docs/updater/functional_spec.md b/docs/updater/functional_spec.md
index 101a956..c041448 100644
--- a/docs/updater/functional_spec.md
+++ b/docs/updater/functional_spec.md
@@ -1004,6 +1004,9 @@
   be disabled by policy.
 * If the update check period is set to zero, the updater is qualified without
   an update check.
+* Major/Minor version rollout policy values are sent to the update server to
+  indicate a preference for taking updates early or late in any gradual rollout
+  process.
 
 Refer to chrome/updater/protos/omaha\_settings.proto for more details.
 
diff --git a/gpu/command_buffer/service/memory_program_cache_unittest.cc b/gpu/command_buffer/service/memory_program_cache_unittest.cc
index 6179e92..ab43645 100644
--- a/gpu/command_buffer/service/memory_program_cache_unittest.cc
+++ b/gpu/command_buffer/service/memory_program_cache_unittest.cc
@@ -2,21 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "gpu/command_buffer/service/memory_program_cache.h"
 
 #include <stddef.h>
 #include <stdint.h>
 
+#include <array>
 #include <memory>
+#include <numeric>
 
+#include "base/compiler_specific.h"
 #include "base/containers/heap_array.h"
+#include "base/containers/span.h"
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
+#include "base/memory/raw_span.h"
+#include "base/numerics/safe_conversions.h"
 #include "build/build_config.h"
 #include "gpu/command_buffer/common/gles2_cmd_format.h"
 #include "gpu/command_buffer/common/shm_count.h"
@@ -38,12 +39,8 @@
 
 class ProgramBinaryEmulator {
  public:
-  ProgramBinaryEmulator(GLsizei length,
-                        GLenum format,
-                        const char* binary)
-      : length_(length),
-        format_(format),
-        binary_(binary) { }
+  ProgramBinaryEmulator(GLenum format, base::span<const char> binary)
+      : format_(format), binary_(binary) {}
 
   void GetProgramBinary(GLuint program,
                         GLsizei buffer_size,
@@ -51,28 +48,42 @@
                         GLenum* format,
                         GLvoid* binary) {
     if (length) {
-      *length = length_;
+      *length = binary_.size();
     }
     *format = format_;
-    memcpy(binary, binary_, length_);
+
+    // SAFETY: This is an OpenGL entry point and cannot be spanified:
+    // https://docs.gl/es3/glGetProgramBinary
+    // We can only trust what we're given.
+    base::span<char> out_arg =
+        UNSAFE_BUFFERS(base::span(static_cast<char*>(binary), binary_.size()));
+    out_arg.copy_from(binary_);
   }
 
   void ProgramBinary(GLuint program,
                      GLenum format,
                      const GLvoid* binary,
                      GLsizei length) {
+    size_t unsigned_length = base::checked_cast<size_t>(length);
+
+    // SAFETY: This is an OpenGL entry point and cannot be spanified:
+    // https://docs.gl/es3/glProgramBinary
+    // We can only trust what we're given.
+    base::span<const char> cast_binary = UNSAFE_BUFFERS(
+        base::span(static_cast<const char*>(binary), unsigned_length));
+
     // format and length are verified by matcher
-    EXPECT_EQ(0, memcmp(binary_, binary, length));
+    EXPECT_EQ(binary_.first(unsigned_length),
+              cast_binary.first(unsigned_length));
   }
 
-  GLsizei length() const { return length_; }
+  GLsizei length() const { return binary_.size(); }
   GLenum format() const { return format_; }
-  const char* binary() const { return binary_; }
+  const char* binary() const { return binary_.data(); }
 
  private:
-  GLsizei length_;
   GLenum format_;
-  const char* binary_;
+  base::raw_span<const char> binary_;
 };
 
 class MemoryProgramCacheTest : public GpuServiceTest, public DecoderClient {
@@ -223,15 +234,21 @@
   std::vector<std::string> varyings_;
 };
 
+namespace {
+
+std::array<char, 20> TwentyIncrementingChars() {
+  std::array<char, 20> chars;
+  std::iota(chars.begin(), chars.end(), 0);
+  return chars;
+}
+
+}  // namespace
+
 TEST_F(MemoryProgramCacheTest, CacheSave) {
   const GLenum kFormat = 1;
   const int kProgramId = 10;
-  const int kBinaryLength = 20;
-  char test_binary[kBinaryLength];
-  for (int i = 0; i < kBinaryLength; ++i) {
-    test_binary[i] = i;
-  }
-  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+  const auto test_binary = TwentyIncrementingChars();
+  ProgramBinaryEmulator emulator(kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
   cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
@@ -248,12 +265,8 @@
 TEST_F(MemoryProgramCacheTest, LoadProgram) {
   const GLenum kFormat = 1;
   const int kProgramId = 10;
-  const int kBinaryLength = 20;
-  char test_binary[kBinaryLength];
-  for (int i = 0; i < kBinaryLength; ++i) {
-    test_binary[i] = i;
-  }
-  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+  const auto test_binary = TwentyIncrementingChars();
+  ProgramBinaryEmulator emulator(kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
   cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
@@ -280,12 +293,8 @@
 TEST_F(MemoryProgramCacheTest, CacheLoadMatchesSave) {
   const GLenum kFormat = 1;
   const int kProgramId = 10;
-  const int kBinaryLength = 20;
-  char test_binary[kBinaryLength];
-  for (int i = 0; i < kBinaryLength; ++i) {
-    test_binary[i] = i;
-  }
-  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+  const auto test_binary = TwentyIncrementingChars();
+  ProgramBinaryEmulator emulator(kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
   cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
@@ -337,12 +346,8 @@
 TEST_F(MemoryProgramCacheTest, LoadProgramMatchesSave) {
   const GLenum kFormat = 1;
   const int kProgramId = 10;
-  const int kBinaryLength = 20;
-  char test_binary[kBinaryLength];
-  for (int i = 0; i < kBinaryLength; ++i) {
-    test_binary[i] = i;
-  }
-  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+  const auto test_binary = TwentyIncrementingChars();
+  ProgramBinaryEmulator emulator(kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
   cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
@@ -399,12 +404,8 @@
 TEST_F(MemoryProgramCacheTest, LoadFailOnLinkFalse) {
   const GLenum kFormat = 1;
   const int kProgramId = 10;
-  const int kBinaryLength = 20;
-  char test_binary[kBinaryLength];
-  for (int i = 0; i < kBinaryLength; ++i) {
-    test_binary[i] = i;
-  }
-  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+  const auto test_binary = TwentyIncrementingChars();
+  ProgramBinaryEmulator emulator(kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
   cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
@@ -420,12 +421,8 @@
 TEST_F(MemoryProgramCacheTest, LoadFailOnDifferentSource) {
   const GLenum kFormat = 1;
   const int kProgramId = 10;
-  const int kBinaryLength = 20;
-  char test_binary[kBinaryLength];
-  for (int i = 0; i < kBinaryLength; ++i) {
-    test_binary[i] = i;
-  }
-  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+  const auto test_binary = TwentyIncrementingChars();
+  ProgramBinaryEmulator emulator(kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
   cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
@@ -452,12 +449,8 @@
 TEST_F(MemoryProgramCacheTest, LoadFailOnDifferentMap) {
   const GLenum kFormat = 1;
   const int kProgramId = 10;
-  const int kBinaryLength = 20;
-  char test_binary[kBinaryLength];
-  for (int i = 0; i < kBinaryLength; ++i) {
-    test_binary[i] = i;
-  }
-  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+  const auto test_binary = TwentyIncrementingChars();
+  ProgramBinaryEmulator emulator(kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
   ProgramCache::LocationMap binding_map;
@@ -479,12 +472,8 @@
 TEST_F(MemoryProgramCacheTest, LoadFailOnDifferentTransformFeedbackVaryings) {
   const GLenum kFormat = 1;
   const int kProgramId = 10;
-  const int kBinaryLength = 20;
-  char test_binary[kBinaryLength];
-  for (int i = 0; i < kBinaryLength; ++i) {
-    test_binary[i] = i;
-  }
-  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+  const auto test_binary = TwentyIncrementingChars();
+  ProgramBinaryEmulator emulator(kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
   varyings_.push_back("test");
@@ -506,12 +495,8 @@
 TEST_F(MemoryProgramCacheTest, LoadFailIfTransformFeedbackCachingDisabled) {
   const GLenum kFormat = 1;
   const int kProgramId = 10;
-  const int kBinaryLength = 20;
-  char test_binary[kBinaryLength];
-  for (int i = 0; i < kBinaryLength; ++i) {
-    test_binary[i] = i;
-  }
-  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+  const auto test_binary = TwentyIncrementingChars();
+  ProgramBinaryEmulator emulator(kFormat, test_binary);
 
   // Forcibly reset the program cache so we can disable caching of
   // programs which include transform feedback varyings.
@@ -529,20 +514,15 @@
 TEST_F(MemoryProgramCacheTest, MemoryProgramCacheEviction) {
   const GLenum kFormat = 1;
   const int kProgramId = 10;
-  const int kBinaryLength = 20;
-  char test_binary[kBinaryLength];
-  for (int i = 0; i < kBinaryLength; ++i) {
-    test_binary[i] = i;
-  }
-  ProgramBinaryEmulator emulator1(kBinaryLength, kFormat, test_binary);
-
+  const auto test_binary = TwentyIncrementingChars();
+  ProgramBinaryEmulator emulator1(kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator1);
   cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
                             nullptr, varyings_, GL_NONE, this);
 
   const int kEvictingProgramId = 11;
-  const GLuint kEvictingBinaryLength = kCacheSizeBytes - kBinaryLength + 1;
+  const GLuint kEvictingBinaryLength = kCacheSizeBytes - test_binary.size() + 1;
 
   // save old source and modify for new program
   const std::string& old_sig = fragment_shader_->last_compiled_signature();
@@ -553,8 +533,7 @@
   for (size_t i = 0; i < kEvictingBinaryLength; ++i) {
     bigTestBinary[i] = i % 250;
   }
-  ProgramBinaryEmulator emulator2(kEvictingBinaryLength, kFormat,
-                                  bigTestBinary.data());
+  ProgramBinaryEmulator emulator2(kFormat, bigTestBinary);
 
   SetExpectationsForSaveLinkedProgram(kEvictingProgramId, &emulator2);
   cache_->SaveLinkedProgram(kEvictingProgramId, vertex_shader_,
@@ -575,12 +554,8 @@
 TEST_F(MemoryProgramCacheTest, SaveCorrectProgram) {
   const GLenum kFormat = 1;
   const int kProgramId = 10;
-  const int kBinaryLength = 20;
-  char test_binary[kBinaryLength];
-  for (int i = 0; i < kBinaryLength; ++i) {
-    test_binary[i] = i;
-  }
-  ProgramBinaryEmulator emulator1(kBinaryLength, kFormat, test_binary);
+  const auto test_binary = TwentyIncrementingChars();
+  ProgramBinaryEmulator emulator1(kFormat, test_binary);
 
   vertex_shader_->set_source("different!");
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator1);
@@ -597,12 +572,8 @@
 TEST_F(MemoryProgramCacheTest, LoadCorrectProgram) {
   const GLenum kFormat = 1;
   const int kProgramId = 10;
-  const int kBinaryLength = 20;
-  char test_binary[kBinaryLength];
-  for (int i = 0; i < kBinaryLength; ++i) {
-    test_binary[i] = i;
-  }
-  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+  const auto test_binary = TwentyIncrementingChars();
+  ProgramBinaryEmulator emulator(kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
   cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
@@ -626,22 +597,18 @@
 TEST_F(MemoryProgramCacheTest, OverwriteOnNewSave) {
   const GLenum kFormat = 1;
   const int kProgramId = 10;
-  const int kBinaryLength = 20;
-  char test_binary[kBinaryLength];
-  for (int i = 0; i < kBinaryLength; ++i) {
-    test_binary[i] = i;
-  }
-  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+  const auto test_binary = TwentyIncrementingChars();
+  ProgramBinaryEmulator emulator(kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
   cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
                             nullptr, varyings_, GL_NONE, this);
 
-  char test_binary2[kBinaryLength];
-  for (int i = 0; i < kBinaryLength; ++i) {
+  std::array<char, test_binary.size()> test_binary2;
+  for (size_t i = 0; i < test_binary.size(); ++i) {
     test_binary2[i] = (i*2) % 250;
   }
-  ProgramBinaryEmulator emulator2(kBinaryLength, kFormat, test_binary2);
+  ProgramBinaryEmulator emulator2(kFormat, test_binary2);
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator2);
   cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
                             nullptr, varyings_, GL_NONE, this);
@@ -657,12 +624,8 @@
   // Insert a 20 byte program.
   const GLenum kFormat = 1;
   const int kProgramId = 10;
-  const int kBinaryLength = 20;
-  char test_binary[kBinaryLength];
-  for (int i = 0; i < kBinaryLength; ++i) {
-    test_binary[i] = i;
-  }
-  ProgramBinaryEmulator emulator1(kBinaryLength, kFormat, test_binary);
+  const auto test_binary = TwentyIncrementingChars();
+  ProgramBinaryEmulator emulator1(kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator1);
   cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
@@ -674,7 +637,7 @@
 
   fragment_shader_->set_source("al sdfkjdk");
   TestHelper::SetShaderStates(gl_.get(), fragment_shader_, true);
-  ProgramBinaryEmulator emulator2(kBinaryLength, kFormat, test_binary);
+  ProgramBinaryEmulator emulator2(kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kSecondProgramId, &emulator2);
   cache_->SaveLinkedProgram(kSecondProgramId, vertex_shader_, fragment_shader_,
diff --git a/infra/config/generated/builder-owners/chrome-blink-engprod@google.com.txt b/infra/config/generated/builder-owners/chrome-blink-engprod@google.com.txt
index af22ab5..77a0509b 100644
--- a/infra/config/generated/builder-owners/chrome-blink-engprod@google.com.txt
+++ b/infra/config/generated/builder-owners/chrome-blink-engprod@google.com.txt
@@ -7,8 +7,6 @@
 try/android-chrome-13-x64-wpt-android-specific
 try/linux-blink-rel
 try/linux-wpt-chromium-rel
-try/mac11.0-blink-rel
-try/mac11.0.arm64-blink-rel
 try/mac12.0-blink-rel
 try/mac12.0.arm64-blink-rel
 try/mac13-blink-rel
diff --git a/infra/config/generated/builders/ci/android-15-tablet-landscape-x64-rel/targets/chromium.android.json b/infra/config/generated/builders/ci/android-15-tablet-landscape-x64-rel/targets/chromium.android.json
index 0ded41e..8ac1323 100644
--- a/infra/config/generated/builders/ci/android-15-tablet-landscape-x64-rel/targets/chromium.android.json
+++ b/infra/config/generated/builders/ci/android-15-tablet-landscape-x64-rel/targets/chromium.android.json
@@ -6,7 +6,6 @@
           "--git-revision=${got_revision}",
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_x64_tablet_landscape.textpb",
           "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_15_tablet_landscape.chrome_public_test_apk.filter",
-          "--emulator-debug-tags=all",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
         ],
diff --git a/infra/config/generated/builders/ci/android-15-tablet-x64-rel/targets/chromium.android.json b/infra/config/generated/builders/ci/android-15-tablet-x64-rel/targets/chromium.android.json
index bd9d0f6..927e2ff 100644
--- a/infra/config/generated/builders/ci/android-15-tablet-x64-rel/targets/chromium.android.json
+++ b/infra/config/generated/builders/ci/android-15-tablet-x64-rel/targets/chromium.android.json
@@ -51,6 +51,7 @@
         "args": [
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_x64_tablet.textpb",
           "--gtest_filter=-InstallableManagerBrowserTest.CheckManifestWithIconThatIsTooSmall",
+          "--emulator-debug-tags=all",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
         ],
diff --git a/infra/config/generated/builders/gn_args_locations.json b/infra/config/generated/builders/gn_args_locations.json
index 0f7a484..465d999 100644
--- a/infra/config/generated/builders/gn_args_locations.json
+++ b/infra/config/generated/builders/gn_args_locations.json
@@ -536,8 +536,6 @@
     "linux-blink-rel": "try/linux-blink-rel/gn-args.json",
     "linux-wpt-chromium-rel": "try/linux-wpt-chromium-rel/gn-args.json",
     "mac-skia-alt-arm64-blink-rel": "try/mac-skia-alt-arm64-blink-rel/gn-args.json",
-    "mac11.0-blink-rel": "try/mac11.0-blink-rel/gn-args.json",
-    "mac11.0.arm64-blink-rel": "try/mac11.0.arm64-blink-rel/gn-args.json",
     "mac12.0-blink-rel": "try/mac12.0-blink-rel/gn-args.json",
     "mac12.0.arm64-blink-rel": "try/mac12.0.arm64-blink-rel/gn-args.json",
     "mac13-blink-rel": "try/mac13-blink-rel/gn-args.json",
diff --git a/infra/config/generated/builders/try/android-15-tablet-landscape-x64-rel/targets/chromium.android.json b/infra/config/generated/builders/try/android-15-tablet-landscape-x64-rel/targets/chromium.android.json
index 0ded41e..8ac1323 100644
--- a/infra/config/generated/builders/try/android-15-tablet-landscape-x64-rel/targets/chromium.android.json
+++ b/infra/config/generated/builders/try/android-15-tablet-landscape-x64-rel/targets/chromium.android.json
@@ -6,7 +6,6 @@
           "--git-revision=${got_revision}",
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_x64_tablet_landscape.textpb",
           "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_15_tablet_landscape.chrome_public_test_apk.filter",
-          "--emulator-debug-tags=all",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
         ],
diff --git a/infra/config/generated/builders/try/android-15-tablet-x64-rel/targets/chromium.android.json b/infra/config/generated/builders/try/android-15-tablet-x64-rel/targets/chromium.android.json
index bd9d0f6..927e2ff 100644
--- a/infra/config/generated/builders/try/android-15-tablet-x64-rel/targets/chromium.android.json
+++ b/infra/config/generated/builders/try/android-15-tablet-x64-rel/targets/chromium.android.json
@@ -51,6 +51,7 @@
         "args": [
           "--avd-config=../../tools/android/avd/proto/android_35_google_apis_x64_tablet.textpb",
           "--gtest_filter=-InstallableManagerBrowserTest.CheckManifestWithIconThatIsTooSmall",
+          "--emulator-debug-tags=all",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
         ],
diff --git a/infra/config/generated/builders/try/mac11.0-blink-rel/gn-args.json b/infra/config/generated/builders/try/mac11.0-blink-rel/gn-args.json
deleted file mode 100644
index 7633088c..0000000
--- a/infra/config/generated/builders/try/mac11.0-blink-rel/gn-args.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "gn_args": {
-    "dcheck_always_on": false,
-    "ffmpeg_branding": "Chrome",
-    "is_component_build": false,
-    "is_debug": false,
-    "proprietary_codecs": true,
-    "symbol_level": 1,
-    "target_cpu": "x64",
-    "target_os": "mac",
-    "use_reclient": false,
-    "use_remoteexec": true,
-    "use_siso": true
-  }
-}
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/mac11.0-blink-rel/properties.json b/infra/config/generated/builders/try/mac11.0-blink-rel/properties.json
deleted file mode 100644
index 5db11717..0000000
--- a/infra/config/generated/builders/try/mac11.0-blink-rel/properties.json
+++ /dev/null
@@ -1,66 +0,0 @@
-{
-  "$build/chromium_tests_builder_config": {
-    "builder_config": {
-      "additional_exclusions": [
-        "infra/config/generated/builders/try/mac11.0-blink-rel/gn-args.json"
-      ],
-      "builder_db": {
-        "entries": [
-          {
-            "builder_id": {
-              "bucket": "try",
-              "builder": "mac11.0-blink-rel",
-              "project": "chromium"
-            },
-            "builder_spec": {
-              "builder_group": "tryserver.blink",
-              "execution_mode": "COMPILE_AND_TEST",
-              "legacy_chromium_config": {
-                "apply_configs": [
-                  "mb"
-                ],
-                "build_config": "Release",
-                "config": "chromium",
-                "target_bits": 64,
-                "target_platform": "mac"
-              },
-              "legacy_gclient_config": {
-                "config": "chromium"
-              }
-            }
-          }
-        ]
-      },
-      "builder_ids": [
-        {
-          "bucket": "try",
-          "builder": "mac11.0-blink-rel",
-          "project": "chromium"
-        }
-      ],
-      "retry_failed_shards": true,
-      "targets_spec_directory": "src/infra/config/generated/builders/try/mac11.0-blink-rel/targets"
-    }
-  },
-  "$build/siso": {
-    "configs": [
-      "builder"
-    ],
-    "enable_cloud_monitoring": true,
-    "enable_cloud_profiler": true,
-    "enable_cloud_trace": true,
-    "experiments": [],
-    "metrics_project": "chromium-reclient-metrics",
-    "project": "rbe-chromium-untrusted",
-    "remote_jobs": 150
-  },
-  "$recipe_engine/resultdb/test_presentation": {
-    "column_keys": [],
-    "grouping_keys": [
-      "status",
-      "v.test_suite"
-    ]
-  },
-  "builder_group": "tryserver.blink",
-  "recipe": "chromium_trybot"
-}
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/mac11.0-blink-rel/targets/tryserver.blink.json b/infra/config/generated/builders/try/mac11.0-blink-rel/targets/tryserver.blink.json
deleted file mode 100644
index e25709c..0000000
--- a/infra/config/generated/builders/try/mac11.0-blink-rel/targets/tryserver.blink.json
+++ /dev/null
@@ -1,123 +0,0 @@
-{
-  "mac11.0-blink-rel": {
-    "isolated_scripts": [
-      {
-        "args": [
-          "--num-retries=3",
-          "--write-run-histories-to=${ISOLATED_OUTDIR}/run_histories.json"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "blink_web_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-11"
-          },
-          "hard_timeout": 2400,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 5
-        },
-        "test": "blink_web_tests",
-        "test_id_prefix": "ninja://:blink_web_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--write-run-histories-to=${ISOLATED_OUTDIR}/run_histories.json"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "blink_wpt_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-11"
-          },
-          "hard_timeout": 2400,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "blink_wpt_tests",
-        "test_id_prefix": "ninja://:blink_wpt_tests/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/chrome.filter"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "chrome_wpt_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-11"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chrome_wpt_tests",
-        "test_id_prefix": "ninja://:chrome_wpt_tests/"
-      },
-      {
-        "args": [
-          "--test-type",
-          "testharness",
-          "reftest",
-          "crashtest",
-          "print-reftest",
-          "--inverted-test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/chrome.filter",
-          "--inverted-test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/content_shell.filter"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "headless_shell_wpt_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "x86-64",
-            "os": "Mac-11"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 18
-        },
-        "test": "headless_shell_wpt",
-        "test_id_prefix": "ninja://:headless_shell_wpt/"
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/mac11.0.arm64-blink-rel/gn-args.json b/infra/config/generated/builders/try/mac11.0.arm64-blink-rel/gn-args.json
deleted file mode 100644
index 754fd51b..0000000
--- a/infra/config/generated/builders/try/mac11.0.arm64-blink-rel/gn-args.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "gn_args": {
-    "dcheck_always_on": false,
-    "ffmpeg_branding": "Chrome",
-    "is_component_build": false,
-    "is_debug": false,
-    "proprietary_codecs": true,
-    "symbol_level": 1,
-    "target_cpu": "arm64",
-    "target_os": "mac",
-    "use_reclient": false,
-    "use_remoteexec": true,
-    "use_siso": true
-  }
-}
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/mac11.0.arm64-blink-rel/properties.json b/infra/config/generated/builders/try/mac11.0.arm64-blink-rel/properties.json
deleted file mode 100644
index 4990b08f..0000000
--- a/infra/config/generated/builders/try/mac11.0.arm64-blink-rel/properties.json
+++ /dev/null
@@ -1,67 +0,0 @@
-{
-  "$build/chromium_tests_builder_config": {
-    "builder_config": {
-      "additional_exclusions": [
-        "infra/config/generated/builders/try/mac11.0.arm64-blink-rel/gn-args.json"
-      ],
-      "builder_db": {
-        "entries": [
-          {
-            "builder_id": {
-              "bucket": "try",
-              "builder": "mac11.0.arm64-blink-rel",
-              "project": "chromium"
-            },
-            "builder_spec": {
-              "build_gs_bucket": "chromium-fyi-archive",
-              "builder_group": "tryserver.blink",
-              "execution_mode": "COMPILE_AND_TEST",
-              "legacy_chromium_config": {
-                "apply_configs": [
-                  "mb"
-                ],
-                "build_config": "Release",
-                "config": "chromium",
-                "target_bits": 64,
-                "target_platform": "mac"
-              },
-              "legacy_gclient_config": {
-                "config": "chromium"
-              }
-            }
-          }
-        ]
-      },
-      "builder_ids": [
-        {
-          "bucket": "try",
-          "builder": "mac11.0.arm64-blink-rel",
-          "project": "chromium"
-        }
-      ],
-      "retry_failed_shards": true,
-      "targets_spec_directory": "src/infra/config/generated/builders/try/mac11.0.arm64-blink-rel/targets"
-    }
-  },
-  "$build/siso": {
-    "configs": [
-      "builder"
-    ],
-    "enable_cloud_monitoring": true,
-    "enable_cloud_profiler": true,
-    "enable_cloud_trace": true,
-    "experiments": [],
-    "metrics_project": "chromium-reclient-metrics",
-    "project": "rbe-chromium-untrusted",
-    "remote_jobs": 150
-  },
-  "$recipe_engine/resultdb/test_presentation": {
-    "column_keys": [],
-    "grouping_keys": [
-      "status",
-      "v.test_suite"
-    ]
-  },
-  "builder_group": "tryserver.blink",
-  "recipe": "chromium_trybot"
-}
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/mac11.0.arm64-blink-rel/targets/tryserver.blink.json b/infra/config/generated/builders/try/mac11.0.arm64-blink-rel/targets/tryserver.blink.json
deleted file mode 100644
index 9065399..0000000
--- a/infra/config/generated/builders/try/mac11.0.arm64-blink-rel/targets/tryserver.blink.json
+++ /dev/null
@@ -1,123 +0,0 @@
-{
-  "mac11.0.arm64-blink-rel": {
-    "isolated_scripts": [
-      {
-        "args": [
-          "--num-retries=3",
-          "--write-run-histories-to=${ISOLATED_OUTDIR}/run_histories.json"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "blink_web_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "arm64",
-            "os": "Mac-11"
-          },
-          "hard_timeout": 2400,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 5
-        },
-        "test": "blink_web_tests",
-        "test_id_prefix": "ninja://:blink_web_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--write-run-histories-to=${ISOLATED_OUTDIR}/run_histories.json"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "blink_wpt_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "arm64",
-            "os": "Mac-11"
-          },
-          "hard_timeout": 2400,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "blink_wpt_tests",
-        "test_id_prefix": "ninja://:blink_wpt_tests/"
-      },
-      {
-        "args": [
-          "--test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/chrome.filter"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "chrome_wpt_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "arm64",
-            "os": "Mac-11"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chrome_wpt_tests",
-        "test_id_prefix": "ninja://:chrome_wpt_tests/"
-      },
-      {
-        "args": [
-          "--test-type",
-          "testharness",
-          "reftest",
-          "crashtest",
-          "print-reftest",
-          "--inverted-test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/chrome.filter",
-          "--inverted-test-launcher-filter-file=../../third_party/blink/web_tests/TestLists/content_shell.filter"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "headless_shell_wpt_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "cpu": "arm64",
-            "os": "Mac-11"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 18
-        },
-        "test": "headless_shell_wpt",
-        "test_id_prefix": "ninja://:headless_shell_wpt/"
-      }
-    ]
-  }
-}
\ No newline at end of file
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg
index 5093fba6..14e2214 100644
--- a/infra/config/generated/luci/commit-queue.cfg
+++ b/infra/config/generated/luci/commit-queue.cfg
@@ -6495,16 +6495,6 @@
         disable_reuse_footers: "Include-Ci-Only-Tests"
       }
       builders {
-        name: "chromium/try/mac11.0-blink-rel"
-        includable_only: true
-        disable_reuse_footers: "Include-Ci-Only-Tests"
-      }
-      builders {
-        name: "chromium/try/mac11.0.arm64-blink-rel"
-        includable_only: true
-        disable_reuse_footers: "Include-Ci-Only-Tests"
-      }
-      builders {
         name: "chromium/try/mac12-arm64-rel"
         includable_only: true
         disable_reuse_footers: "Include-Ci-Only-Tests"
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index e94fe87..a979963 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -123147,227 +123147,6 @@
       }
     }
     builders {
-      name: "mac11.0-blink-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      dimensions: "builder:mac11.0-blink-rel"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-15"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:1"
-      exe {
-        cipd_package: "infra/chromium/bootstrapper/${platform}"
-        cipd_version: "latest"
-        cmd: "bootstrapper"
-      }
-      properties:
-        '{'
-        '  "$bootstrap/exe": {'
-        '    "exe": {'
-        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
-        '      "cipd_version": "refs/heads/main",'
-        '      "cmd": ['
-        '        "luciexe"'
-        '      ]'
-        '    }'
-        '  },'
-        '  "$bootstrap/properties": {'
-        '    "properties_file": "infra/config/generated/builders/try/mac11.0-blink-rel/properties.json",'
-        '    "top_level_project": {'
-        '      "ref": "refs/heads/main",'
-        '      "repo": {'
-        '        "host": "chromium.googlesource.com",'
-        '        "project": "chromium/src"'
-        '      }'
-        '    }'
-        '  },'
-        '  "builder_group": "tryserver.blink",'
-        '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium_trybot"'
-        '}'
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      grace_period {
-        seconds: 120
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      experiments {
-        key: "chromium.use_per_builder_build_dir_name"
-        value: 100
-      }
-      experiments {
-        key: "luci.buildbucket.canary_software"
-        value: 5
-      }
-      experiments {
-        key: "luci.recipes.use_python3"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "gpu_try_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://(chrome|content)/test:telemetry_gpu_integration_test[^/]*/.+"
-            }
-          }
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "blink_web_tests_try_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*_wpt_tests/.+)|(ninja://[^/]*headless_shell_wpt/.+)"
-            }
-          }
-        }
-        history_options {
-          use_invocation_timestamp: true
-        }
-      }
-      description_html: "Standalone try builder that <a href=\"https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/web_test_expectations.md#rebaselining-using-try-jobs\">generates new expectations</a> for web platform changes.<br/>Builder owner: <a href=mailto:chrome-blink-engprod@google.com>chrome-blink-engprod@google.com</a>"
-      contact_team_email: "chrome-blink-engprod@google.com"
-      custom_metric_definitions {
-        name: "/chrome/infra/browser/builds/cached_count"
-        predicates: "has(build.output.properties.is_cached)"
-        predicates: "string(build.output.properties.is_cached) == \"true\""
-      }
-      custom_metric_definitions {
-        name: "/chrome/infra/browser/builds/ran_tests_retry_shard_count"
-        predicates: "has(build.output.properties.ran_tests_retry_shard)"
-      }
-      custom_metric_definitions {
-        name: "/chrome/infra/browser/builds/ran_tests_without_patch_count"
-        predicates: "has(build.output.properties.ran_tests_without_patch)"
-      }
-      custom_metric_definitions {
-        name: "/chrome/infra/browser/builds/uncached_count"
-        predicates: "has(build.output.properties.is_cached)"
-        predicates: "string(build.output.properties.is_cached) == \"false\""
-      }
-    }
-    builders {
-      name: "mac11.0.arm64-blink-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      dimensions: "builderless:1"
-      dimensions: "cpu:arm64"
-      dimensions: "free_space:standard"
-      dimensions: "os:Mac-15"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:1"
-      exe {
-        cipd_package: "infra/chromium/bootstrapper/${platform}"
-        cipd_version: "latest"
-        cmd: "bootstrapper"
-      }
-      properties:
-        '{'
-        '  "$bootstrap/exe": {'
-        '    "exe": {'
-        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
-        '      "cipd_version": "refs/heads/main",'
-        '      "cmd": ['
-        '        "luciexe"'
-        '      ]'
-        '    }'
-        '  },'
-        '  "$bootstrap/properties": {'
-        '    "properties_file": "infra/config/generated/builders/try/mac11.0.arm64-blink-rel/properties.json",'
-        '    "top_level_project": {'
-        '      "ref": "refs/heads/main",'
-        '      "repo": {'
-        '        "host": "chromium.googlesource.com",'
-        '        "project": "chromium/src"'
-        '      }'
-        '    }'
-        '  },'
-        '  "builder_group": "tryserver.blink",'
-        '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium_trybot"'
-        '}'
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      grace_period {
-        seconds: 120
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      experiments {
-        key: "chromium.use_per_builder_build_dir_name"
-        value: 100
-      }
-      experiments {
-        key: "luci.buildbucket.canary_software"
-        value: 5
-      }
-      experiments {
-        key: "luci.recipes.use_python3"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "gpu_try_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://(chrome|content)/test:telemetry_gpu_integration_test[^/]*/.+"
-            }
-          }
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "blink_web_tests_try_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*_wpt_tests/.+)|(ninja://[^/]*headless_shell_wpt/.+)"
-            }
-          }
-        }
-        history_options {
-          use_invocation_timestamp: true
-        }
-      }
-      description_html: "Standalone try builder that <a href=\"https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/web_test_expectations.md#rebaselining-using-try-jobs\">generates new expectations</a> for web platform changes.<br/>Builder owner: <a href=mailto:chrome-blink-engprod@google.com>chrome-blink-engprod@google.com</a>"
-      contact_team_email: "chrome-blink-engprod@google.com"
-      custom_metric_definitions {
-        name: "/chrome/infra/browser/builds/cached_count"
-        predicates: "has(build.output.properties.is_cached)"
-        predicates: "string(build.output.properties.is_cached) == \"true\""
-      }
-      custom_metric_definitions {
-        name: "/chrome/infra/browser/builds/ran_tests_retry_shard_count"
-        predicates: "has(build.output.properties.ran_tests_retry_shard)"
-      }
-      custom_metric_definitions {
-        name: "/chrome/infra/browser/builds/ran_tests_without_patch_count"
-        predicates: "has(build.output.properties.ran_tests_without_patch)"
-      }
-      custom_metric_definitions {
-        name: "/chrome/infra/browser/builds/uncached_count"
-        predicates: "has(build.output.properties.is_cached)"
-        predicates: "string(build.output.properties.is_cached) == \"false\""
-      }
-    }
-    builders {
       name: "mac12-arm64-rel"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg
index 112dd73..b5f7f20 100644
--- a/infra/config/generated/luci/luci-milo.cfg
+++ b/infra/config/generated/luci/luci-milo.cfg
@@ -27793,12 +27793,6 @@
     name: "buildbucket/luci.chromium.try/mac11-arm64-rel"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/mac11.0-blink-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try/mac11.0.arm64-blink-rel"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/mac12-arm64-rel"
   }
   builders {
@@ -28122,12 +28116,6 @@
     name: "buildbucket/luci.chromium.try/mac-skia-alt-arm64-blink-rel"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/mac11.0-blink-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try/mac11.0.arm64-blink-rel"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/mac12.0-blink-rel"
   }
   builders {
diff --git a/infra/config/subprojects/chromium/ci/chromium.android.star b/infra/config/subprojects/chromium/ci/chromium.android.star
index 2e737b5d..a837248 100644
--- a/infra/config/subprojects/chromium/ci/chromium.android.star
+++ b/infra/config/subprojects/chromium/ci/chromium.android.star
@@ -4483,7 +4483,6 @@
             "chrome_public_test_apk": targets.mixin(
                 args = [
                     "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_15_tablet_landscape.chrome_public_test_apk.filter",
-                    "--emulator-debug-tags=all",
                 ],
             ),
         },
@@ -4554,6 +4553,7 @@
                 args = [
                     # https://crbug.com/375086487
                     "--gtest_filter=-InstallableManagerBrowserTest.CheckManifestWithIconThatIsTooSmall",
+                    "--emulator-debug-tags=all",
                 ],
                 swarming = targets.swarming(
                     shards = 6,
diff --git a/infra/config/subprojects/chromium/try/tryserver.blink.star b/infra/config/subprojects/chromium/try/tryserver.blink.star
index 8beef9d..3da43f9 100644
--- a/infra/config/subprojects/chromium/try/tryserver.blink.star
+++ b/infra/config/subprojects/chromium/try/tryserver.blink.star
@@ -322,112 +322,6 @@
 )
 
 _mac_rebaseline_builder(
-    name = "mac11.0-blink-rel",
-    builder_spec = builder_config.builder_spec(
-        gclient_config = builder_config.gclient_config(
-            config = "chromium",
-        ),
-        chromium_config = builder_config.chromium_config(
-            config = "chromium",
-            apply_configs = [
-                "mb",
-            ],
-            build_config = builder_config.build_config.RELEASE,
-            target_bits = 64,
-            target_platform = builder_config.target_platform.MAC,
-        ),
-    ),
-    builder_config_settings = builder_config.try_settings(
-        retry_failed_shards = True,
-    ),
-    gn_args = gn_args.config(
-        configs = [
-            "release_builder",
-            "remoteexec",
-            "chrome_with_codecs",
-            "minimal_symbols",
-            "mac",
-            "x64",
-        ],
-    ),
-    targets = targets.bundle(
-        targets = [
-            "chromium_webkit_isolated_scripts",
-        ],
-        mixins = [
-            "mac_11_x64",
-        ],
-        per_test_modifications = {
-            "blink_wpt_tests": targets.mixin(
-                swarming = targets.swarming(
-                    hard_timeout_sec = 2400,
-                ),
-            ),
-            "blink_web_tests": targets.mixin(
-                swarming = targets.swarming(
-                    hard_timeout_sec = 2400,
-                ),
-            ),
-        },
-    ),
-    builderless = False,
-)
-
-_mac_rebaseline_builder(
-    name = "mac11.0.arm64-blink-rel",
-    builder_spec = builder_config.builder_spec(
-        gclient_config = builder_config.gclient_config(
-            config = "chromium",
-        ),
-        chromium_config = builder_config.chromium_config(
-            config = "chromium",
-            apply_configs = [
-                "mb",
-            ],
-            build_config = builder_config.build_config.RELEASE,
-            target_bits = 64,
-            target_platform = builder_config.target_platform.MAC,
-        ),
-        build_gs_bucket = "chromium-fyi-archive",
-    ),
-    builder_config_settings = builder_config.try_settings(
-        retry_failed_shards = True,
-    ),
-    gn_args = gn_args.config(
-        configs = [
-            "release_builder",
-            "remoteexec",
-            "chrome_with_codecs",
-            "arm64",
-            "minimal_symbols",
-            "mac",
-        ],
-    ),
-    targets = targets.bundle(
-        targets = [
-            "chromium_webkit_isolated_scripts",
-        ],
-        mixins = [
-            "mac_11_arm64",
-        ],
-        per_test_modifications = {
-            "blink_wpt_tests": targets.mixin(
-                swarming = targets.swarming(
-                    hard_timeout_sec = 2400,
-                ),
-            ),
-            "blink_web_tests": targets.mixin(
-                swarming = targets.swarming(
-                    hard_timeout_sec = 2400,
-                ),
-            ),
-        },
-    ),
-    cores = None,
-    cpu = cpu.ARM64,
-)
-
-_mac_rebaseline_builder(
     name = "mac12.0-blink-rel",
     builder_spec = builder_config.builder_spec(
         gclient_config = builder_config.gclient_config(
diff --git a/infra/inclusive_language_presubmit_exempt_dirs.txt b/infra/inclusive_language_presubmit_exempt_dirs.txt
index a666615..9511d85 100644
--- a/infra/inclusive_language_presubmit_exempt_dirs.txt
+++ b/infra/inclusive_language_presubmit_exempt_dirs.txt
@@ -73,7 +73,7 @@
 chromecast/media/cma/backend 1 1
 chromecast/media/cma/backend/alsa 1 1
 chromecast/public 2 1
-chrome/common 4 3
+chrome/common 3 3
 chrome/common/chromeos/extensions 2 1
 chrome/common/extensions 1 1
 chrome/common/extensions/api 2 2
diff --git a/internal b/internal
index 6113fc6..0cd9d61 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit 6113fc67631d1ddb7a8918e5bb92e34d8492710b
+Subproject commit 0cd9d611e47ef77b8acd24fba00403d8709bd2da
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index d5a5074..ee57b6d2 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -3053,9 +3053,12 @@
       <message name="IDS_IOS_INTENTS_URL_PARAMETER" desc="The URL the user would like to pass as input parameter to Shortcuts that require a URL as input [iOS only].">
         URL
       </message>
-      <message name="IDS_IOS_IPH_BUBBLE_NEXT" desc="Label of a button that appears in an in-product help Tip. Pressing this button will dismiss the Tip, and the next tip will be shown after dismissal.">
+      <message name="IDS_IOS_IPH_BUBBLE_GOT_IT" desc="Label of a button that appears in an in-product help Tip. Pressing this button will dismiss the last Tip.">
         Got it
       </message>
+      <message name="IDS_IOS_IPH_BUBBLE_NEXT" desc="Label of a button that appears in an in-product help Tip. Pressing this button will dismiss the Tip, and the next tip will be shown after dismissal.">
+        Next
+      </message>
       <message name="IDS_IOS_IPH_BUBBLE_SNOOZE" desc="Label of a button that appears in an in-product help Tip. Pressing this button will dismiss the Tip, the user will be reminded of the same Tip later on. Used as a button title in an info bubble." meaning="Used as a button title in an info bubble.">
         Remind me later
       </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IPH_BUBBLE_GOT_IT.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IPH_BUBBLE_GOT_IT.png.sha1
new file mode 100644
index 0000000..beeeaeb
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IPH_BUBBLE_GOT_IT.png.sha1
@@ -0,0 +1 @@
+6abbed82e279206880683322b8bda366599f7422
\ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IPH_BUBBLE_NEXT.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IPH_BUBBLE_NEXT.png.sha1
index e3e91c4..e4cbd2ef 100644
--- a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IPH_BUBBLE_NEXT.png.sha1
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IPH_BUBBLE_NEXT.png.sha1
@@ -1 +1 @@
-3412f4d8c12f481e7ca0dba98c187544c875c685
\ No newline at end of file
+c290332d34d659a498b678596ff0c459abaa5ba4
\ No newline at end of file
diff --git a/ios/chrome/browser/bubble/ui_bundled/bubble_view.mm b/ios/chrome/browser/bubble/ui_bundled/bubble_view.mm
index 35a6c5e..6f176576 100644
--- a/ios/chrome/browser/bubble/ui_bundled/bubble_view.mm
+++ b/ios/chrome/browser/bubble/ui_bundled/bubble_view.mm
@@ -252,10 +252,12 @@
   return label;
 }
 
-UIButton* BubbleNextButton() {
+UIButton* BubbleNextButton(BubblePageControlPage page) {
   UIButton* button = [UIButton buttonWithType:UIButtonTypeSystem];
   button.accessibilityIdentifier = kBubbleViewNextButtonIdentifier;
-  [button setTitle:l10n_util::GetNSString(IDS_IOS_IPH_BUBBLE_NEXT)
+  int textID = page == BubblePageControlPageFourth ? IDS_IOS_IPH_BUBBLE_GOT_IT
+                                                   : IDS_IOS_IPH_BUBBLE_NEXT;
+  [button setTitle:l10n_util::GetNSString(textID)
           forState:UIControlStateNormal];
   [button setTitleColor:[UIColor colorNamed:kSolidButtonTextColor]
                forState:UIControlStateNormal];
@@ -406,7 +408,7 @@
       _separator.translatesAutoresizingMaskIntoConstraints = NO;
       _separator.backgroundColor = [UIColor colorNamed:kSeparatorColor];
       [self addSubview:_separator];
-      _nextButton = BubbleNextButton();
+      _nextButton = BubbleNextButton(page);
       [_nextButton addTarget:self
                       action:@selector(nextButtonWasTapped:)
             forControlEvents:UIControlEventTouchUpInside];
diff --git a/ios/chrome/browser/intelligence/gemini/model/BUILD.gn b/ios/chrome/browser/intelligence/gemini/model/BUILD.gn
index b6698d4..58fa217 100644
--- a/ios/chrome/browser/intelligence/gemini/model/BUILD.gn
+++ b/ios/chrome/browser/intelligence/gemini/model/BUILD.gn
@@ -9,6 +9,7 @@
   ]
   deps = [
     "//components/keyed_service/core",
+    "//components/signin/public/identity_manager",
     "//ios/chrome/browser/signin/model:authentication_service",
     "//ios/chrome/browser/signin/model:authentication_service_factory",
     "//ios/public/provider/chrome/browser/glic:glic_api",
@@ -24,10 +25,12 @@
   ]
   deps = [
     ":model",
+    "//components/signin/public/identity_manager",
     "//ios/chrome/browser/intelligence/features",
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/profile",
     "//ios/chrome/browser/shared/model/profile:profile_keyed_service_factory",
+    "//ios/chrome/browser/signin/model",
     "//ios/chrome/browser/signin/model:authentication_service_factory",
     "//ios/public/provider/chrome/browser/glic:glic_api",
   ]
diff --git a/ios/chrome/browser/intelligence/gemini/model/DEPS b/ios/chrome/browser/intelligence/gemini/model/DEPS
index 8666819c..674507f 100644
--- a/ios/chrome/browser/intelligence/gemini/model/DEPS
+++ b/ios/chrome/browser/intelligence/gemini/model/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   "+ios/chrome/browser/signin/model/authentication_service.h",
   "+ios/chrome/browser/signin/model/authentication_service_factory.h",
+  "+ios/chrome/browser/signin/model/identity_manager_factory.h",
 ]
diff --git a/ios/chrome/browser/intelligence/gemini/model/glic_service.h b/ios/chrome/browser/intelligence/gemini/model/glic_service.h
index 6646284..4683e3f 100644
--- a/ios/chrome/browser/intelligence/gemini/model/glic_service.h
+++ b/ios/chrome/browser/intelligence/gemini/model/glic_service.h
@@ -12,11 +12,15 @@
 #import "components/optimization_guide/proto/features/common_quality_data.pb.h"
 
 class AuthenticationService;
+namespace signin {
+class IdentityManager;
+}  // namespace signin
 
 // A browser-context keyed service for Glic.
 class GlicService : public KeyedService {
  public:
-  GlicService(AuthenticationService* auth_service);
+  GlicService(AuthenticationService* auth_service,
+              signin::IdentityManager* identity_manager);
   ~GlicService() override;
 
   // Presents the overlay on a given view controller.
@@ -24,9 +28,16 @@
       UIViewController* base_view_controller,
       std::unique_ptr<optimization_guide::proto::PageContext> page_context);
 
+  // Returns whether the current profile is eligible for Glic.
+  // TODO(crbug.com/419066154): Use this function to show the entry point.
+  bool IsEligibleForGlic();
+
  private:
   // AuthenticationService used to check if a user is signed in or not.
   raw_ptr<AuthenticationService> auth_service_ = nullptr;
+
+  // Identity manager used to check account capabilities.
+  raw_ptr<signin::IdentityManager> identity_manager_ = nullptr;
 };
 
 #endif  // IOS_CHROME_BROWSER_INTELLIGENCE_GEMINI_MODEL_GLIC_SERVICE_H_
diff --git a/ios/chrome/browser/intelligence/gemini/model/glic_service.mm b/ios/chrome/browser/intelligence/gemini/model/glic_service.mm
index 1ba541a..ad912e3 100644
--- a/ios/chrome/browser/intelligence/gemini/model/glic_service.mm
+++ b/ios/chrome/browser/intelligence/gemini/model/glic_service.mm
@@ -6,11 +6,14 @@
 
 #import <memory>
 
+#import "components/signin/public/identity_manager/identity_manager.h"
 #import "ios/chrome/browser/signin/model/authentication_service.h"
 #import "ios/public/provider/chrome/browser/glic/glic_api.h"
 
-GlicService::GlicService(AuthenticationService* auth_service) {
+GlicService::GlicService(AuthenticationService* auth_service,
+                         signin::IdentityManager* identity_manager) {
   auth_service_ = auth_service;
+  identity_manager_ = identity_manager;
 }
 
 GlicService::~GlicService() = default;
@@ -21,3 +24,16 @@
   ios::provider::StartGlicOverlay(base_view_controller, auth_service_,
                                   std::move(page_context));
 }
+
+bool GlicService::IsEligibleForGlic() {
+  // TODO(crbug.com/419066154): Check other conditions, such as enterprise.
+
+  AccountCapabilities capabilities =
+      identity_manager_
+          ->FindExtendedAccountInfo(identity_manager_->GetPrimaryAccountInfo(
+              signin::ConsentLevel::kSignin))
+          .capabilities;
+
+  return capabilities.can_use_model_execution_features() ==
+         signin::Tribool::kTrue;
+}
diff --git a/ios/chrome/browser/intelligence/gemini/model/glic_service_factory.mm b/ios/chrome/browser/intelligence/gemini/model/glic_service_factory.mm
index f1d6f94a7..d1973da4 100644
--- a/ios/chrome/browser/intelligence/gemini/model/glic_service_factory.mm
+++ b/ios/chrome/browser/intelligence/gemini/model/glic_service_factory.mm
@@ -4,11 +4,13 @@
 
 #import "ios/chrome/browser/intelligence/gemini/model/glic_service_factory.h"
 
+#import "components/signin/public/identity_manager/identity_manager.h"
 #import "ios/chrome/browser/intelligence/features/features.h"
 #import "ios/chrome/browser/intelligence/gemini/model/glic_service.h"
 #import "ios/chrome/browser/shared/model/application_context/application_context.h"
 #import "ios/chrome/browser/shared/model/profile/profile_ios.h"
 #import "ios/chrome/browser/signin/model/authentication_service_factory.h"
+#import "ios/chrome/browser/signin/model/identity_manager_factory.h"
 #import "ios/public/provider/chrome/browser/glic/glic_api.h"
 
 class GlicService;
@@ -21,7 +23,8 @@
   }
   ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
   return std::make_unique<GlicService>(
-      AuthenticationServiceFactory::GetForProfile(profile));
+      AuthenticationServiceFactory::GetForProfile(profile),
+      IdentityManagerFactory::GetForProfile(profile));
 }
 
 }  // namespace
@@ -41,6 +44,7 @@
 GlicServiceFactory::GlicServiceFactory()
     : ProfileKeyedServiceFactoryIOS("GlicService") {
   DependsOn(AuthenticationServiceFactory::GetInstance());
+  DependsOn(IdentityManagerFactory::GetInstance());
 }
 
 GlicServiceFactory::~GlicServiceFactory() = default;
diff --git a/ios/chrome/browser/intelligence/page_action_menu/ui/page_action_menu_view_controller.mm b/ios/chrome/browser/intelligence/page_action_menu/ui/page_action_menu_view_controller.mm
index c89f5f4..2e8c354b 100644
--- a/ios/chrome/browser/intelligence/page_action_menu/ui/page_action_menu_view_controller.mm
+++ b/ios/chrome/browser/intelligence/page_action_menu/ui/page_action_menu_view_controller.mm
@@ -59,7 +59,7 @@
 
   // Add blurred background.
   UIBlurEffect* blurEffect =
-      [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
+      [UIBlurEffect effectWithStyle:UIBlurEffectStyleRegular];
   UIVisualEffectView* blurEffectView =
       [[UIVisualEffectView alloc] initWithEffect:blurEffect];
   blurEffectView.translatesAutoresizingMaskIntoConstraints = NO;
diff --git a/ios/chrome/browser/settings/ui_bundled/BUILD.gn b/ios/chrome/browser/settings/ui_bundled/BUILD.gn
index 9957549..e0354557 100644
--- a/ios/chrome/browser/settings/ui_bundled/BUILD.gn
+++ b/ios/chrome/browser/settings/ui_bundled/BUILD.gn
@@ -171,7 +171,6 @@
     "//ios/chrome/browser/settings/ui_bundled/google_services",
     "//ios/chrome/browser/settings/ui_bundled/google_services:constants",
     "//ios/chrome/browser/settings/ui_bundled/google_services/manage_accounts",
-    "//ios/chrome/browser/settings/ui_bundled/google_services/manage_accounts:manage_accounts_ui",
     "//ios/chrome/browser/settings/ui_bundled/language",
     "//ios/chrome/browser/settings/ui_bundled/language:ui",
     "//ios/chrome/browser/settings/ui_bundled/notifications",
diff --git a/ios/chrome/browser/settings/ui_bundled/settings_table_view_controller.mm b/ios/chrome/browser/settings/ui_bundled/settings_table_view_controller.mm
index dd47792..d058986 100644
--- a/ios/chrome/browser/settings/ui_bundled/settings_table_view_controller.mm
+++ b/ios/chrome/browser/settings/ui_bundled/settings_table_view_controller.mm
@@ -84,7 +84,6 @@
 #import "ios/chrome/browser/settings/ui_bundled/downloads/downloads_settings_coordinator_delegate.h"
 #import "ios/chrome/browser/settings/ui_bundled/elements/enterprise_info_popover_view_controller.h"
 #import "ios/chrome/browser/settings/ui_bundled/google_services/google_services_settings_coordinator.h"
-#import "ios/chrome/browser/settings/ui_bundled/google_services/manage_accounts/manage_accounts_coordinator.h"
 #import "ios/chrome/browser/settings/ui_bundled/google_services/manage_sync_settings_coordinator.h"
 #import "ios/chrome/browser/settings/ui_bundled/language/language_settings_mediator.h"
 #import "ios/chrome/browser/settings/ui_bundled/language/language_settings_table_view_controller.h"
@@ -249,9 +248,6 @@
   // Passwords coordinator.
   PasswordsCoordinator* _passwordsCoordinator;
 
-  // Accounts coordinator.
-  ManageAccountsCoordinator* _manageAccountsCoordinator;
-
   // Feature engagement tracker for the signin IPH.
   raw_ptr<feature_engagement::Tracker> _featureEngagementTracker;
   // Presenter for the signin IPH.
@@ -2054,9 +2050,6 @@
   _passwordsCoordinator.delegate = nil;
   _passwordsCoordinator = nil;
 
-  [_manageAccountsCoordinator stop];
-  _manageAccountsCoordinator = nil;
-
   [_notificationsCoordinator stop];
   _notificationsCoordinator = nil;
 
diff --git a/ios/chrome/test/wpt/BUILD.gn b/ios/chrome/test/wpt/BUILD.gn
index 17e878f..fe9d25d 100644
--- a/ios/chrome/test/wpt/BUILD.gn
+++ b/ios/chrome/test/wpt/BUILD.gn
@@ -11,11 +11,13 @@
 import("//testing/test.gni")
 
 # Options shared by all script test targets that call `run_wpt_tests.py`.
+# TODO(crbug.com/419890016): Consolidate the common options.
 _common_web_test_options = [
   "--no-show-results",
   "--zero-tests-executed-ok",
   "--build-directory",
   "@WrappedPath(.)",
+  "--verbose",
 ]
 if (is_debug) {
   _common_web_test_options += [ "--debug" ]
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc
index a1741a2..18029db 100644
--- a/media/base/video_frame.cc
+++ b/media/base/video_frame.cc
@@ -24,6 +24,8 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/process/memory.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/lock.h"
 #include "base/types/pass_key.h"
@@ -1311,6 +1313,27 @@
   }
 }
 
+// static
+void VideoFrame::UpdateHashWithFrameForTesting(crypto::hash::Hasher& hasher,
+                                               const VideoFrame& frame) {
+  for (size_t plane = 0; plane < NumPlanes(frame.format()); ++plane) {
+    for (int row = 0; row < frame.rows(plane); ++row) {
+      hasher.Update(frame.data_[plane].subspan(
+          base::checked_cast<size_t>(frame.stride(plane) * row),
+          base::checked_cast<size_t>(frame.row_bytes(plane))));
+    }
+  }
+}
+
+// static
+std::string VideoFrame::HexHashOfFrameForTesting(const VideoFrame& frame) {
+  crypto::hash::Hasher hasher(crypto::hash::HashKind::kSha256);
+  UpdateHashWithFrameForTesting(hasher, frame);  // IN-TEST
+  std::array<uint8_t, crypto::hash::kSha256Size> hash;
+  hasher.Finish(hash);
+  return base::ToLowerASCII(base::HexEncode(hash));
+}
+
 void VideoFrame::BackWithSharedMemory(
     const base::ReadOnlySharedMemoryRegion* region) {
   DCHECK(!shm_region_);
diff --git a/media/base/video_frame.h b/media/base/video_frame.h
index a9c22c0..1bcdef5 100644
--- a/media/base/video_frame.h
+++ b/media/base/video_frame.h
@@ -31,6 +31,7 @@
 #include "base/types/pass_key.h"
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
+#include "crypto/hash.h"
 #include "gpu/command_buffer/client/client_shared_image.h"
 #include "gpu/command_buffer/common/mailbox_holder.h"
 #include "gpu/ipc/common/vulkan_ycbcr_info.h"
@@ -529,9 +530,20 @@
 
   // Used to keep a running hash of seen frames.  Expects an initialized MD5
   // context.  Calls MD5Update with the context and the contents of the frame.
+  //
+  // Deprecated, do not use this.
+  // TODO(https://crbug.com/419771387): Remove this.
   static void HashFrameForTesting(base::MD5Context* context,
                                   const VideoFrame& frame);
 
+  // Given a crypto/hash Hasher, hash in the pixels from a single VideoFrame.
+  static void UpdateHashWithFrameForTesting(crypto::hash::Hasher& hasher,
+                                            const VideoFrame& frame);
+
+  // Convenience wrapper around UpdateHashWithFrameForTesting(): produces the
+  // SHA-256 hash of a single video frame's pixels, as a lowercase hex string.
+  static std::string HexHashOfFrameForTesting(const VideoFrame& frame);
+
   // Returns true if |frame| is accessible mapped in the VideoFrame memory
   // space.
   // static
diff --git a/media/base/video_frame_unittest.cc b/media/base/video_frame_unittest.cc
index f96df0c..6a1af98 100644
--- a/media/base/video_frame_unittest.cc
+++ b/media/base/video_frame_unittest.cc
@@ -150,8 +150,6 @@
 
 namespace media {
 
-using base::MD5DigestToBase16;
-
 // Helper function that initializes a YV12 frame with white and black scan
 // lines based on the |white_to_black| parameter.  If 0, then the entire
 // frame will be black, if 1 then the entire frame will be white.
@@ -242,12 +240,7 @@
            frame->stride(plane) * frame->rows(plane));
   }
 
-  base::MD5Context context;
-  base::MD5Init(&context);
-  VideoFrame::HashFrameForTesting(&context, *frame.get());
-  base::MD5Digest digest;
-  base::MD5Final(&digest, &context);
-  EXPECT_EQ(MD5DigestToBase16(digest), expected_hash);
+  EXPECT_EQ(VideoFrame::HexHashOfFrameForTesting(*frame.get()), expected_hash);
 }
 
 TEST(VideoFrame, CreateFrame) {
@@ -268,21 +261,15 @@
     InitializeYV12Frame(frame.get(), 0.0f);
     ExpectFrameColor(frame.get(), 0xFF000000);
   }
-  base::MD5Digest digest;
-  base::MD5Context context;
-  base::MD5Init(&context);
-  VideoFrame::HashFrameForTesting(&context, *frame.get());
-  base::MD5Final(&digest, &context);
-  EXPECT_EQ(MD5DigestToBase16(digest), "9065c841d9fca49186ef8b4ef547e79b");
+  EXPECT_EQ(VideoFrame::HexHashOfFrameForTesting(*frame.get()),
+            "48a14002453cf6ff6719661fc0715cbf1978214c182d1b4bbb9afb934051d630");
   {
     SCOPED_TRACE("");
     InitializeYV12Frame(frame.get(), 1.0f);
     ExpectFrameColor(frame.get(), 0xFFFFFFFF);
   }
-  base::MD5Init(&context);
-  VideoFrame::HashFrameForTesting(&context, *frame.get());
-  base::MD5Final(&digest, &context);
-  EXPECT_EQ(MD5DigestToBase16(digest), "911991d51438ad2e1a40ed5f6fc7c796");
+  EXPECT_EQ(VideoFrame::HexHashOfFrameForTesting(*frame.get()),
+            "a08db3e63e9b8ca723142d7fb734716a3a2af9f0e655271eb5acc9d2c2088dbb");
 
   // Test single planar frame.
   frame = VideoFrame::CreateFrame(PIXEL_FORMAT_ARGB, size, gfx::Rect(size),
@@ -642,8 +629,12 @@
 TEST(VideoFrame, CheckFrameExtents) {
   // Each call consists of a Format and the expected hash of all
   // planes if filled with kFillByte (defined in ExpectFrameExtents).
-  ExpectFrameExtents(PIXEL_FORMAT_YV12, "8e5d54cb23cd0edca111dd35ffb6ff05");
-  ExpectFrameExtents(PIXEL_FORMAT_I422, "cce408a044b212db42a10dfec304b3ef");
+  ExpectFrameExtents(
+      PIXEL_FORMAT_YV12,
+      "cdf392577e7dced37c10e986b82be9aaabdfe32a3e8c1e132c9986a533447740");
+  ExpectFrameExtents(
+      PIXEL_FORMAT_I422,
+      "df513a840bbb43915da7b3d00c1191ce3f46d6e657db5ab7f65e3f879c6eded0");
 }
 
 static void TextureCallback(gpu::SyncToken* called_sync_token,
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index 023b25c..b835ee7 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -2,13 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "media/ffmpeg/ffmpeg_common.h"
 
+#include "base/containers/span.h"
 #include "base/hash/sha1.h"
 #include "base/logging.h"
 #include "base/no_destructor.h"
@@ -53,7 +49,7 @@
 VideoDecoderConfig::AlphaMode GetAlphaMode(const AVStream* stream) {
   AVDictionaryEntry* alpha_mode =
       av_dict_get(stream->metadata, "alpha_mode", nullptr, 0);
-  return alpha_mode && !strcmp(alpha_mode->value, "1")
+  return alpha_mode && std::string_view(alpha_mode->value) == "1"
              ? VideoDecoderConfig::AlphaMode::kHasAlpha
              : VideoDecoderConfig::AlphaMode::kIsOpaque;
 }
@@ -91,6 +87,46 @@
   }
 }
 
+inline base::span<uint8_t> AVCodecContextToSpan(
+    const AVCodecContext* codec_context) {
+  // SAFETY:
+  // https://ffmpeg.org/doxygen/6.0/structAVCodecContext.html#abe964316aaaa61967b012efdcced79c4
+  // ffmpeg documentation: The allocated memory should be
+  // `AV_INPUT_BUFFER_PADDING_SIZE` bytes larger than `extradata_size`. So when
+  // we only use extradata_size bytes, it is safe.
+  return UNSAFE_BUFFERS(
+      base::span(codec_context->extradata,
+                 base::checked_cast<size_t>(codec_context->extradata_size)));
+}
+
+template <typename T>
+void CopyBufferFromConfig(const T& config, AVCodecContext* codec_context) {
+  if (config.extra_data().empty()) {
+    codec_context->extradata = nullptr;
+    codec_context->extradata_size = 0;
+    return;
+  }
+  codec_context->extradata_size = config.extra_data().size();
+  codec_context->extradata = reinterpret_cast<uint8_t*>(
+      av_malloc(config.extra_data().size() + AV_INPUT_BUFFER_PADDING_SIZE));
+  // SAFETY:
+  // https://ffmpeg.org/doxygen/6.0/structAVCodecContext.html#abe964316aaaa61967b012efdcced79c4
+  // ffmpeg documentation: The allocated memory should be
+  // `AV_INPUT_BUFFER_PADDING_SIZE` bytes larger than `extradata_size`. And the
+  // memory must be allocated using `av_malloc`.
+  //
+  // We allocated the appropriate memory according to this rule above and
+  // converted it to `base::span` here. So this is safe.
+  base::span allocated_extradata = UNSAFE_BUFFERS(
+      base::span(codec_context->extradata,
+                 static_cast<size_t>(config.extra_data().size() +
+                                     AV_INPUT_BUFFER_PADDING_SIZE)));
+  auto [extradata, padding] =
+      allocated_extradata.split_at(config.extra_data().size());
+  extradata.copy_from_nonoverlapping(config.extra_data());
+  std::ranges::fill(padding, '\0');
+}
+
 }  // namespace
 
 // Allows faster SIMD YUV convert. Also, FFmpeg overreads/-writes occasionally.
@@ -415,8 +451,9 @@
 
   std::vector<uint8_t> extra_data;
   if (codec_context->extradata_size > 0) {
-    extra_data.assign(codec_context->extradata,
-                      codec_context->extradata + codec_context->extradata_size);
+    extra_data.resize(codec_context->extradata_size);
+    base::span(extra_data)
+        .copy_from_nonoverlapping(AVCodecContextToSpan(codec_context));
   }
 
   config->Initialize(codec, sample_format, channel_layout, codec_context->sample_rate,
@@ -496,18 +533,7 @@
   codec_context->ch_layout.nb_channels = config.channels();
   codec_context->sample_rate = config.samples_per_second();
 
-  if (config.extra_data().empty()) {
-    codec_context->extradata = nullptr;
-    codec_context->extradata_size = 0;
-  } else {
-    codec_context->extradata_size = config.extra_data().size();
-    codec_context->extradata = reinterpret_cast<uint8_t*>(
-        av_malloc(config.extra_data().size() + AV_INPUT_BUFFER_PADDING_SIZE));
-    memcpy(codec_context->extradata, &config.extra_data()[0],
-           config.extra_data().size());
-    memset(codec_context->extradata + config.extra_data().size(), '\0',
-           AV_INPUT_BUFFER_PADDING_SIZE);
-  }
+  CopyBufferFromConfig(config, codec_context);
   ApplyCodecContextSecuritySettings(codec_context);
 }
 
@@ -750,13 +776,14 @@
 
   std::vector<uint8_t> extra_data;
   if (codec_context->extradata_size > 0) {
-    extra_data.assign(codec_context->extradata,
-                      codec_context->extradata + codec_context->extradata_size);
+    extra_data.resize(codec_context->extradata_size);
+    base::span(extra_data)
+        .copy_from_nonoverlapping(AVCodecContextToSpan(codec_context.get()));
   }
 
   VideoTransformation video_transformation = VideoTransformation();
-  for (int i = 0; i < stream->codecpar->nb_coded_side_data; ++i) {
-    const auto& side_data = stream->codecpar->coded_side_data[i];
+  for (const auto& side_data :
+       AVCodecParametersCodedSideToSpan(stream->codecpar)) {
     switch (side_data.type) {
       case AV_PKT_DATA_DISPLAYMATRIX: {
         CHECK_EQ(side_data.size, sizeof(int32_t) * 3 * 3);
@@ -868,18 +895,7 @@
   if (config.color_space_info().range == gfx::ColorSpace::RangeID::FULL)
     codec_context->color_range = AVCOL_RANGE_JPEG;
 
-  if (config.extra_data().empty()) {
-    codec_context->extradata = nullptr;
-    codec_context->extradata_size = 0;
-  } else {
-    codec_context->extradata_size = config.extra_data().size();
-    codec_context->extradata = reinterpret_cast<uint8_t*>(
-        av_malloc(config.extra_data().size() + AV_INPUT_BUFFER_PADDING_SIZE));
-    memcpy(codec_context->extradata, &config.extra_data()[0],
-           config.extra_data().size());
-    memset(codec_context->extradata + config.extra_data().size(), '\0',
-           AV_INPUT_BUFFER_PADDING_SIZE);
-  }
+  CopyBufferFromConfig(config, codec_context);
   ApplyCodecContextSecuritySettings(codec_context);
 }
 
@@ -1014,22 +1030,25 @@
 int32_t HashCodecName(const char* codec_name) {
   // Use the first 32-bits from the SHA1 hash as the identifier.
   int32_t hash;
-  memcpy(&hash, base::SHA1HashString(codec_name).substr(0, 4).c_str(), 4);
+  base::byte_span_from_ref(hash).copy_from_nonoverlapping(
+      base::as_byte_span(base::SHA1HashString(codec_name)).first<4>());
   return hash;
 }
 
 const char* GetAllowedAudioDecoders() {
-  static const base::NoDestructor<std::string> kAllowedAudioCodecs([]() {
-    // This should match the configured lists in //third_party/ffmpeg.
-    std::string allowed_decoders(
-        "vorbis,libopus,flac,pcm_u8,pcm_s16le,pcm_s24le,pcm_s32le,pcm_f32le,"
-        "mp3,pcm_s16be,pcm_s24be,pcm_mulaw,pcm_alaw");
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
-    allowed_decoders += ",aac";
+#define EXTRA_CODECS ",aac"
+#else
+#define EXTRA_CODECS
 #endif
-    return allowed_decoders;
-  }());
-  return kAllowedAudioCodecs->c_str();
+
+  // This should match the configured lists in //third_party/ffmpeg.
+  static constexpr std::string_view kAllowedAudioCodecs =
+      "vorbis,libopus,flac,pcm_u8,pcm_s16le,pcm_s24le,pcm_s32le,pcm_f32le,"
+      "mp3,pcm_s16be,pcm_s24be,pcm_mulaw,pcm_alaw" EXTRA_CODECS;
+#undef EXTRA_CODECS
+
+  return kAllowedAudioCodecs.data();
 }
 
 }  // namespace media
diff --git a/media/ffmpeg/ffmpeg_common.h b/media/ffmpeg/ffmpeg_common.h
index 0225b37..ca0a6d2 100644
--- a/media/ffmpeg/ffmpeg_common.h
+++ b/media/ffmpeg/ffmpeg_common.h
@@ -93,6 +93,28 @@
       base::span(packet.data, base::checked_cast<size_t>(packet.size)));
 }
 
+inline base::span<AVStream*> AVFormatContextToSpan(
+    const AVFormatContext* codec_context) {
+  // SAFETY:
+  // https://ffmpeg.org/doxygen/trunk/structAVFormatContext.html#a0b748d924898b08b89ff4974afd17285
+  // ffmpeg documentation: `nb_streams` is the number of elements in
+  // `AVFormatContext.streams`.
+  return UNSAFE_BUFFERS(
+      base::span(codec_context->streams,
+                 base::checked_cast<size_t>(codec_context->nb_streams)));
+}
+
+inline base::span<AVPacketSideData> AVCodecParametersCodedSideToSpan(
+    const AVCodecParameters* codecpar) {
+  // SAFETY:
+  // https://ffmpeg.org/doxygen/trunk/structAVCodecParameters.html#a29643cfd94231e2d148a5d17b08d115b
+  // ffmpeg documentation: `nb_coded_side_data` is the amount of entries in
+  // `coded_side_data`.
+  return UNSAFE_BUFFERS(
+      base::span(codecpar->coded_side_data,
+                 base::checked_cast<size_t>(codecpar->nb_coded_side_data)));
+}
+
 // Converts an int64_t timestamp in |time_base| units to a base::TimeDelta.
 // For example if |timestamp| equals 11025 and |time_base| equals {1, 44100}
 // then the return value will be a base::TimeDelta for 0.25 seconds since that
diff --git a/media/ffmpeg/ffmpeg_common_unittest.cc b/media/ffmpeg/ffmpeg_common_unittest.cc
index 5b1a54a..cb337c3 100644
--- a/media/ffmpeg/ffmpeg_common_unittest.cc
+++ b/media/ffmpeg/ffmpeg_common_unittest.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "media/ffmpeg/ffmpeg_common.h"
 
 #include <stddef.h>
@@ -37,6 +32,17 @@
 
 uint8_t kExtraData[5] = {0x00, 0x01, 0x02, 0x03, 0x04};
 
+inline base::span<uint8_t> AVCodecParametersExtraDataToSpan(
+    const AVCodecParameters* codec_context) {
+  // SAFETY:
+  // https://ffmpeg.org/doxygen/trunk/structAVCodecParameters.html#a9befe0b86412646017afb0051d144d13
+  // ffmpeg documentation: The allocated size of `extradata` must be at least
+  // `extradata_size + AV_INPUT_BUFFER_PADDING_SIZE`.
+  return UNSAFE_BUFFERS(
+      base::span(codec_context->extradata,
+                 base::checked_cast<size_t>(codec_context->extradata_size)));
+}
+
 template <typename T>
 void TestConfigConvertExtraData(
     AVStream* stream,
@@ -63,9 +69,8 @@
   EXPECT_TRUE(converter_fn.Run(stream, decoder_config));
   EXPECT_EQ(static_cast<size_t>(codec_parameters->extradata_size),
             decoder_config->extra_data().size());
-  EXPECT_EQ(
-      0, memcmp(codec_parameters->extradata, &decoder_config->extra_data()[0],
-                decoder_config->extra_data().size()));
+  EXPECT_EQ(AVCodecParametersExtraDataToSpan(codec_parameters),
+            base::span(decoder_config->extra_data()));
 
   // Possible combination: extra_data = nullptr && size != 0, but the converter
   // function considers this valid and having no extra_data, due to behavior of
@@ -95,8 +100,7 @@
   ASSERT_TRUE(glue.OpenContext());
   AVFormatContext* format_context = glue.format_context();
 
-  for (size_t i = 0; i < format_context->nb_streams; ++i) {
-    AVStream* stream = format_context->streams[i];
+  for (auto* stream : AVFormatContextToSpan(format_context)) {
     AVCodecParameters* codec_parameters = stream->codecpar;
     AVMediaType codec_type = codec_parameters->codec_type;
 
@@ -124,10 +128,11 @@
   // for extradata and extradata_size.
   bool found_audio = false;
   bool found_video = false;
-  for (size_t i = 0;
-       i < format_context->nb_streams && (!found_audio || !found_video);
-       ++i) {
-    AVStream* stream = format_context->streams[i];
+  for (AVStream* stream : AVFormatContextToSpan(format_context)) {
+    if (found_audio && found_video) {
+      break;
+    }
+
     AVCodecParameters* codec_parameters = stream->codecpar;
     AVMediaType codec_type = codec_parameters->codec_type;
 
diff --git a/media/filters/audio_video_metadata_extractor.cc b/media/filters/audio_video_metadata_extractor.cc
index 3ff1d184..1a1333a 100644
--- a/media/filters/audio_video_metadata_extractor.cc
+++ b/media/filters/audio_video_metadata_extractor.cc
@@ -2,13 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "media/filters/audio_video_metadata_extractor.h"
 
+#include <algorithm>
+
 #include "base/functional/bind.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -106,21 +103,22 @@
     has_duration_ = true;
   }
 
-  stream_infos_.push_back(StreamInfo());
+  stream_infos_.emplace_back();
   StreamInfo& container_info = stream_infos_.back();
   container_info.type = format_context->iformat->name;
   ExtractDictionary(format_context->metadata, &container_info.tags);
 
-  for (unsigned int i = 0; i < format_context->nb_streams; ++i) {
-    stream_infos_.push_back(StreamInfo());
+  base::span<AVStream*> format_context_span =
+      AVFormatContextToSpan(format_context);
+  std::ranges::for_each(format_context_span, [&](AVStream* stream) {
+    stream_infos_.emplace_back();
     StreamInfo& info = stream_infos_.back();
 
-    AVStream* stream = format_context->streams[i];
-    if (!stream)
-      continue;
+    if (!stream) {
+      return;
+    }
 
-    for (int j = 0; j < stream->codecpar->nb_coded_side_data; j++) {
-      const AVPacketSideData& sd = stream->codecpar->coded_side_data[j];
+    for (const auto& sd : AVCodecParametersCodedSideToSpan(stream->codecpar)) {
       if (sd.type == AV_PKT_DATA_DISPLAYMATRIX) {
         CHECK_EQ(sd.size, sizeof(int32_t) * 3 * 3);
         rotation_ = VideoTransformation::FromFFmpegDisplayMatrix(
@@ -135,8 +133,9 @@
     // metadata to contained streams instead the container itself, like OGG.
     ExtractDictionary(stream->metadata, &info.tags);
 
-    if (!stream->codecpar)
-      continue;
+    if (!stream->codecpar) {
+      return;
+    }
 
     info.type = avcodec_get_name(stream->codecpar->codec_id);
 
@@ -153,12 +152,12 @@
         stream->attached_pic.size > 0 &&
         stream->attached_pic.size <= kAttachedImageSizeLimit &&
         stream->attached_pic.data != nullptr) {
-      attached_images_bytes_.push_back(std::string());
+      attached_images_bytes_.emplace_back();
       attached_images_bytes_.back().assign(
           reinterpret_cast<const char*>(stream->attached_pic.data),
           stream->attached_pic.size);
     }
-  }
+  });
 
   extracted_ = true;
   return true;
diff --git a/media/filters/dav1d_video_decoder_unittest.cc b/media/filters/dav1d_video_decoder_unittest.cc
index af75237..a223c37 100644
--- a/media/filters/dav1d_video_decoder_unittest.cc
+++ b/media/filters/dav1d_video_decoder_unittest.cc
@@ -183,15 +183,6 @@
     output_frames_.push_back(std::move(frame));
   }
 
-  std::string GetVideoFrameHash(const VideoFrame& frame) {
-    base::MD5Context md5_context;
-    base::MD5Init(&md5_context);
-    VideoFrame::HashFrameForTesting(&md5_context, frame);
-    base::MD5Digest digest;
-    base::MD5Final(&digest, &md5_context);
-    return base::MD5DigestToBase16(digest);
-  }
-
   MOCK_METHOD1(DecodeDone, void(DecoderStatus));
 
   base::test::SingleThreadTaskEnvironment task_environment_;
@@ -232,7 +223,8 @@
 
   const auto& frame = output_frames_.front();
   EXPECT_EQ(PIXEL_FORMAT_I420, frame->format());
-  EXPECT_EQ("589dc641b7742ffe7a2b0d4c16aa3e86", GetVideoFrameHash(*frame));
+  EXPECT_EQ("52b7d8e65b031f09c0db38d1f36113a332bd7bfcafde95ee794112261535e223",
+            VideoFrame::HexHashOfFrameForTesting(*frame));
 }
 
 TEST_F(Dav1dVideoDecoderTest, DecodeFrame_8bitMono) {
@@ -246,7 +238,8 @@
   EXPECT_EQ(PIXEL_FORMAT_I420, frame->format());
   EXPECT_EQ(frame->data(VideoFrame::Plane::kU),
             frame->data(VideoFrame::Plane::kV));
-  EXPECT_EQ("eeba03dcc9c22c4632bf74b481db36b2", GetVideoFrameHash(*frame));
+  EXPECT_EQ("3d85366c6607ea2f829bd7058a3f77f23ecd10327612bc62171dbff08421e3ad",
+            VideoFrame::HexHashOfFrameForTesting(*frame));
 }
 
 TEST_F(Dav1dVideoDecoderTest, DecodeFrame_10bitMono) {
@@ -260,7 +253,8 @@
   EXPECT_EQ(PIXEL_FORMAT_YUV420P10, frame->format());
   EXPECT_EQ(frame->data(VideoFrame::Plane::kU),
             frame->data(VideoFrame::Plane::kV));
-  EXPECT_EQ("026c1fed9e161f09d816ac7278458a80", GetVideoFrameHash(*frame));
+  EXPECT_EQ("0a659dd4f04ecee14ca1881435ad8d18ce862ef519aaa990191cc8fa0ba66eb2",
+            VideoFrame::HexHashOfFrameForTesting(*frame));
 }
 
 TEST_F(Dav1dVideoDecoderTest, DecodeFrame_12bitMono) {
@@ -274,7 +268,8 @@
   EXPECT_EQ(PIXEL_FORMAT_YUV420P12, frame->format());
   EXPECT_EQ(frame->data(VideoFrame::Plane::kU),
             frame->data(VideoFrame::Plane::kV));
-  EXPECT_EQ("32115092dc00fbe86823b0b714a0f63e", GetVideoFrameHash(*frame));
+  EXPECT_EQ("f1acdafc4a9fa0840d7d938a9dea41ac55f612cecce2d6b89095c44fc7f29c46",
+            VideoFrame::HexHashOfFrameForTesting(*frame));
 }
 
 TEST_F(Dav1dVideoDecoderTest, DecodeFrame_AgtmMetadata) {
diff --git a/media/filters/media_file_checker.cc b/media/filters/media_file_checker.cc
index 57d6596f..2e73f3b9 100644
--- a/media/filters/media_file_checker.cc
+++ b/media/filters/media_file_checker.cc
@@ -2,15 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "media/filters/media_file_checker.h"
 
 #include <stddef.h>
 #include <stdint.h>
+
+#include <algorithm>
 #include <map>
 #include <memory>
 #include <utility>
@@ -67,22 +64,29 @@
   // Remember the codec context for any decodable audio or video streams.
   bool found_streams = false;
   std::vector<Decoder> stream_contexts(format_context->nb_streams);
-  for (size_t i = 0; i < format_context->nb_streams; ++i) {
-    AVCodecParameters* cp = format_context->streams[i]->codecpar;
+  base::span<AVStream*> format_context_span =
+      AVFormatContextToSpan(format_context);
+  std::ranges::transform(
+      format_context_span, stream_contexts.begin(),
+      [&found_streams](AVStream* stream) {
+        AVCodecParameters* cp = stream->codecpar;
 
-    if (cp->codec_type == AVMEDIA_TYPE_AUDIO ||
-        cp->codec_type == AVMEDIA_TYPE_VIDEO) {
-      auto context = AVStreamToAVCodecContext(format_context->streams[i]);
-      if (!context)
-        continue;
-      const AVCodec* codec = avcodec_find_decoder(cp->codec_id);
-      if (codec && avcodec_open2(context.get(), codec, nullptr) >= 0) {
-        auto loop = std::make_unique<FFmpegDecodingLoop>(context.get());
-        stream_contexts[i] = {std::move(context), std::move(loop)};
-        found_streams = true;
-      }
-    }
-  }
+        if (cp->codec_type == AVMEDIA_TYPE_AUDIO ||
+            cp->codec_type == AVMEDIA_TYPE_VIDEO) {
+          auto context = AVStreamToAVCodecContext(stream);
+          if (!context) {
+            return Decoder{};
+          }
+          const AVCodec* codec = avcodec_find_decoder(cp->codec_id);
+          if (codec && avcodec_open2(context.get(), codec, nullptr) >= 0) {
+            auto loop = std::make_unique<FFmpegDecodingLoop>(context.get());
+            found_streams = true;
+            return Decoder{std::move(context), std::move(loop)};
+          }
+        }
+
+        return Decoder{};
+      });
 
   if (!found_streams)
     return false;
diff --git a/media/gpu/av1_decoder.cc b/media/gpu/av1_decoder.cc
index 054820e..f8b2095 100644
--- a/media/gpu/av1_decoder.cc
+++ b/media/gpu/av1_decoder.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "media/gpu/av1_decoder.h"
 
 #include <algorithm>
@@ -181,8 +176,7 @@
   // skip it and will keep skipping until we get a sequence header.
   current_sequence_header_.reset();
   stream_id_ = 0;
-  stream_ = nullptr;
-  stream_size_ = 0;
+  stream_ = {};
   on_error_ = false;
 
   state_ = std::make_unique<libgav1::DecoderState>();
@@ -200,15 +194,13 @@
 
 void AV1Decoder::SetStream(int32_t id, const DecoderBuffer& decoder_buffer) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  auto decoder_buffer_span = base::span(decoder_buffer);
+  stream_ = base::span(decoder_buffer);
   stream_id_ = id;
-  stream_ = decoder_buffer_span.data();
-  stream_size_ = decoder_buffer_span.size();
   ClearCurrentFrame();
 
   parser_ = base::WrapUnique(new (std::nothrow) libgav1::ObuParser(
-      decoder_buffer_span.data(), decoder_buffer_span.size(),
-      kDefaultOperatingPoint, buffer_pool_.get(), state_.get()));
+      stream_.data(), stream_.size(), kDefaultOperatingPoint,
+      buffer_pool_.get(), state_.get()));
   if (!parser_) {
     on_error_ = true;
     return;
@@ -226,8 +218,8 @@
     secure_handle_ = 0;
   }
 
-  const AV1Accelerator::Status status = accelerator_->SetStream(
-      base::span(stream_.get(), stream_size_), decrypt_config_.get());
+  const AV1Accelerator::Status status =
+      accelerator_->SetStream(stream_, decrypt_config_.get());
   if (status != AV1Accelerator::Status::kOk) {
     on_error_ = true;
     return;
@@ -580,10 +572,8 @@
   // For intra frames, we don't need this assertion because they shouldn't
   // depend on reference frames.
   if (!libgav1::IsIntraFrame(current_frame_header_->frame_type)) {
-    for (size_t i = 0; i < libgav1::kNumInterReferenceFrameTypes; ++i) {
-      const auto ref_frame_index =
-          current_frame_header_->reference_frame_index[i];
-
+    for (int8_t ref_frame_index :
+         current_frame_header_->reference_frame_index) {
       // Unless an error occurred in libgav1, |ref_frame_index| should be valid,
       // and since CheckAndCleanUpReferenceFrames() only gets called if parsing
       // succeeded, we can assert that validity.
@@ -604,16 +594,15 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(pic);
   DCHECK(current_sequence_header_);
-  DCHECK(stream_);
-  DCHECK_GT(stream_size_, 0u);
+  DCHECK(!stream_.empty());
   if (!CheckAndCleanUpReferenceFrames()) {
     DLOG(ERROR) << "The states of reference frames are different between "
                 << "|ref_frames_| and |state_|";
     return AV1Accelerator::Status::kFail;
   }
-  const AV1Accelerator::Status status = accelerator_->SubmitDecode(
-      *pic, *current_sequence_header_, ref_frames_, tile_buffers,
-      base::span(stream_.get(), stream_size_));
+  const AV1Accelerator::Status status =
+      accelerator_->SubmitDecode(*pic, *current_sequence_header_, ref_frames_,
+                                 tile_buffers, base::span(stream_));
   if (status != AV1Accelerator::Status::kOk) {
     if (status == AV1Accelerator::Status::kTryAgain)
       pending_pic_ = std::move(pic);
diff --git a/media/gpu/av1_decoder.h b/media/gpu/av1_decoder.h
index 4d1108c..4f011983 100644
--- a/media/gpu/av1_decoder.h
+++ b/media/gpu/av1_decoder.h
@@ -192,8 +192,7 @@
   std::optional<gfx::HDRMetadata> hdr_metadata_;
 
   int32_t stream_id_ = 0;
-  raw_ptr<const uint8_t, DanglingUntriaged> stream_ = nullptr;
-  size_t stream_size_ = 0;
+  base::raw_span<const uint8_t, DanglingUntriaged> stream_;
   std::unique_ptr<DecryptConfig> decrypt_config_;
 
   // Secure handle to pass through to the accelerator when doing secure playback
diff --git a/media/gpu/av1_decoder_unittest.cc b/media/gpu/av1_decoder_unittest.cc
index 5d98592..a8b2c7a 100644
--- a/media/gpu/av1_decoder_unittest.cc
+++ b/media/gpu/av1_decoder_unittest.cc
@@ -2,17 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "media/gpu/av1_decoder.h"
 
 #include <string.h>
 
 #include <algorithm>
 #include <array>
+#include <iterator>
 #include <string>
 #include <vector>
 
@@ -212,8 +208,7 @@
   EXPECT_FALSE(decoder_->current_frame_header_);
   EXPECT_FALSE(decoder_->current_frame_);
   EXPECT_NE(decoder_->stream_id_, 0);
-  EXPECT_TRUE(decoder_->stream_);
-  EXPECT_GT(decoder_->stream_size_, 0u);
+  EXPECT_FALSE(decoder_->stream_.empty());
 
   decoder_->Reset();
   EXPECT_EQ(decoder_->state_->current_frame_id, -1);
@@ -225,8 +220,7 @@
   EXPECT_FALSE(decoder_->current_frame_header_);
   EXPECT_FALSE(decoder_->current_frame_);
   EXPECT_EQ(decoder_->stream_id_, 0);
-  EXPECT_FALSE(decoder_->stream_);
-  EXPECT_EQ(decoder_->stream_size_, 0u);
+  EXPECT_TRUE(decoder_->stream_.empty());
 }
 
 scoped_refptr<DecoderBuffer> AV1DecoderTest::ReadDecoderBuffer(
@@ -273,19 +267,17 @@
   InMemoryUrlProtocol protocol(*webm_data, false);
   FFmpegGlue glue(&protocol);
   LOG_ASSERT(glue.OpenContext());
-  int stream_index = -1;
-  for (unsigned int i = 0; i < glue.format_context()->nb_streams; ++i) {
-    const AVStream* stream = glue.format_context()->streams[i];
+  base::span<AVStream*> format_context =
+      AVFormatContextToSpan(glue.format_context());
+  auto iter = std::ranges::find_if(format_context, [](AVStream* stream) {
     const AVCodecParameters* codec_parameters = stream->codecpar;
     const AVMediaType codec_type = codec_parameters->codec_type;
     const AVCodecID codec_id = codec_parameters->codec_id;
-    if (codec_type == AVMEDIA_TYPE_VIDEO && codec_id == AV_CODEC_ID_AV1) {
-      stream_index = i;
-      break;
-    }
-  }
-  EXPECT_NE(stream_index, -1) << "No AV1 data found in " << input_file;
-
+    return codec_type == AVMEDIA_TYPE_VIDEO && codec_id == AV_CODEC_ID_AV1;
+  });
+  EXPECT_NE(iter, format_context.end())
+      << "No AV1 data found in " << input_file;
+  int stream_index = std::distance(format_context.begin(), iter);
   std::vector<scoped_refptr<DecoderBuffer>> buffers;
   auto packet = ScopedAVPacket::Allocate();
   while (av_read_frame(glue.format_context(), packet.get()) >= 0) {
@@ -792,8 +784,11 @@
   EXPECT_EQ(av1_picture->frame_header.frame_type, libgav1::kFrameInter);
 
   // Next, let's check the reference frames that frame needs.
-  for (int8_t i = 0; i < libgav1::kNumInterReferenceFrameTypes; ++i)
-    EXPECT_EQ(av1_picture->frame_header.reference_frame_index[i], i);
+  base::span<int8_t> reference_frame_index(
+      av1_picture->frame_header.reference_frame_index);
+  for (size_t i = 0; i < reference_frame_index.size(); ++i) {
+    EXPECT_EQ(static_cast<size_t>(reference_frame_index[i]), i);
+  }
 
   // Finally, let's check that libgav1 thought that all the reference frames
   // were valid.
diff --git a/media/gpu/test/raw_video.cc b/media/gpu/test/raw_video.cc
index 241ba34..af09dffe9 100644
--- a/media/gpu/test/raw_video.cc
+++ b/media/gpu/test/raw_video.cc
@@ -314,24 +314,22 @@
   FFmpegGlue glue(&protocol);
   LOG_ASSERT(glue.OpenContext()) << "Failed to open AVFormatContext";
   // Find the first VP9 stream in the file.
-  std::optional<size_t> vp9_stream_index;
   VideoDecoderConfig config;
-  for (size_t i = 0; i < glue.format_context()->nb_streams; ++i) {
-    AVStream* stream = glue.format_context()->streams[i];
+  base::span<AVStream*> format_context =
+      AVFormatContextToSpan(glue.format_context());
+  auto iter = std::ranges::find_if(format_context, [&config](AVStream* stream) {
     const AVCodecParameters* codec_parameters = stream->codecpar;
     const AVMediaType codec_type = codec_parameters->codec_type;
     const AVCodecID codec_id = codec_parameters->codec_id;
-    if (codec_type == AVMEDIA_TYPE_VIDEO && codec_id == AV_CODEC_ID_VP9 &&
-        AVStreamToVideoDecoderConfig(stream, &config) &&
-        config.IsValidConfig()) {
-      vp9_stream_index = i;
-      break;
-    }
-  }
-  if (!vp9_stream_index) {
+    return codec_type == AVMEDIA_TYPE_VIDEO && codec_id == AV_CODEC_ID_VP9 &&
+           AVStreamToVideoDecoderConfig(stream, &config) &&
+           config.IsValidConfig();
+  });
+  if (iter == format_context.end()) {
     return nullptr;
   }
-
+  std::optional<size_t> vp9_stream_index =
+      std::distance(format_context.begin(), iter);
   auto vp9_data_mmap_file = CreateMemoryMappedFile(vp9_webm_data.size());
   uint8_t* const vp9_data = vp9_data_mmap_file->data();
   size_t vp9_data_size = 0;
diff --git a/media/gpu/vaapi/h264_vaapi_video_decoder_delegate.cc b/media/gpu/vaapi/h264_vaapi_video_decoder_delegate.cc
index 7ec048b..b89d4897 100644
--- a/media/gpu/vaapi/h264_vaapi_video_decoder_delegate.cc
+++ b/media/gpu/vaapi/h264_vaapi_video_decoder_delegate.cc
@@ -377,10 +377,20 @@
       DVLOG(1) << "Failure submitting encrypted slice header buffers";
       return DecodeStatus::kFail;
     }
+
     if (!vaapi_wrapper_->ExecuteAndDestroyPendingBuffers(surface->id())) {
+      if (NeedsProtectedSessionRecovery()) {
+        LOG(ERROR) << "Retry slice header decrypt due to recovery";
+        return DecodeStatus::kTryAgain;
+      }
       LOG(ERROR) << "Failed executing for slice header decrypt";
       return DecodeStatus::kFail;
     }
+
+    if (IsEncryptedSession()) {
+      ProtectedDecodedSucceeded();
+    }
+
     if (status_buf->status != VA_ENCRYPTION_STATUS_SUCCESSFUL) {
       LOG(ERROR) << "Failure status in encrypted header parsing: "
                  << static_cast<int>(status_buf->status);
diff --git a/media/mojo/mojom/video_frame_mojom_traits_unittest.cc b/media/mojo/mojom/video_frame_mojom_traits_unittest.cc
index e3270a77..572da7e 100644
--- a/media/mojo/mojom/video_frame_mojom_traits_unittest.cc
+++ b/media/mojo/mojom/video_frame_mojom_traits_unittest.cc
@@ -90,9 +90,7 @@
                       EchoVideoFrameCallback callback) override {
     // Touch all data in the received frame to ensure that it is valid.
     if (f && f->IsMappable()) {
-      base::MD5Context md5_context;
-      base::MD5Init(&md5_context);
-      VideoFrame::HashFrameForTesting(&md5_context, *f);
+      VideoFrame::HexHashOfFrameForTesting(*f);
     }
 
     std::move(callback).Run(f);
diff --git a/net/disk_cache/blockfile/backend_impl.cc b/net/disk_cache/blockfile/backend_impl.cc
index 3053b6f..91f988b 100644
--- a/net/disk_cache/blockfile/backend_impl.cc
+++ b/net/disk_cache/blockfile/backend_impl.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "net/disk_cache/blockfile/backend_impl.h"
 
 #include <algorithm>
@@ -16,6 +11,7 @@
 #include <utility>
 
 #include "base/containers/heap_array.h"
+#include "base/containers/span.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -1307,8 +1303,9 @@
   header.table_len = DesiredIndexTableLen(max_size_);
   header.create_time = Time::Now().ToInternalValue();
 
-  if (!file->Write(&header, sizeof(header), 0))
+  if (!file->Write(base::byte_span_from_ref(header), 0)) {
     return false;
+  }
 
   size_t size = GetIndexSize(header.table_len);
   if (!file->SetLength(size))
@@ -1322,17 +1319,16 @@
   // header), to force allocation now and fail cleanly if there is no space.
   //
   // See https://crbug.com/1097518
-  const int kPageSize = 4096;
+  static constexpr size_t kPageSize = 4096;
   static_assert(sizeof(disk_cache::IndexHeader) < kPageSize,
                 "Code below assumes it wouldn't overwrite header by starting "
                 "at kPageSize");
-  auto page = std::make_unique<char[]>(kPageSize);
-  memset(page.get(), 0, kPageSize);
-
+  auto page = base::HeapArray<uint8_t>::WithSize(kPageSize);
   for (size_t offset = kPageSize; offset < size; offset += kPageSize) {
     size_t end = std::min(offset + kPageSize, size);
-    if (!file->Write(page.get(), end - offset, offset))
+    if (!file->Write(page.first(end - offset), offset)) {
       return false;
+    }
   }
   return true;
 }
@@ -1919,8 +1915,12 @@
     return false;
   }
 
-  if (!mask_)
-    mask_ = data_->header.table_len - 1;
+  if (!mask_) {
+    // `data_->header.table_len` may be larger than `kIndexTablesize`. This will
+    // cause a memory out of bounds error.
+    mask_ = std::min(static_cast<int>(kIndexTablesize) - 1,
+                     data_->header.table_len - 1);
+  }
 
   // Load the table into memory.
   return index_->Preload();
@@ -1969,16 +1969,20 @@
 bool BackendImpl::CheckEntry(EntryImpl* cache_entry) {
   bool ok = block_files_.IsValid(cache_entry->entry()->address());
   ok = ok && block_files_.IsValid(cache_entry->rankings()->address());
-  EntryStore* data = cache_entry->entry()->Data();
-  for (size_t i = 0; i < std::size(data->data_addr); i++) {
-    if (data->data_addr[i]) {
-      Addr address(data->data_addr[i]);
-      if (address.is_block_file())
-        ok = ok && block_files_.IsValid(address);
-    }
-  }
+  ok = ok && cache_entry->rankings()->VerifyHash();
+  ok = ok && std::ranges::all_of(
+                 cache_entry->entry()->Data()->data_addr,
+                 [&block_files = block_files_](const CacheAddr& cache_addr) {
+                   if (cache_addr) {
+                     Addr address(cache_addr);
+                     if (address.is_block_file()) {
+                       return block_files.IsValid(address);
+                     }
+                   }
 
-  return ok && cache_entry->rankings()->VerifyHash();
+                   return true;
+                 });
+  return ok;
 }
 
 // static
diff --git a/net/disk_cache/blockfile/disk_format.cc b/net/disk_cache/blockfile/disk_format.cc
index 6c75dd1..637e89b 100644
--- a/net/disk_cache/blockfile/disk_format.cc
+++ b/net/disk_cache/blockfile/disk_format.cc
@@ -12,10 +12,6 @@
 
 static_assert(sizeof(IndexHeader) == 368);
 
-IndexHeader::IndexHeader() {
-  std::ranges::fill(base::byte_span_from_ref(*this), 0);
-  magic = kIndexMagic;
-  version = kCurrentVersion;
-}
+IndexHeader::IndexHeader() = default;
 
 }  // namespace disk_cache
diff --git a/net/disk_cache/blockfile/disk_format.h b/net/disk_cache/blockfile/disk_format.h
index 72e62bf..faaa0749 100644
--- a/net/disk_cache/blockfile/disk_format.h
+++ b/net/disk_cache/blockfile/disk_format.h
@@ -49,60 +49,63 @@
 #include <stdint.h>
 #include <string.h>
 
+#include <array>
+
 #include "net/base/net_export.h"
 #include "net/disk_cache/blockfile/disk_format_base.h"
 
 namespace disk_cache {
 
-const int kIndexTablesize = 0x10000;
-const uint32_t kIndexMagic = 0xC103CAC3;
-const uint32_t kVersion2_0 = 0x20000;
-const uint32_t kVersion2_1 = 0x20001;
-const uint32_t kVersion3_0 = 0x30000;
-const uint32_t kCurrentVersion = kVersion3_0;
+inline constexpr size_t kIndexTablesize = 0x10000;
+inline constexpr uint32_t kIndexMagic = 0xC103CAC3;
+inline constexpr uint32_t kVersion2_0 = 0x20000;
+inline constexpr uint32_t kVersion2_1 = 0x20001;
+inline constexpr uint32_t kVersion3_0 = 0x30000;
+inline constexpr uint32_t kCurrentVersion = kVersion3_0;
 
 struct LruData {
-  int32_t pad1[2];
-  int32_t filled;  // Flag to tell when we filled the cache.
-  int32_t sizes[5];
-  CacheAddr heads[5];
-  CacheAddr tails[5];
-  CacheAddr transaction;     // In-flight operation target.
-  int32_t operation;         // Actual in-flight operation.
-  int32_t operation_list;    // In-flight operation list.
-  int32_t pad2[7];
+  std::array<int32_t, 2> pad1 = {};
+  int32_t filled = 0;  // Flag to tell when we filled the cache.
+  std::array<int32_t, 5> sizes = {};
+  std::array<CacheAddr, 5> heads = {};
+  std::array<CacheAddr, 5> tails = {};
+  CacheAddr transaction = 0;   // In-flight operation target.
+  int32_t operation = 0;       // Actual in-flight operation.
+  int32_t operation_list = 0;  // In-flight operation list.
+  std::array<int32_t, 7> pad2 = {};
 };
 
 // Header for the master index file.
 struct NET_EXPORT_PRIVATE IndexHeader {
   IndexHeader();
 
-  uint32_t magic;
-  uint32_t version;
-  int32_t num_entries;       // Number of entries currently stored.
-  int32_t old_v2_num_bytes;  // Total size of the stored data, in versions 2.x
-  int32_t last_file;         // Last external file created.
-  int32_t this_id;           // Id for all entries being changed (dirty flag).
-  CacheAddr   stats;         // Storage for usage data.
-  int32_t table_len;         // Actual size of the table (0 == kIndexTablesize).
-  int32_t crash;             // Signals a previous crash.
-  int32_t experiment;        // Id of an ongoing test.
-  uint64_t create_time;      // Creation time for this set of files.
-  int64_t num_bytes;         // Total size of the stored data, in version 3.0
-  int32_t pad[50];
+  uint32_t magic = kIndexMagic;
+  uint32_t version = kCurrentVersion;
+  int32_t num_entries = 0;  // Number of entries currently stored.
+  int32_t old_v2_num_bytes =
+      0;                     // Total size of the stored data, in versions 2.x
+  int32_t last_file = 0;     // Last external file created.
+  int32_t this_id = 0;       // Id for all entries being changed (dirty flag).
+  CacheAddr stats = 0;       // Storage for usage data.
+  int32_t table_len = 0;     // Actual size of the table (0 == kIndexTablesize).
+  int32_t crash = 0;         // Signals a previous crash.
+  int32_t experiment = 0;    // Id of an ongoing test.
+  uint64_t create_time = 0;  // Creation time for this set of files.
+  int64_t num_bytes = 0;     // Total size of the stored data, in version 3.0
+  std::array<int32_t, 50> pad = {};
   LruData     lru;           // Eviction control data.
 };
 
 // The structure of the whole index file.
 struct Index {
   IndexHeader header;
-  CacheAddr   table[kIndexTablesize];  // Default size. Actual size controlled
-                                       // by header.table_len.
+  // Default size. Actual size controlled by header.table_len.
+  std::array<CacheAddr, kIndexTablesize> table = {};
 };
 
 // Main structure for an entry on the backing storage. If the key is longer than
 // what can be stored on this structure, it will be extended on consecutive
-// blocks (adding 256 bytes each time), up to 4 blocks (1024 - 32 - 1 chars).
+// blocks (adding 256 bytes each time), up to 4 blocks (1024 - 96 - 1 chars).
 // After that point, the whole key will be stored as a data block or external
 // file.
 struct EntryStore {
@@ -116,7 +119,7 @@
   int32_t key_len;
   CacheAddr   long_key;           // Optional address of a long key.
   int32_t data_size[4];           // We can store up to 4 data streams for each
-  CacheAddr   data_addr[4];       // entry.
+  std::array<CacheAddr, 4> data_addr;  // entry.
   uint32_t flags;                 // Any combination of EntryFlags.
   int32_t pad[4];
   uint32_t self_hash;             // The hash of EntryStore up to this point.
diff --git a/net/disk_cache/blockfile/file.cc b/net/disk_cache/blockfile/file.cc
index b37694c0..3142e2d7 100644
--- a/net/disk_cache/blockfile/file.cc
+++ b/net/disk_cache/blockfile/file.cc
@@ -13,4 +13,33 @@
 
 File::File(bool mixed_mode) : init_(false), mixed_(mixed_mode) {}
 
+bool File::Read(void* buffer, size_t buffer_len, size_t offset) {
+  return UNSAFE_TODO(
+      Read(base::span(static_cast<uint8_t*>(buffer), buffer_len), offset));
+}
+
+bool File::Write(const void* buffer, size_t buffer_len, size_t offset) {
+  return UNSAFE_TODO(Write(
+      base::span(static_cast<const uint8_t*>(buffer), buffer_len), offset));
+}
+
+bool File::Read(void* buffer,
+                size_t buffer_len,
+                size_t offset,
+                FileIOCallback* callback,
+                bool* completed) {
+  return UNSAFE_TODO(Read(base::span(static_cast<uint8_t*>(buffer), buffer_len),
+                          offset, callback, completed));
+}
+
+bool File::Write(const void* buffer,
+                 size_t buffer_len,
+                 size_t offset,
+                 FileIOCallback* callback,
+                 bool* completed) {
+  return UNSAFE_TODO(
+      Write(base::span(static_cast<const uint8_t*>(buffer), buffer_len), offset,
+            callback, completed));
+}
+
 }  // namespace disk_cache
diff --git a/net/disk_cache/blockfile/file.h b/net/disk_cache/blockfile/file.h
index 1477343..1e1b339 100644
--- a/net/disk_cache/blockfile/file.h
+++ b/net/disk_cache/blockfile/file.h
@@ -10,6 +10,7 @@
 #include <stddef.h>
 
 #include "base/files/file.h"
+#include "base/memory/raw_span.h"
 #include "base/memory/ref_counted.h"
 #include "net/base/net_export.h"
 
@@ -54,13 +55,43 @@
   bool IsValid() const;
 
   // Performs synchronous IO.
+  //
+  // Read/Write the content from the file `offset` position, and the content
+  // will be placed in the `buffer`. If the read/write size is equal to the
+  // `buffer` size, it returns `true`, otherwise it returns `false`.
+  bool Read(base::span<uint8_t> buffer, size_t offset);
+  bool Write(base::span<const uint8_t> buffer, size_t offset);
+
+  // DEPRECATED: Use the above `base::span` variant to avoid unsafe buffer
+  // usage.
+  // TODO(https://crbug.com/40284755): Remove this once the callers are gone.
   bool Read(void* buffer, size_t buffer_len, size_t offset);
+
+  // DEPRECATED: Use the above `base::span` variant to avoid unsafe buffer
+  // usage.
+  // TODO(https://crbug.com/40284755): Remove this once the callers are gone.
   bool Write(const void* buffer, size_t buffer_len, size_t offset);
 
   // Performs asynchronous IO. callback will be called when the IO completes,
   // as an APC on the thread that queued the operation.
+  bool Read(base::span<uint8_t> buffer,
+            size_t offset,
+            FileIOCallback* callback,
+            bool* completed);
+  bool Write(base::span<const uint8_t> buffer,
+             size_t offset,
+             FileIOCallback* callback,
+             bool* completed);
+
+  // DEPRECATED: Use the above `base::span` variant to avoid unsafe buffer
+  // usage.
+  // TODO(https://crbug.com/40284755): Remove this once the callers are gone.
   bool Read(void* buffer, size_t buffer_len, size_t offset,
             FileIOCallback* callback, bool* completed);
+
+  // DEPRECATED: Use the above `base::span` variant to avoid unsafe buffer
+  // usage.
+  // TODO(https://crbug.com/40284755): Remove this once the callers are gone.
   bool Write(const void* buffer, size_t buffer_len, size_t offset,
              FileIOCallback* callback, bool* completed);
 
@@ -84,12 +115,14 @@
  private:
   // Performs the actual asynchronous write. If notify is set and there is no
   // callback, the call will be re-synchronized.
-  bool AsyncWrite(const void* buffer, size_t buffer_len, size_t offset,
-                  FileIOCallback* callback, bool* completed);
+  bool AsyncWrite(base::span<const uint8_t> buffer,
+                  size_t offset,
+                  FileIOCallback* callback,
+                  bool* completed);
 
   // Infrastructure for async IO.
-  int DoRead(void* buffer, size_t buffer_len, size_t offset);
-  int DoWrite(const void* buffer, size_t buffer_len, size_t offset);
+  int DoRead(base::raw_span<uint8_t> buffer, size_t offset);
+  int DoWrite(base::raw_span<const uint8_t> buffer, size_t offset);
   void OnOperationComplete(FileIOCallback* callback, int result);
 
   bool init_;
diff --git a/net/disk_cache/blockfile/file_ios.cc b/net/disk_cache/blockfile/file_ios.cc
index 94ecdbe..92ebaee 100644
--- a/net/disk_cache/blockfile/file_ios.cc
+++ b/net/disk_cache/blockfile/file_ios.cc
@@ -12,9 +12,12 @@
 
 #include "base/check.h"
 #include "base/compiler_specific.h"
+#include "base/containers/span.h"
 #include "base/functional/bind.h"
 #include "base/location.h"
 #include "base/memory/raw_ptr.h"
+#include "base/memory/raw_span.h"
+#include "base/numerics/checked_math.h"
 #include "base/task/thread_pool.h"
 #include "net/base/net_errors.h"
 #include "net/disk_cache/blockfile/in_flight_io.h"
@@ -31,12 +34,16 @@
   // is keeping track of all operations. When done, we notify the controller
   // (we do NOT invoke the callback), in the worker thead that completed the
   // operation.
-  FileBackgroundIO(disk_cache::File* file, const void* buf, size_t buf_len,
-                   size_t offset, disk_cache::FileIOCallback* callback,
+  FileBackgroundIO(disk_cache::File* file,
+                   base::span<uint8_t> buffer,
+                   size_t offset,
+                   disk_cache::FileIOCallback* callback,
                    disk_cache::InFlightIO* controller)
-      : disk_cache::BackgroundIO(controller), callback_(callback), file_(file),
-        buf_(buf), buf_len_(buf_len), offset_(offset) {
-  }
+      : disk_cache::BackgroundIO(controller),
+        callback_(callback),
+        file_(file),
+        buffer_(buffer),
+        offset_(offset) {}
 
   FileBackgroundIO(const FileBackgroundIO&) = delete;
   FileBackgroundIO& operator=(const FileBackgroundIO&) = delete;
@@ -63,8 +70,7 @@
   raw_ptr<disk_cache::FileIOCallback> callback_;
 
   raw_ptr<disk_cache::File> file_;
-  raw_ptr<const void> buf_;
-  size_t buf_len_;
+  base::raw_span<uint8_t> buffer_;
   size_t offset_;
 };
 
@@ -82,10 +88,14 @@
   // These methods start an asynchronous operation. The arguments have the same
   // semantics of the File asynchronous operations, with the exception that the
   // operation never finishes synchronously.
-  void PostRead(disk_cache::File* file, void* buf, size_t buf_len,
-                size_t offset, disk_cache::FileIOCallback* callback);
-  void PostWrite(disk_cache::File* file, const void* buf, size_t buf_len,
-                 size_t offset, disk_cache::FileIOCallback* callback);
+  void PostRead(disk_cache::File* file,
+                base::span<uint8_t> buffer,
+                size_t offset,
+                disk_cache::FileIOCallback* callback);
+  void PostWrite(disk_cache::File* file,
+                 base::span<uint8_t> buffer,
+                 size_t offset,
+                 disk_cache::FileIOCallback* callback);
 
  protected:
   // Invokes the users' completion callback at the end of the IO operation.
@@ -100,8 +110,8 @@
 
 // Runs on a worker thread.
 void FileBackgroundIO::Read() {
-  if (file_->Read(const_cast<void*>(buf_.get()), buf_len_, offset_)) {
-    result_ = static_cast<int>(buf_len_);
+  if (file_->Read(buffer_, offset_)) {
+    result_ = buffer_.size();
   } else {
     result_ = net::ERR_CACHE_READ_FAILURE;
   }
@@ -110,18 +120,20 @@
 
 // Runs on a worker thread.
 void FileBackgroundIO::Write() {
-  bool rv = file_->Write(buf_, buf_len_, offset_);
+  bool rv = file_->Write(buffer_, offset_);
 
-  result_ = rv ? static_cast<int>(buf_len_) : net::ERR_CACHE_WRITE_FAILURE;
+  result_ = rv ? buffer_.size() : net::ERR_CACHE_WRITE_FAILURE;
   NotifyController();
 }
 
 // ---------------------------------------------------------------------------
 
-void FileInFlightIO::PostRead(disk_cache::File *file, void* buf, size_t buf_len,
-                          size_t offset, disk_cache::FileIOCallback *callback) {
-  auto operation = base::MakeRefCounted<FileBackgroundIO>(
-      file, buf, buf_len, offset, callback, this);
+void FileInFlightIO::PostRead(disk_cache::File* file,
+                              base::span<uint8_t> buffer,
+                              size_t offset,
+                              disk_cache::FileIOCallback* callback) {
+  auto operation = base::MakeRefCounted<FileBackgroundIO>(file, buffer, offset,
+                                                          callback, this);
   file->AddRef();  // Balanced on OnOperationComplete()
 
   base::ThreadPool::PostTask(
@@ -131,11 +143,12 @@
   OnOperationPosted(operation.get());
 }
 
-void FileInFlightIO::PostWrite(disk_cache::File* file, const void* buf,
-                           size_t buf_len, size_t offset,
-                           disk_cache::FileIOCallback* callback) {
-  auto operation = base::MakeRefCounted<FileBackgroundIO>(
-      file, buf, buf_len, offset, callback, this);
+void FileInFlightIO::PostWrite(disk_cache::File* file,
+                               base::span<uint8_t> buffer,
+                               size_t offset,
+                               disk_cache::FileIOCallback* callback) {
+  auto operation = base::MakeRefCounted<FileBackgroundIO>(file, buffer, offset,
+                                                          callback, this);
   file->AddRef();  // Balanced on OnOperationComplete()
 
   base::ThreadPool::PostTask(
@@ -203,61 +216,78 @@
   return base_file_.IsValid();
 }
 
-bool File::Read(void* buffer, size_t buffer_len, size_t offset) {
+bool File::Read(base::span<uint8_t> buffer, size_t offset) {
   DCHECK(base_file_.IsValid());
-  if (buffer_len > static_cast<size_t>(std::numeric_limits<int32_t>::max()) ||
-      offset > static_cast<size_t>(std::numeric_limits<int32_t>::max())) {
+  if (!base::IsValueInRangeForNumericType<int32_t>(buffer.size()) ||
+      !base::IsValueInRangeForNumericType<int32_t>(offset)) {
     return false;
   }
 
-  int ret = UNSAFE_TODO(
-      base_file_.Read(offset, static_cast<char*>(buffer), buffer_len));
-  return (static_cast<size_t>(ret) == buffer_len);
+  std::optional<size_t> ret = base_file_.Read(offset, buffer);
+  return ret == buffer.size();
 }
 
-bool File::Write(const void* buffer, size_t buffer_len, size_t offset) {
+bool File::Write(base::span<const uint8_t> buffer, size_t offset) {
   DCHECK(base_file_.IsValid());
-  if (buffer_len > static_cast<size_t>(std::numeric_limits<int32_t>::max()) ||
-      offset > static_cast<size_t>(std::numeric_limits<int32_t>::max())) {
+  if (!base::IsValueInRangeForNumericType<int32_t>(buffer.size()) ||
+      !base::IsValueInRangeForNumericType<int32_t>(offset)) {
     return false;
   }
 
-  int ret = UNSAFE_TODO(
-      base_file_.Write(offset, static_cast<const char*>(buffer), buffer_len));
-  return (static_cast<size_t>(ret) == buffer_len);
+  std::optional<size_t> ret = base_file_.Write(offset, buffer);
+  return ret == buffer.size();
 }
 
 // We have to increase the ref counter of the file before performing the IO to
 // prevent the completion to happen with an invalid handle (if the file is
 // closed while the IO is in flight).
-bool File::Read(void* buffer, size_t buffer_len, size_t offset,
-                FileIOCallback* callback, bool* completed) {
+bool File::Read(base::span<uint8_t> buffer,
+                size_t offset,
+                FileIOCallback* callback,
+                bool* completed) {
   DCHECK(base_file_.IsValid());
   if (!callback) {
     if (completed)
       *completed = true;
-    return Read(buffer, buffer_len, offset);
+    return Read(buffer, offset);
   }
 
-  if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
+  if (offset > ULONG_MAX) {
     return false;
+  }
 
-  GetFileInFlightIO()->PostRead(this, buffer, buffer_len, offset, callback);
+  GetFileInFlightIO()->PostRead(this, buffer, offset, callback);
 
   *completed = false;
   return true;
 }
 
-bool File::Write(const void* buffer, size_t buffer_len, size_t offset,
-                 FileIOCallback* callback, bool* completed) {
+bool File::Write(base::span<const uint8_t> buffer,
+                 size_t offset,
+                 FileIOCallback* callback,
+                 bool* completed) {
   DCHECK(base_file_.IsValid());
   if (!callback) {
     if (completed)
       *completed = true;
-    return Write(buffer, buffer_len, offset);
+    return Write(buffer, offset);
   }
 
-  return AsyncWrite(buffer, buffer_len, offset, callback, completed);
+  if (offset > ULONG_MAX) {
+    return false;
+  }
+
+  GetFileInFlightIO()->PostWrite(
+      this,
+      // SAFETY: Converting `base::span<const uint8_t>` to `base::span<uint8_t>`
+      // does not involve any other changes.
+      UNSAFE_BUFFERS(
+          base::span(const_cast<uint8_t*>(buffer.data()), buffer.size())),
+      offset, callback);
+  if (completed) {
+    *completed = false;
+  }
+  return true;
 }
 
 bool File::SetLength(size_t length) {
@@ -300,17 +330,4 @@
   return base_file_.GetPlatformFile();
 }
 
-bool File::AsyncWrite(const void* buffer, size_t buffer_len, size_t offset,
-                      FileIOCallback* callback, bool* completed) {
-  DCHECK(base_file_.IsValid());
-  if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
-    return false;
-
-  GetFileInFlightIO()->PostWrite(this, buffer, buffer_len, offset, callback);
-
-  if (completed)
-    *completed = false;
-  return true;
-}
-
 }  // namespace disk_cache
diff --git a/net/disk_cache/blockfile/file_posix.cc b/net/disk_cache/blockfile/file_posix.cc
index 660138b..d272ee1 100644
--- a/net/disk_cache/blockfile/file_posix.cc
+++ b/net/disk_cache/blockfile/file_posix.cc
@@ -13,6 +13,7 @@
 #include "base/compiler_specific.h"
 #include "base/functional/bind.h"
 #include "base/location.h"
+#include "base/numerics/checked_math.h"
 #include "base/run_loop.h"
 #include "base/task/thread_pool.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
@@ -38,65 +39,67 @@
   return base_file_.IsValid();
 }
 
-bool File::Read(void* buffer, size_t buffer_len, size_t offset) {
+bool File::Read(base::span<uint8_t> buffer, size_t offset) {
   DCHECK(base_file_.IsValid());
-  if (buffer_len > static_cast<size_t>(std::numeric_limits<int32_t>::max()) ||
-      offset > static_cast<size_t>(std::numeric_limits<int32_t>::max())) {
+  if (!base::IsValueInRangeForNumericType<int32_t>(buffer.size()) ||
+      !base::IsValueInRangeForNumericType<int32_t>(offset)) {
     return false;
   }
 
-  int ret = UNSAFE_TODO(
-      base_file_.Read(offset, static_cast<char*>(buffer), buffer_len));
-  return (static_cast<size_t>(ret) == buffer_len);
+  std::optional<size_t> ret = base_file_.Read(offset, buffer);
+  return ret == buffer.size();
 }
 
-bool File::Write(const void* buffer, size_t buffer_len, size_t offset) {
+bool File::Write(base::span<const uint8_t> buffer, size_t offset) {
   DCHECK(base_file_.IsValid());
-  if (buffer_len > static_cast<size_t>(std::numeric_limits<int32_t>::max()) ||
-      offset > static_cast<size_t>(std::numeric_limits<int32_t>::max())) {
+  if (!base::IsValueInRangeForNumericType<int32_t>(buffer.size()) ||
+      !base::IsValueInRangeForNumericType<int32_t>(offset)) {
     return false;
   }
 
-  int ret = UNSAFE_TODO(
-      base_file_.Write(offset, static_cast<const char*>(buffer), buffer_len));
-  return (static_cast<size_t>(ret) == buffer_len);
+  std::optional<size_t> ret = base_file_.Write(offset, buffer);
+  return ret == buffer.size();
 }
 
-bool File::Read(void* buffer, size_t buffer_len, size_t offset,
-                FileIOCallback* callback, bool* completed) {
+bool File::Read(base::span<uint8_t> buffer,
+                size_t offset,
+                FileIOCallback* callback,
+                bool* completed) {
   DCHECK(base_file_.IsValid());
   if (!callback) {
     if (completed)
       *completed = true;
-    return Read(buffer, buffer_len, offset);
+    return Read(buffer, offset);
   }
 
-  if (buffer_len > static_cast<size_t>(std::numeric_limits<int32_t>::max()) ||
-      offset > static_cast<size_t>(std::numeric_limits<int32_t>::max())) {
+  if (!base::IsValueInRangeForNumericType<int32_t>(buffer.size()) ||
+      !base::IsValueInRangeForNumericType<int32_t>(offset)) {
     return false;
   }
 
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE, {base::TaskPriority::USER_BLOCKING, base::MayBlock()},
-      base::BindOnce(&File::DoRead, base::Unretained(this), buffer, buffer_len,
-                     offset),
+      base::BindOnce(&File::DoRead, base::Unretained(this), buffer, offset),
       base::BindOnce(&File::OnOperationComplete, this, callback));
 
   *completed = false;
   return true;
 }
 
-bool File::Write(const void* buffer, size_t buffer_len, size_t offset,
-                 FileIOCallback* callback, bool* completed) {
+bool File::Write(base::span<const uint8_t> buffer,
+                 size_t offset,
+                 FileIOCallback* callback,
+                 bool* completed) {
   DCHECK(base_file_.IsValid());
   if (!callback) {
-    if (completed)
+    if (completed) {
       *completed = true;
-    return Write(buffer, buffer_len, offset);
+    }
+    return Write(buffer, offset);
   }
 
-  if (buffer_len > static_cast<size_t>(std::numeric_limits<int32_t>::max()) ||
-      offset > static_cast<size_t>(std::numeric_limits<int32_t>::max())) {
+  if (!base::IsValueInRangeForNumericType<int32_t>(buffer.size()) ||
+      !base::IsValueInRangeForNumericType<int32_t>(offset)) {
     return false;
   }
 
@@ -106,8 +109,7 @@
   // requests and changing the priority to BACKGROUND.
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE, {base::TaskPriority::USER_BLOCKING, base::MayBlock()},
-      base::BindOnce(&File::DoWrite, base::Unretained(this), buffer, buffer_len,
-                     offset),
+      base::BindOnce(&File::DoWrite, base::Unretained(this), buffer, offset),
       base::BindOnce(&File::OnOperationComplete, this, callback));
 
   *completed = false;
@@ -155,17 +157,19 @@
 }
 
 // Runs on a worker thread.
-int File::DoRead(void* buffer, size_t buffer_len, size_t offset) {
-  if (Read(const_cast<void*>(buffer), buffer_len, offset))
-    return static_cast<int>(buffer_len);
+int File::DoRead(base::raw_span<uint8_t> buffer, size_t offset) {
+  if (Read(buffer, offset)) {
+    return static_cast<int>(buffer.size());
+  }
 
   return net::ERR_CACHE_READ_FAILURE;
 }
 
 // Runs on a worker thread.
-int File::DoWrite(const void* buffer, size_t buffer_len, size_t offset) {
-  if (Write(const_cast<void*>(buffer), buffer_len, offset))
-    return static_cast<int>(buffer_len);
+int File::DoWrite(base::raw_span<const uint8_t> buffer, size_t offset) {
+  if (Write(buffer, offset)) {
+    return static_cast<int>(buffer.size());
+  }
 
   return net::ERR_CACHE_WRITE_FAILURE;
 }
diff --git a/net/disk_cache/blockfile/file_win.cc b/net/disk_cache/blockfile/file_win.cc
index 1698359..4c18f92 100644
--- a/net/disk_cache/blockfile/file_win.cc
+++ b/net/disk_cache/blockfile/file_win.cc
@@ -138,46 +138,49 @@
   return base_file_.IsValid() || sync_base_file_.IsValid();
 }
 
-bool File::Read(void* buffer, size_t buffer_len, size_t offset) {
+bool File::Read(base::span<uint8_t> buffer, size_t offset) {
   DCHECK(init_);
-  if (buffer_len > ULONG_MAX || offset > LONG_MAX)
+  if (buffer.size() > ULONG_MAX || offset > LONG_MAX) {
     return false;
+  }
 
-  int ret = UNSAFE_TODO(
-      sync_base_file_.Read(offset, static_cast<char*>(buffer), buffer_len));
-  return static_cast<int>(buffer_len) == ret;
+  std::optional<size_t> ret = sync_base_file_.Read(offset, buffer);
+  return ret == buffer.size();
 }
 
-bool File::Write(const void* buffer, size_t buffer_len, size_t offset) {
+bool File::Write(base::span<const uint8_t> buffer, size_t offset) {
   DCHECK(init_);
-  if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
+  if (buffer.size() > ULONG_MAX || offset > ULONG_MAX) {
     return false;
+  }
 
-  int ret = UNSAFE_TODO(sync_base_file_.Write(
-      offset, static_cast<const char*>(buffer), buffer_len));
-  return static_cast<int>(buffer_len) == ret;
+  std::optional<size_t> ret = sync_base_file_.Write(offset, buffer);
+  return ret == buffer.size();
 }
 
 // We have to increase the ref counter of the file before performing the IO to
 // prevent the completion to happen with an invalid handle (if the file is
 // closed while the IO is in flight).
-bool File::Read(void* buffer, size_t buffer_len, size_t offset,
-                FileIOCallback* callback, bool* completed) {
+bool File::Read(base::span<uint8_t> buffer,
+                size_t offset,
+                FileIOCallback* callback,
+                bool* completed) {
   DCHECK(init_);
   if (!callback) {
     if (completed)
       *completed = true;
-    return Read(buffer, buffer_len, offset);
+    return Read(buffer, offset);
   }
 
-  if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
+  if (buffer.size() > ULONG_MAX || offset > ULONG_MAX) {
     return false;
+  }
 
   MyOverlapped* data = new MyOverlapped(this, offset, callback);
-  DWORD size = static_cast<DWORD>(buffer_len);
+  DWORD size = static_cast<DWORD>(buffer.size());
 
   DWORD actual;
-  if (!ReadFile(base_file_.GetPlatformFile(), buffer, size, &actual,
+  if (!ReadFile(base_file_.GetPlatformFile(), buffer.data(), size, &actual,
                 data->overlapped())) {
     *completed = false;
     if (GetLastError() == ERROR_IO_PENDING)
@@ -194,16 +197,18 @@
   return *completed;
 }
 
-bool File::Write(const void* buffer, size_t buffer_len, size_t offset,
-                 FileIOCallback* callback, bool* completed) {
+bool File::Write(base::span<const uint8_t> buffer,
+                 size_t offset,
+                 FileIOCallback* callback,
+                 bool* completed) {
   DCHECK(init_);
   if (!callback) {
     if (completed)
       *completed = true;
-    return Write(buffer, buffer_len, offset);
+    return Write(buffer, offset);
   }
 
-  return AsyncWrite(buffer, buffer_len, offset, callback, completed);
+  return AsyncWrite(buffer, offset, callback, completed);
 }
 
 File::~File() = default;
@@ -214,19 +219,22 @@
                                 sync_base_file_.GetPlatformFile();
 }
 
-bool File::AsyncWrite(const void* buffer, size_t buffer_len, size_t offset,
-                      FileIOCallback* callback, bool* completed) {
+bool File::AsyncWrite(base::span<const uint8_t> buffer,
+                      size_t offset,
+                      FileIOCallback* callback,
+                      bool* completed) {
   DCHECK(init_);
   DCHECK(callback);
   DCHECK(completed);
-  if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
+  if (buffer.size() > ULONG_MAX || offset > ULONG_MAX) {
     return false;
+  }
 
   MyOverlapped* data = new MyOverlapped(this, offset, callback);
-  DWORD size = static_cast<DWORD>(buffer_len);
+  DWORD size = static_cast<DWORD>(buffer.size());
 
   DWORD actual;
-  if (!WriteFile(base_file_.GetPlatformFile(), buffer, size, &actual,
+  if (!WriteFile(base_file_.GetPlatformFile(), buffer.data(), size, &actual,
                  data->overlapped())) {
     *completed = false;
     if (GetLastError() == ERROR_IO_PENDING)
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc
index dce9fa0..c51de4d 100644
--- a/net/disk_cache/entry_unittest.cc
+++ b/net/disk_cache/entry_unittest.cc
@@ -5518,6 +5518,35 @@
   SparseReadLength0();
 }
 
+TEST_F(DiskCacheEntryTest, BlockFileKeyLenCalc) {
+  constexpr int kFirstBlockPortion =
+      sizeof(disk_cache::EntryStore) - offsetof(disk_cache::EntryStore, key);
+  constexpr int kOtherBlocksPortion = sizeof(disk_cache::EntryStore);
+  EXPECT_EQ(1,
+            disk_cache::EntryImpl::NumBlocksForEntry(kFirstBlockPortion - 1));
+  // This needs 2 blocks for terminating nul. This pattern continues on below.
+  EXPECT_EQ(2, disk_cache::EntryImpl::NumBlocksForEntry(kFirstBlockPortion));
+
+  EXPECT_EQ(2, disk_cache::EntryImpl::NumBlocksForEntry(
+                   kFirstBlockPortion + kOtherBlocksPortion - 1));
+  EXPECT_EQ(3, disk_cache::EntryImpl::NumBlocksForEntry(kFirstBlockPortion +
+                                                        kOtherBlocksPortion));
+
+  EXPECT_EQ(3, disk_cache::EntryImpl::NumBlocksForEntry(
+                   kFirstBlockPortion + 2 * kOtherBlocksPortion - 1));
+  EXPECT_EQ(4, disk_cache::EntryImpl::NumBlocksForEntry(
+                   kFirstBlockPortion + 2 * kOtherBlocksPortion));
+
+  EXPECT_EQ(4, disk_cache::EntryImpl::NumBlocksForEntry(
+                   kFirstBlockPortion + 3 * kOtherBlocksPortion - 1));
+
+  // And this now requires an external block.
+  EXPECT_EQ(1, disk_cache::EntryImpl::NumBlocksForEntry(
+                   kFirstBlockPortion + 3 * kOtherBlocksPortion));
+  EXPECT_EQ(kFirstBlockPortion + 3 * kOtherBlocksPortion,
+            disk_cache::kMaxInternalKeyLength + 1);
+}
+
 class DiskCacheSimplePrefetchTest : public DiskCacheEntryTest {
  public:
   DiskCacheSimplePrefetchTest() = default;
diff --git a/pdf/pdf_features.cc b/pdf/pdf_features.cc
index 7c534b6..655719c0 100644
--- a/pdf/pdf_features.cc
+++ b/pdf/pdf_features.cc
@@ -45,6 +45,7 @@
              "PdfSaveOriginalFromMemory",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// TODO(crbug.com/419436546): Deprecated, remove.
 BASE_FEATURE(kPdfSearchify, "PdfSearchify", base::FEATURE_ENABLED_BY_DEFAULT);
 
 BASE_FEATURE(kPdfSearchifySave,
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 19f5c95..5692c6c 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -4348,8 +4348,7 @@
 void PDFiumEngine::StartSearchify(
     GetOcrMaxImageDimensionCallbackAsync get_max_dimension,
     PerformOcrCallbackAsync perform_ocr_callback) {
-  if (!base::FeatureList::IsEnabled(chrome_pdf::features::kPdfSearchify) ||
-      !base::FeatureList::IsEnabled(ax::mojom::features::kScreenAIOCREnabled)) {
+  if (!base::FeatureList::IsEnabled(ax::mojom::features::kScreenAIOCREnabled)) {
     return;
   }
   // Searchify requests may be sent to the engine when PDF pages are loaded and
@@ -4403,8 +4402,7 @@
     return;
   }
 
-  if (!base::FeatureList::IsEnabled(chrome_pdf::features::kPdfSearchify) ||
-      !base::FeatureList::IsEnabled(ax::mojom::features::kScreenAIOCREnabled)) {
+  if (!base::FeatureList::IsEnabled(ax::mojom::features::kScreenAIOCREnabled)) {
     return;
   }
 
diff --git a/pdf/pdfium/pdfium_font_helpers.cc b/pdf/pdfium/pdfium_font_helpers.cc
index afdaffb..c381d41 100644
--- a/pdf/pdfium/pdfium_font_helpers.cc
+++ b/pdf/pdfium/pdfium_font_helpers.cc
@@ -2,15 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
-#pragma allow_unsafe_libc_calls
-#endif
-
 #include "pdf/pdfium/pdfium_font_helpers.h"
 
 #include <algorithm>
 #include <optional>
+#include <string_view>
 
 #include "base/i18n/encoding_detection.h"
 #include "base/i18n/icu_string_conversions.h"
@@ -23,6 +19,49 @@
 
 namespace {
 
+struct PdfFontSubstitution {
+  std::string_view pdf_name;
+  std::string_view face;
+  bool bold;
+  bool italic;
+};
+
+constexpr PdfFontSubstitution kPdfFontSubstitutions[] = {
+    {"Courier", "Courier New", false, false},
+    {"Courier-Bold", "Courier New", true, false},
+    {"Courier-BoldOblique", "Courier New", true, true},
+    {"Courier-Oblique", "Courier New", false, true},
+    {"Helvetica", "Arial", false, false},
+    {"Helvetica-Bold", "Arial", true, false},
+    {"Helvetica-BoldOblique", "Arial", true, true},
+    {"Helvetica-Oblique", "Arial", false, true},
+    {"Times-Roman", "Times New Roman", false, false},
+    {"Times-Bold", "Times New Roman", true, false},
+    {"Times-BoldItalic", "Times New Roman", true, true},
+    {"Times-Italic", "Times New Roman", false, true},
+
+    // MS P?(Mincho|Gothic) are the most notable fonts in Japanese PDF files
+    // without embedding the glyphs. Sometimes the font names are encoded
+    // in Japanese Windows's locale (CP932/Shift_JIS) without space.
+    // Most Linux systems don't have the exact font, but for outsourcing
+    // fontconfig to find substitutable font in the system, we pass ASCII
+    // font names to it.
+    {"MS-PGothic", "MS PGothic", false, false},
+    {"MS-Gothic", "MS Gothic", false, false},
+    {"MS-PMincho", "MS PMincho", false, false},
+    {"MS-Mincho", "MS Mincho", false, false},
+    // MS PGothic in Shift_JIS encoding.
+    {"\x82\x6C\x82\x72\x82\x6F\x83\x53\x83\x56\x83\x62\x83\x4E", "MS PGothic",
+     false, false},
+    // MS Gothic in Shift_JIS encoding.
+    {"\x82\x6C\x82\x72\x83\x53\x83\x56\x83\x62\x83\x4E", "MS Gothic", false,
+     false},
+    // MS PMincho in Shift_JIS encoding.
+    {"\x82\x6C\x82\x72\x82\x6F\x96\xBE\x92\xA9", "MS PMincho", false, false},
+    // MS Mincho in Shift_JIS encoding.
+    {"\x82\x6C\x82\x72\x96\xBE\x92\xA9", "MS Mincho", false, false},
+};
+
 blink::WebFontDescription::Weight WeightToBlinkWeight(int weight) {
   static_assert(blink::WebFontDescription::kWeight100 == 0, "Blink Weight min");
   static_assert(blink::WebFontDescription::kWeight900 == 8, "Blink Weight max");
@@ -43,7 +82,8 @@
     const char* face) {
   // Pretend the system does not have the Symbol font to force a fallback to
   // the built in Symbol font in CFX_FontMapper::FindSubstFont().
-  if (strcmp(face, "Symbol") == 0) {
+  static constexpr std::string_view kSymbol("Symbol");
+  if (face == kSymbol) {
     return std::nullopt;
   }
 
@@ -56,51 +96,10 @@
     desc.generic_family = blink::WebFontDescription::kGenericFamilyStandard;
   }
 
-  static constexpr struct {
-    const char* pdf_name;
-    const char* face;
-    bool bold;
-    bool italic;
-  } kPdfFontSubstitutions[] = {
-      {"Courier", "Courier New", false, false},
-      {"Courier-Bold", "Courier New", true, false},
-      {"Courier-BoldOblique", "Courier New", true, true},
-      {"Courier-Oblique", "Courier New", false, true},
-      {"Helvetica", "Arial", false, false},
-      {"Helvetica-Bold", "Arial", true, false},
-      {"Helvetica-BoldOblique", "Arial", true, true},
-      {"Helvetica-Oblique", "Arial", false, true},
-      {"Times-Roman", "Times New Roman", false, false},
-      {"Times-Bold", "Times New Roman", true, false},
-      {"Times-BoldItalic", "Times New Roman", true, true},
-      {"Times-Italic", "Times New Roman", false, true},
-
-      // MS P?(Mincho|Gothic) are the most notable fonts in Japanese PDF files
-      // without embedding the glyphs. Sometimes the font names are encoded
-      // in Japanese Windows's locale (CP932/Shift_JIS) without space.
-      // Most Linux systems don't have the exact font, but for outsourcing
-      // fontconfig to find substitutable font in the system, we pass ASCII
-      // font names to it.
-      {"MS-PGothic", "MS PGothic", false, false},
-      {"MS-Gothic", "MS Gothic", false, false},
-      {"MS-PMincho", "MS PMincho", false, false},
-      {"MS-Mincho", "MS Mincho", false, false},
-      // MS PGothic in Shift_JIS encoding.
-      {"\x82\x6C\x82\x72\x82\x6F\x83\x53\x83\x56\x83\x62\x83\x4E", "MS PGothic",
-       false, false},
-      // MS Gothic in Shift_JIS encoding.
-      {"\x82\x6C\x82\x72\x83\x53\x83\x56\x83\x62\x83\x4E", "MS Gothic", false,
-       false},
-      // MS PMincho in Shift_JIS encoding.
-      {"\x82\x6C\x82\x72\x82\x6F\x96\xBE\x92\xA9", "MS PMincho", false, false},
-      // MS Mincho in Shift_JIS encoding.
-      {"\x82\x6C\x82\x72\x96\xBE\x92\xA9", "MS Mincho", false, false},
-  };
-
   // Map from the standard PDF fonts to TrueType font names.
   bool found_substitution = false;
   for (const auto& substitution : kPdfFontSubstitutions) {
-    if (strcmp(face, substitution.pdf_name) == 0) {
+    if (face == substitution.pdf_name) {
       desc.family = blink::WebString::FromUTF8(substitution.face);
       if (substitution.bold) {
         desc.weight = blink::WebFontDescription::kWeightBold;
diff --git a/pdf/pdfium/pdfium_ocr.cc b/pdf/pdfium/pdfium_ocr.cc
index 34a3ca3..a0310e12d 100644
--- a/pdf/pdfium/pdfium_ocr.cc
+++ b/pdf/pdfium/pdfium_ocr.cc
@@ -39,8 +39,7 @@
 SkBitmap GetImageForOcr(FPDF_DOCUMENT doc,
                         FPDF_PAGE page,
                         FPDF_PAGEOBJECT page_object,
-                        uint32_t max_image_dimension,
-                        bool rotate_image_to_upright) {
+                        uint32_t max_image_dimension) {
   SkBitmap bitmap;
 
   if (FPDFPageObj_GetType(page_object) != FPDF_PAGEOBJ_IMAGE) {
@@ -86,37 +85,13 @@
     effective_height = pixel_height;
   }
 
-  if (rotate_image_to_upright) {
-    // Scale the matrix to get image with highest resolution and keep the
-    // rotation. If image is stretched differently in horizontal and vertical
-    // directions, the one with no enlargement of the original height and width
-    // is selected.
-    float width_scale = hypotf(original_matrix.a, original_matrix.c);
-    float height_scale = hypotf(original_matrix.b, original_matrix.d);
-    if (width_scale == 0 || height_scale == 0) {
-      return bitmap;
-    }
-    float ratio = std::min(effective_width / width_scale,
-                           effective_height / height_scale);
-    const FS_MATRIX new_matrix = {
-        original_matrix.a * ratio, original_matrix.b * ratio,
-        original_matrix.c * ratio, original_matrix.d * ratio,
-        original_matrix.e,         original_matrix.f};
+  // Scale the image to the highest (capped) resolution while keeping its
+  // rotation as it is.
+  const FS_MATRIX new_matrix = {effective_width, 0, 0, effective_height, 0, 0};
 
-    if (!FPDFPageObj_SetMatrix(page_object, &new_matrix)) {
-      DLOG(ERROR) << "Failed to set new matrix on image";
-      return bitmap;
-    }
-  } else {
-    // Scale the image to the highest (capped) resolution, but do not rotate the
-    // image to make it upright.
-    const FS_MATRIX new_matrix = {effective_width,  0, 0,
-                                  effective_height, 0, 0};
-
-    if (!FPDFPageObj_SetMatrix(page_object, &new_matrix)) {
-      DLOG(ERROR) << "Failed to set new matrix on image";
-      return bitmap;
-    }
+  if (!FPDFPageObj_SetMatrix(page_object, &new_matrix)) {
+    DLOG(ERROR) << "Failed to set new matrix on image";
+    return bitmap;
   }
 
   ScopedFPDFBitmap raw_bitmap(
diff --git a/pdf/pdfium/pdfium_ocr.h b/pdf/pdfium/pdfium_ocr.h
index 17c2536..04e2123 100644
--- a/pdf/pdfium/pdfium_ocr.h
+++ b/pdf/pdfium/pdfium_ocr.h
@@ -11,14 +11,10 @@
 
 namespace chrome_pdf {
 
-// TODO(crbug.com/c/360803943): Remove `rotate_image_to_upright` when PDF OCR
-// support is removed and set the default behavior to
-// rotate_image_to_upright = false.
 SkBitmap GetImageForOcr(FPDF_DOCUMENT doc,
                         FPDF_PAGE page,
                         FPDF_PAGEOBJECT page_object,
-                        uint32_t max_image_dimension,
-                        bool rotate_image_to_upright);
+                        uint32_t max_image_dimension);
 
 // Returns image bound's size in page coordinates. Returns (0,0) if fails.
 gfx::SizeF GetImageSize(FPDF_PAGEOBJECT page_object);
diff --git a/pdf/pdfium/pdfium_on_demand_searchifier_unittest.cc b/pdf/pdfium/pdfium_on_demand_searchifier_unittest.cc
index 1764938..4d818cc 100644
--- a/pdf/pdfium/pdfium_on_demand_searchifier_unittest.cc
+++ b/pdf/pdfium/pdfium_on_demand_searchifier_unittest.cc
@@ -16,11 +16,9 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/test/test_future.h"
 #include "base/time/time.h"
 #include "pdf/accessibility_structs.h"
-#include "pdf/pdf_features.h"
 #include "pdf/pdfium/pdfium_print.h"
 #include "pdf/pdfium/pdfium_range.h"
 #include "pdf/pdfium/pdfium_test_base.h"
@@ -126,11 +124,6 @@
 
 class PDFiumOnDemandSearchifierTest : public PDFiumTestBase {
  public:
-  PDFiumOnDemandSearchifierTest() {
-    scoped_feature_list_.InitAndEnableFeature(
-        chrome_pdf::features::kPdfSearchify);
-  }
-
   void CreateEngine(const base::FilePath::CharType* test_filename) {
     engine_ = InitializeEngine(&client_, test_filename);
     ASSERT_TRUE(engine_) << test_filename;
@@ -221,7 +214,6 @@
   }
 
  private:
-  base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<PDFiumEngine> engine_;
   SearchifierTestClient client_;
   int performed_ocrs_ = 0;
diff --git a/pdf/pdfium/pdfium_page.cc b/pdf/pdfium/pdfium_page.cc
index 01ddaf5..bacd323 100644
--- a/pdf/pdfium/pdfium_page.cc
+++ b/pdf/pdfium/pdfium_page.cc
@@ -53,7 +53,6 @@
 
 #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
 #include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/skbitmap_operations.h"
 #endif
 
 using printing::ConvertUnitFloat;
@@ -951,31 +950,8 @@
                                     int max_image_dimension) {
   FPDF_PAGE page = GetPage();
   FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, page_object_index);
-  bool rotate_image_to_upright =
-      !base::FeatureList::IsEnabled(chrome_pdf::features::kPdfSearchify);
-  SkBitmap bitmap = ::chrome_pdf::GetImageForOcr(
-      engine_->doc(), page, page_object, max_image_dimension,
-      rotate_image_to_upright);
-
-  if (!rotate_image_to_upright) {
-    return bitmap;
-  }
-  SkBitmapOperations::RotationAmount rotation;
-  switch (FPDFPage_GetRotation(page)) {
-    case 0:
-      return bitmap;
-    case 1:
-      rotation = SkBitmapOperations::RotationAmount::ROTATION_90_CW;
-      break;
-    case 2:
-      rotation = SkBitmapOperations::RotationAmount::ROTATION_180_CW;
-      break;
-    case 3:
-      rotation = SkBitmapOperations::RotationAmount::ROTATION_270_CW;
-      break;
-  }
-
-  return SkBitmapOperations::Rotate(bitmap, rotation);
+  return ::chrome_pdf::GetImageForOcr(engine_->doc(), page, page_object,
+                                      max_image_dimension);
 }
 
 void PDFiumPage::OnSearchifyGotOcrResult(bool added_text) {
diff --git a/pdf/pdfium/pdfium_page_unittest.cc b/pdf/pdfium/pdfium_page_unittest.cc
index bdc1187..134e984 100644
--- a/pdf/pdfium/pdfium_page_unittest.cc
+++ b/pdf/pdfium/pdfium_page_unittest.cc
@@ -17,7 +17,6 @@
 #include "build/build_config.h"
 #include "pdf/accessibility_structs.h"
 #include "pdf/buildflags.h"
-#include "pdf/pdf_features.h"
 #include "pdf/pdfium/pdfium_engine.h"
 #include "pdf/pdfium/pdfium_test_base.h"
 #include "pdf/test/test_client.h"
@@ -628,17 +627,9 @@
   SkBitmap image_bitmap = engine->GetImageForOcr(
       /*page_index=*/0, page.images_[0].page_object_index);
 
-  if (base::FeatureList::IsEnabled(chrome_pdf::features::kPdfSearchify)) {
-    // When PDF Searchify is enabled, page rotation does not affect the images
-    // that are sent to OCR.
-    EXPECT_EQ(image_bitmap.width(), 100);
-    EXPECT_EQ(image_bitmap.height(), 25);
-  } else {
-    // This page is rotated, therefore the extracted image size is 25x100 while
-    // the stored image is 100x25.
-    EXPECT_EQ(image_bitmap.width(), 25);
-    EXPECT_EQ(image_bitmap.height(), 100);
-  }
+  // Page rotation does not affect the images that are sent to OCR.
+  EXPECT_EQ(image_bitmap.width(), 100);
+  EXPECT_EQ(image_bitmap.height(), 25);
 }
 
 TEST_P(PDFiumPageImageForOcrTest, NonImage) {
diff --git a/pdf/pdfium/pdfium_range.cc b/pdf/pdfium/pdfium_range.cc
index c4e3e616..6d7381f 100644
--- a/pdf/pdfium/pdfium_range.cc
+++ b/pdf/pdfium/pdfium_range.cc
@@ -8,7 +8,6 @@
 
 #include "base/check_op.h"
 #include "base/containers/span.h"
-#include "base/feature_list.h"
 #include "base/strings/string_util.h"
 #include "pdf/accessibility_structs.h"
 #include "pdf/pdfium/pdfium_api_string_buffer_adapter.h"
@@ -21,12 +20,6 @@
 
 namespace {
 
-// Enables AccessibilityTextRunInfo-based screen rects.
-// TODO(crbug.com/40448046): Remove this kill switch after a safe rollout.
-BASE_FEATURE(kPdfAccessibilityTextRunInfoScreenRects,
-             "PdfAccessibilityTextRunInfoScreenRects",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 void AdjustForBackwardsRange(int& index, int& count) {
   if (count < 0) {
     count *= -1;
@@ -195,25 +188,6 @@
   DCHECK_LT(char_index, FPDFText_CountChars(text_page))
       << " start: " << char_index_ << " count: " << char_count_;
 
-  if (!base::FeatureList::IsEnabled(kPdfAccessibilityTextRunInfoScreenRects)) {
-    int count = FPDFText_CountRects(text_page, char_index, char_count);
-    for (int i = 0; i < count; ++i) {
-      double left;
-      double top;
-      double right;
-      double bottom;
-      FPDFText_GetRect(text_page, i, &left, &top, &right, &bottom);
-      gfx::Rect rect = page_->PageToScreen(point, zoom, left, top, right,
-                                           bottom, orientation);
-      if (rect.IsEmpty()) {
-        continue;
-      }
-      cached_screen_rects_.push_back(rect);
-    }
-
-    return cached_screen_rects_;
-  }
-
   std::vector<ScreenRectTextRunInfo> text_runs;
   const int end_char_index = char_index + char_count;
   bool reached_end = false;
diff --git a/pdf/pdfium/pdfium_searchify.cc b/pdf/pdfium/pdfium_searchify.cc
index 8e8119c0..aeb21e2 100644
--- a/pdf/pdfium/pdfium_searchify.cc
+++ b/pdf/pdfium/pdfium_searchify.cc
@@ -286,8 +286,7 @@
       // GetImageForOcr() checks for null `image`.
       FPDF_PAGEOBJECT image = FPDFPage_GetObject(page.get(), object_index);
       SkBitmap bitmap = GetImageForOcr(document.get(), page.get(), image,
-                                       screen_ai::GetMaxDimensionForOCR(),
-                                       /*rotate_image_to_upright=*/false);
+                                       screen_ai::GetMaxDimensionForOCR());
       // The object is not an image or failed to get the bitmap from the image.
       if (bitmap.empty()) {
         continue;
diff --git a/remoting/base/typed_buffer.h b/remoting/base/typed_buffer.h
index 20e55878..a190d21 100644
--- a/remoting/base/typed_buffer.h
+++ b/remoting/base/typed_buffer.h
@@ -6,13 +6,14 @@
 #ifndef REMOTING_BASE_TYPED_BUFFER_H_
 #define REMOTING_BASE_TYPED_BUFFER_H_
 
-#include <assert.h>
 #include <stdint.h>
 
 #include <algorithm>
-#include <memory>
 #include <type_traits>
 
+#include "base/check.h"
+#include "base/containers/heap_array.h"
+
 namespace remoting {
 
 // A scoper for a variable-length structure such as SID, SECURITY_DESCRIPTOR and
@@ -26,9 +27,9 @@
   TypedBuffer() = default;
 
   // Creates an instance of the object allocating a buffer of the given size.
-  constexpr explicit TypedBuffer(uint32_t length) : length_(length) {
-    if (length_ > 0) {
-      buffer_ = std::make_unique<uint8_t[]>(length);
+  constexpr explicit TypedBuffer(uint32_t length) {
+    if (length > 0) {
+      buffer_ = base::HeapArray<uint8_t>::Uninit(length);
     }
   }
 
@@ -45,46 +46,44 @@
   }
 
   // Accessors to get the owned buffer.
-  // operator* and operator-> will assert() if there is no current buffer.
+  // operator* and operator-> are fatal if there is no current buffer.
   T& operator*() {
-    assert(buffer_);
-    return *(reinterpret_cast<T*>(buffer_.get()));
+    CHECK(!buffer_.empty());
+    return *(reinterpret_cast<T*>(buffer_.data()));
   }
   T* operator->() {
-    assert(buffer_);
-    return reinterpret_cast<T*>(buffer_.get());
+    CHECK(!buffer_.empty());
+    return reinterpret_cast<T*>(buffer_.data());
   }
-  T* get() { return buffer_ ? reinterpret_cast<T*>(&buffer_[0]) : nullptr; }
+  T* get() {
+    return buffer_.empty() ? nullptr : reinterpret_cast<T*>(buffer_.data());
+  }
 
   // `const` variants of the above.
   const T& operator*() const {
-    assert(buffer_);
-    return *(reinterpret_cast<const T*>(buffer_.get()));
+    CHECK(!buffer_.empty());
+    return *(reinterpret_cast<const T*>(buffer_.data()));
   }
   const T* operator->() const {
-    assert(buffer_);
-    return reinterpret_cast<const T*>(buffer_.get());
+    CHECK(!buffer_.empty());
+    return reinterpret_cast<const T*>(buffer_.data());
   }
   const T* get() const {
-    return buffer_ ? reinterpret_cast<const T*>(&buffer_[0]) : nullptr;
+    return buffer_.empty() ? nullptr
+                           : reinterpret_cast<const T*>(buffer_.data());
   }
 
-  uint32_t length() const { return length_; }
+  size_t length() const { return buffer_.size(); }
 
-  explicit operator bool() const { return buffer_.operator bool(); }
+  explicit operator bool() const { return !buffer_.empty(); }
 
   // Swap two buffers.
   void Swap(TypedBuffer& other) {
     std::swap(buffer_, other.buffer_);
-    std::swap(length_, other.length_);
   }
 
  private:
-  // Points to the owned buffer.
-  std::unique_ptr<uint8_t[]> buffer_;
-
-  // Length of the owned buffer in bytes.
-  uint32_t length_ = 0;
+  base::HeapArray<uint8_t> buffer_;
 };
 
 }  // namespace remoting
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn
index 6c7b85d3..cfc150f 100644
--- a/remoting/host/BUILD.gn
+++ b/remoting/host/BUILD.gn
@@ -400,8 +400,6 @@
     "host_power_save_blocker.h",
     "host_secret.cc",
     "host_secret.h",
-    "host_status_logger.cc",
-    "host_status_logger.h",
     "host_status_monitor.cc",
     "host_status_monitor.h",
     "host_status_observer.h",
@@ -459,8 +457,6 @@
     "remoting_register_support_host_request.h",
     "resizing_host_observer.cc",
     "resizing_host_observer.h",
-    "server_log_entry_host.cc",
-    "server_log_entry_host.h",
     "session_policies_from_dict.cc",
     "session_policies_from_dict.h",
     "shutdown_watchdog.cc",
@@ -807,7 +803,6 @@
     "host_experiment_session_plugin_unittest.cc",
     "host_extension_session_manager_unittest.cc",
     "host_power_save_blocker_unittest.cc",
-    "host_status_logger_unittest.cc",
     "input_monitor/local_input_monitor_unittest.cc",
     "ipc_desktop_environment_unittest.cc",
     "it2me/it2me_confirmation_dialog_proxy_unittest.cc",
@@ -825,7 +820,6 @@
     "remoting_register_support_host_request_unittest.cc",
     "resizing_host_observer_unittest.cc",
     "resources_unittest.cc",
-    "server_log_entry_host_unittest.cc",
     "session_policies_from_dict_unittest.cc",
     "setup/host_starter_oauth_helper_unittest.cc",
     "setup/me2me_native_messaging_host_unittest.cc",
diff --git a/remoting/host/heartbeat_sender.cc b/remoting/host/heartbeat_sender.cc
index e1a2b7c6..2ef3ad0 100644
--- a/remoting/host/heartbeat_sender.cc
+++ b/remoting/host/heartbeat_sender.cc
@@ -25,7 +25,6 @@
 #include "remoting/base/protobuf_http_request_config.h"
 #include "remoting/base/service_urls.h"
 #include "remoting/host/host_config.h"
-#include "remoting/host/server_log_entry_host.h"
 #include "remoting/signaling/ftl_signal_strategy.h"
 #include "remoting/signaling/signaling_address.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
diff --git a/remoting/host/host_status_logger.cc b/remoting/host/host_status_logger.cc
deleted file mode 100644
index 7ef81e0..0000000
--- a/remoting/host/host_status_logger.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/host/host_status_logger.h"
-
-#include "base/functional/bind.h"
-#include "remoting/base/constants.h"
-#include "remoting/host/host_status_monitor.h"
-#include "remoting/host/server_log_entry_host.h"
-#include "remoting/protocol/transport.h"
-#include "remoting/signaling/server_log_entry.h"
-
-namespace remoting {
-
-HostStatusLogger::HostStatusLogger(scoped_refptr<HostStatusMonitor> monitor,
-                                   LogToServer* log_to_server)
-    : log_to_server_(log_to_server), monitor_(monitor) {
-  DCHECK(log_to_server_);
-  DCHECK(monitor_);
-  monitor_->AddStatusObserver(this);
-}
-
-HostStatusLogger::~HostStatusLogger() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  monitor_->RemoveStatusObserver(this);
-}
-
-void HostStatusLogger::LogSessionStateChange(const std::string& jid,
-                                             bool connected) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  std::unique_ptr<ServerLogEntry> entry(
-      MakeLogEntryForSessionStateChange(connected));
-  AddHostFieldsToLogEntry(entry.get());
-  entry->AddModeField(log_to_server_->mode());
-
-  if (connected && connection_route_type_.count(jid) > 0) {
-    AddConnectionTypeToLogEntry(entry.get(), connection_route_type_[jid]);
-  }
-
-  log_to_server_->Log(*entry.get());
-}
-
-void HostStatusLogger::OnClientConnected(const std::string& jid) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  LogSessionStateChange(jid, true);
-}
-
-void HostStatusLogger::OnClientDisconnected(const std::string& jid) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  LogSessionStateChange(jid, false);
-  connection_route_type_.erase(jid);
-}
-
-void HostStatusLogger::OnClientRouteChange(
-    const std::string& jid,
-    const std::string& channel_name,
-    const protocol::TransportRoute& route) {
-  // Store connection type for the video channel. It is logged later
-  // when client authentication is finished. For WebRTC clients, the
-  // route-change notification is not per-channel, so the channel_name is
-  // empty.
-  if (channel_name.empty() || channel_name == kVideoChannelName) {
-    connection_route_type_[jid] = route.type;
-  }
-}
-
-}  // namespace remoting
diff --git a/remoting/host/host_status_logger.h b/remoting/host/host_status_logger.h
deleted file mode 100644
index 76407bf..0000000
--- a/remoting/host/host_status_logger.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_HOST_HOST_STATUS_LOGGER_H_
-#define REMOTING_HOST_HOST_STATUS_LOGGER_H_
-
-#include <map>
-
-#include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequence_checker.h"
-#include "remoting/host/host_status_observer.h"
-#include "remoting/protocol/transport.h"
-#include "remoting/signaling/log_to_server.h"
-
-namespace remoting {
-
-class HostStatusMonitor;
-
-// HostStatusLogger sends host log entries to a server.
-// The contents of the log entries are described in server_log_entry_host.cc.
-// They do not contain any personally identifiable information.
-class HostStatusLogger : public HostStatusObserver {
- public:
-  HostStatusLogger(scoped_refptr<HostStatusMonitor> monitor,
-                   LogToServer* log_to_server);
-
-  HostStatusLogger(const HostStatusLogger&) = delete;
-  HostStatusLogger& operator=(const HostStatusLogger&) = delete;
-
-  ~HostStatusLogger() override;
-
-  // Logs a session state change. Currently, this is either
-  // connection or disconnection.
-  void LogSessionStateChange(const std::string& jid, bool connected);
-
-  // HostStatusObserver interface.
-  void OnClientConnected(const std::string& jid) override;
-  void OnClientDisconnected(const std::string& jid) override;
-  void OnClientRouteChange(const std::string& jid,
-                           const std::string& channel_name,
-                           const protocol::TransportRoute& route) override;
-
- private:
-  raw_ptr<LogToServer> log_to_server_;
-
-  scoped_refptr<HostStatusMonitor> monitor_;
-
-  // A map from client JID to the route type of that client's connection to
-  // this host.
-  std::map<std::string, protocol::TransportRoute::RouteType>
-      connection_route_type_;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-};
-
-}  // namespace remoting
-
-#endif  // REMOTING_HOST_HOST_STATUS_LOGGER_H_
diff --git a/remoting/host/host_status_logger_unittest.cc b/remoting/host/host_status_logger_unittest.cc
deleted file mode 100644
index fd78047b..0000000
--- a/remoting/host/host_status_logger_unittest.cc
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/host/host_status_logger.h"
-
-#include "base/run_loop.h"
-#include "base/test/task_environment.h"
-#include "remoting/host/host_status_monitor.h"
-#include "remoting/signaling/mock_signal_strategy.h"
-#include "remoting/signaling/xmpp_log_to_server.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
-
-using jingle_xmpp::QName;
-using jingle_xmpp::XmlElement;
-using testing::_;
-using testing::DeleteArg;
-using testing::DoAll;
-using testing::InSequence;
-using testing::Return;
-
-namespace remoting {
-
-namespace {
-
-ACTION_P(QuitRunLoop, run_loop) {
-  run_loop->QuitWhenIdle();
-}
-
-const char kJabberClientNamespace[] = "jabber:client";
-const char kChromotingNamespace[] = "google:remoting";
-const char kTestBotJid[] = "remotingunittest@bot.talk.google.com";
-const char kClientJid1[] = "client@domain.com/1234";
-const char kClientJid2[] = "client@domain.com/5678";
-const char kHostJid[] = "host@domain.com/1234";
-
-bool IsLogEntryForConnection(XmlElement* node, const char* connection_type) {
-  return (node->Name() == QName(kChromotingNamespace, "entry") &&
-          node->Attr(QName(std::string(), "event-name")) == "session-state" &&
-          node->Attr(QName(std::string(), "session-state")) == "connected" &&
-          node->Attr(QName(std::string(), "role")) == "host" &&
-          node->Attr(QName(std::string(), "mode")) == "me2me" &&
-          node->Attr(QName(std::string(), "connection-type")) ==
-              connection_type);
-}
-
-MATCHER_P(IsClientConnected, connection_type, "") {
-  if (arg->Name() != QName(kJabberClientNamespace, "iq")) {
-    return false;
-  }
-  jingle_xmpp::XmlElement* log_stanza = arg->FirstChild()->AsElement();
-  if (log_stanza->Name() != QName(kChromotingNamespace, "log")) {
-    return false;
-  }
-  if (log_stanza->NextChild()) {
-    return false;
-  }
-  jingle_xmpp::XmlElement* log_entry = log_stanza->FirstChild()->AsElement();
-  if (!IsLogEntryForConnection(log_entry, connection_type)) {
-    return false;
-  }
-  if (log_entry->NextChild()) {
-    return false;
-  }
-  return true;
-}
-
-MATCHER_P2(IsTwoClientsConnected, connection_type1, connection_type2, "") {
-  if (arg->Name() != QName(kJabberClientNamespace, "iq")) {
-    return false;
-  }
-  jingle_xmpp::XmlElement* log_stanza = arg->FirstChild()->AsElement();
-  if (log_stanza->Name() != QName(kChromotingNamespace, "log")) {
-    return false;
-  }
-  if (log_stanza->NextChild()) {
-    return false;
-  }
-  jingle_xmpp::XmlElement* log_entry = log_stanza->FirstChild()->AsElement();
-  if (!IsLogEntryForConnection(log_entry, connection_type1)) {
-    return false;
-  }
-  log_entry = log_entry->NextChild()->AsElement();
-  if (!IsLogEntryForConnection(log_entry, connection_type2)) {
-    return false;
-  }
-  if (log_entry->NextChild()) {
-    return false;
-  }
-  return true;
-}
-
-bool IsLogEntryForDisconnection(XmlElement* node) {
-  return (node->Name() == QName(kChromotingNamespace, "entry") &&
-          node->Attr(QName(std::string(), "event-name")) == "session-state" &&
-          node->Attr(QName(std::string(), "session-state")) == "closed" &&
-          node->Attr(QName(std::string(), "role")) == "host" &&
-          node->Attr(QName(std::string(), "mode")) == "me2me");
-}
-
-MATCHER(IsClientDisconnected, "") {
-  if (arg->Name() != QName(kJabberClientNamespace, "iq")) {
-    return false;
-  }
-  jingle_xmpp::XmlElement* log_stanza = arg->FirstChild()->AsElement();
-  if (log_stanza->Name() != QName(kChromotingNamespace, "log")) {
-    return false;
-  }
-  if (log_stanza->NextChild()) {
-    return false;
-  }
-  jingle_xmpp::XmlElement* log_entry = log_stanza->FirstChild()->AsElement();
-  if (!IsLogEntryForDisconnection(log_entry)) {
-    return false;
-  }
-  if (log_entry->NextChild()) {
-    return false;
-  }
-  return true;
-}
-
-}  // namespace
-
-class HostStatusLoggerTest : public testing::Test {
- public:
-  HostStatusLoggerTest()
-      : signal_strategy_(SignalingAddress(kHostJid)),
-        host_status_monitor_(new HostStatusMonitor()) {}
-  void SetUp() override {
-    EXPECT_CALL(signal_strategy_, AddListener(_));
-    log_to_server_ = std::make_unique<XmppLogToServer>(
-        ServerLogEntry::ME2ME, &signal_strategy_, kTestBotJid);
-    host_status_logger_ = std::make_unique<HostStatusLogger>(
-        host_status_monitor_, log_to_server_.get());
-    EXPECT_CALL(signal_strategy_, RemoveListener(_));
-  }
-
- protected:
-  base::test::SingleThreadTaskEnvironment task_environment_;
-  MockSignalStrategy signal_strategy_;
-  std::unique_ptr<XmppLogToServer> log_to_server_;
-  std::unique_ptr<HostStatusLogger> host_status_logger_;
-  scoped_refptr<HostStatusMonitor> host_status_monitor_;
-};
-
-TEST_F(HostStatusLoggerTest, SendNow) {
-  base::RunLoop run_loop;
-  {
-    InSequence s;
-    EXPECT_CALL(signal_strategy_, AddListener(_));
-    EXPECT_CALL(signal_strategy_, GetNextId());
-    EXPECT_CALL(signal_strategy_, SendStanzaPtr(IsClientConnected("direct")))
-        .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-    EXPECT_CALL(signal_strategy_, RemoveListener(_))
-        .WillOnce(QuitRunLoop(&run_loop))
-        .RetiresOnSaturation();
-  }
-  log_to_server_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED);
-  protocol::TransportRoute route;
-  route.type = protocol::TransportRoute::DIRECT;
-  host_status_logger_->OnClientRouteChange(kClientJid1, "video", route);
-  host_status_logger_->OnClientAuthenticated(kClientJid1);
-  host_status_logger_->OnClientConnected(kClientJid1);
-  log_to_server_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED);
-  run_loop.Run();
-}
-
-TEST_F(HostStatusLoggerTest, SendLater) {
-  base::RunLoop run_loop;
-  protocol::TransportRoute route;
-  route.type = protocol::TransportRoute::DIRECT;
-  host_status_logger_->OnClientRouteChange(kClientJid1, "video", route);
-  host_status_logger_->OnClientAuthenticated(kClientJid1);
-  host_status_logger_->OnClientConnected(kClientJid1);
-
-  {
-    InSequence s;
-    EXPECT_CALL(signal_strategy_, AddListener(_));
-    EXPECT_CALL(signal_strategy_, GetNextId());
-    EXPECT_CALL(signal_strategy_, SendStanzaPtr(IsClientConnected("direct")))
-        .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-    EXPECT_CALL(signal_strategy_, RemoveListener(_))
-        .WillOnce(QuitRunLoop(&run_loop))
-        .RetiresOnSaturation();
-  }
-  log_to_server_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED);
-  log_to_server_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED);
-  run_loop.Run();
-}
-
-TEST_F(HostStatusLoggerTest, SendTwoEntriesLater) {
-  base::RunLoop run_loop;
-  protocol::TransportRoute route1;
-  route1.type = protocol::TransportRoute::DIRECT;
-  host_status_logger_->OnClientRouteChange(kClientJid1, "video", route1);
-  host_status_logger_->OnClientAuthenticated(kClientJid1);
-  host_status_logger_->OnClientConnected(kClientJid1);
-  protocol::TransportRoute route2;
-  route2.type = protocol::TransportRoute::STUN;
-  host_status_logger_->OnClientRouteChange(kClientJid2, "video", route2);
-  host_status_logger_->OnClientAuthenticated(kClientJid2);
-  host_status_logger_->OnClientConnected(kClientJid2);
-
-  {
-    InSequence s;
-    EXPECT_CALL(signal_strategy_, AddListener(_));
-    EXPECT_CALL(signal_strategy_, GetNextId());
-    EXPECT_CALL(signal_strategy_,
-                SendStanzaPtr(IsTwoClientsConnected("direct", "stun")))
-        .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-    EXPECT_CALL(signal_strategy_, RemoveListener(_))
-        .WillOnce(QuitRunLoop(&run_loop))
-        .RetiresOnSaturation();
-  }
-  log_to_server_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED);
-  log_to_server_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED);
-  run_loop.Run();
-}
-
-TEST_F(HostStatusLoggerTest, HandleRouteChangeInUnusualOrder) {
-  base::RunLoop run_loop;
-
-  {
-    InSequence s;
-    EXPECT_CALL(signal_strategy_, AddListener(_));
-    EXPECT_CALL(signal_strategy_, GetNextId());
-    EXPECT_CALL(signal_strategy_, SendStanzaPtr(IsClientConnected("direct")))
-        .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-    EXPECT_CALL(signal_strategy_, GetNextId());
-    EXPECT_CALL(signal_strategy_, SendStanzaPtr(IsClientDisconnected()))
-        .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-    EXPECT_CALL(signal_strategy_, GetNextId());
-    EXPECT_CALL(signal_strategy_, SendStanzaPtr(IsClientConnected("stun")))
-        .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-    EXPECT_CALL(signal_strategy_, RemoveListener(_))
-        .WillOnce(QuitRunLoop(&run_loop))
-        .RetiresOnSaturation();
-  }
-  log_to_server_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED);
-  protocol::TransportRoute route1;
-  route1.type = protocol::TransportRoute::DIRECT;
-  host_status_logger_->OnClientRouteChange(kClientJid1, "video", route1);
-  host_status_logger_->OnClientAuthenticated(kClientJid1);
-  host_status_logger_->OnClientConnected(kClientJid1);
-  protocol::TransportRoute route2;
-  route2.type = protocol::TransportRoute::STUN;
-  host_status_logger_->OnClientRouteChange(kClientJid2, "video", route2);
-  host_status_logger_->OnClientDisconnected(kClientJid1);
-  host_status_logger_->OnClientAuthenticated(kClientJid2);
-  host_status_logger_->OnClientConnected(kClientJid2);
-  log_to_server_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED);
-  run_loop.Run();
-}
-
-}  // namespace remoting
diff --git a/remoting/host/it2me/it2me_host.cc b/remoting/host/it2me/it2me_host.cc
index ba4d44c7..bad83dd 100644
--- a/remoting/host/it2me/it2me_host.cc
+++ b/remoting/host/it2me/it2me_host.cc
@@ -46,7 +46,6 @@
 #include "remoting/host/host_event_logger.h"
 #include "remoting/host/host_event_reporter.h"
 #include "remoting/host/host_secret.h"
-#include "remoting/host/host_status_logger.h"
 #include "remoting/host/it2me/it2me_confirmation_dialog.h"
 #include "remoting/host/it2me/it2me_confirmation_dialog_proxy.h"
 #include "remoting/host/it2me/it2me_helpers.h"
@@ -280,10 +279,8 @@
   SetState(It2MeHostState::kStarting, ErrorCode::OK);
 
   auto connection_context = std::move(create_context).Run(host_context_.get());
-  log_to_server_ = std::move(connection_context->log_to_server);
   signal_strategy_ = std::move(connection_context->signal_strategy);
   api_token_getter_ = std::move(connection_context->api_token_getter);
-  DCHECK(log_to_server_);
   DCHECK(signal_strategy_);
 
   if (connection_context->use_ftl_signaling) {
@@ -415,8 +412,6 @@
                           base::Unretained(this)),
       local_session_policies_provider_.get());
   host_->status_monitor()->AddStatusObserver(this);
-  host_status_logger_ = std::make_unique<HostStatusLogger>(
-      host_->status_monitor(), log_to_server_.get());
 
   // Create event logger.
   host_event_logger_ =
@@ -819,8 +814,6 @@
   }
 
   register_request_ = nullptr;
-  host_status_logger_ = nullptr;
-  log_to_server_ = nullptr;
   ftl_signaling_connector_ = nullptr;
   reconnect_params_.reset();
 
diff --git a/remoting/host/it2me/it2me_host.h b/remoting/host/it2me/it2me_host.h
index 8598a1b..7747fed 100644
--- a/remoting/host/it2me/it2me_host.h
+++ b/remoting/host/it2me/it2me_host.h
@@ -38,9 +38,7 @@
 class FtlSignalingConnector;
 class HostEventLogger;
 class HostEventReporter;
-class HostStatusLogger;
 class HostStatusMonitor;
-class LogToServer;
 class OAuthTokenGetter;
 class RegisterSupportHostRequest;
 class RsaKeyPair;
@@ -57,7 +55,6 @@
     DeferredConnectContext();
     ~DeferredConnectContext();
 
-    std::unique_ptr<LogToServer> log_to_server;
     std::unique_ptr<RegisterSupportHostRequest> register_request;
     std::unique_ptr<SignalStrategy> signal_strategy;
 
@@ -247,7 +244,6 @@
   base::WeakPtr<It2MeHost::Observer> observer_;
   std::unique_ptr<SignalStrategy> signal_strategy_;
   std::unique_ptr<FtlSignalingConnector> ftl_signaling_connector_;
-  std::unique_ptr<LogToServer> log_to_server_;
   std::unique_ptr<OAuthTokenGetter> api_token_getter_;
 
   It2MeHostState state_ = It2MeHostState::kDisconnected;
@@ -262,7 +258,6 @@
   std::string ftl_device_id_;
   scoped_refptr<RsaKeyPair> host_key_pair_;
   std::unique_ptr<RegisterSupportHostRequest> register_request_;
-  std::unique_ptr<HostStatusLogger> host_status_logger_;
   std::unique_ptr<DesktopEnvironmentFactory> desktop_environment_factory_;
   std::unique_ptr<HostEventLogger> host_event_logger_;
   std::unique_ptr<LocalSessionPoliciesProvider>
diff --git a/remoting/host/it2me/it2me_host_unittest.cc b/remoting/host/it2me/it2me_host_unittest.cc
index 5634b2ac..b5fdc5b 100644
--- a/remoting/host/it2me/it2me_host_unittest.cc
+++ b/remoting/host/it2me/it2me_host_unittest.cc
@@ -51,8 +51,6 @@
 #include "remoting/protocol/errors.h"
 #include "remoting/protocol/transport_context.h"
 #include "remoting/signaling/fake_signal_strategy.h"
-#include "remoting/signaling/remoting_log_to_server.h"
-#include "remoting/signaling/xmpp_log_to_server.h"
 #include "services/network/test/test_shared_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -443,10 +441,6 @@
         context->use_corp_session_authz = use_corp_session_authz;
         context->register_request =
             std::make_unique<FakeRegisterSupportHostRequest>();
-        context->log_to_server = std::make_unique<RemotingLogToServer>(
-            ServerLogEntry::IT2ME,
-            std::make_unique<OAuthTokenGetterProxy>(token_getter),
-            host_context->url_loader_factory());
         context->signaling_token_getter =
             std::make_unique<OAuthTokenGetterProxy>(token_getter);
         context->api_token_getter =
diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc
index a9f7e41..ab2de565 100644
--- a/remoting/host/it2me/it2me_native_messaging_host.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host.cc
@@ -53,9 +53,6 @@
 #include "remoting/signaling/delegating_signal_strategy.h"
 #include "remoting/signaling/ftl_signal_strategy.h"
 #include "remoting/signaling/ftl_support_host_device_id_provider.h"
-#include "remoting/signaling/remoting_log_to_server.h"
-#include "remoting/signaling/server_log_entry.h"
-#include "remoting/signaling/xmpp_log_to_server.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 #if BUILDFLAG(IS_WIN)
@@ -115,9 +112,6 @@
       std::make_unique<It2MeHost::DeferredConnectContext>();
   connection_context->register_request =
       std::make_unique<XmppRegisterSupportHostRequest>(kDirectoryBotJidValue);
-  connection_context->log_to_server = std::make_unique<XmppLogToServer>(
-      ServerLogEntry::IT2ME, signal_strategy.get(), kDirectoryBotJidValue,
-      context->network_task_runner());
   connection_context->signal_strategy = std::move(signal_strategy);
   return connection_context;
 }
@@ -158,11 +152,6 @@
                 api_token_getter, oauth_token_getter_task_runner),
             host_context->url_loader_factory());
   }
-  connection_context->log_to_server = std::make_unique<RemotingLogToServer>(
-      ServerLogEntry::IT2ME,
-      std::make_unique<OAuthTokenGetterProxy>(api_token_getter,
-                                              oauth_token_getter_task_runner),
-      host_context->url_loader_factory());
   connection_context->signaling_token_getter =
       std::make_unique<OAuthTokenGetterProxy>(signaling_token_getter,
                                               oauth_token_getter_task_runner);
diff --git a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
index dfaaba2..2e69508 100644
--- a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
@@ -46,7 +46,6 @@
 #include "remoting/host/setup/test_util.h"
 #include "remoting/protocol/errors.h"
 #include "remoting/protocol/ice_config.h"
-#include "remoting/signaling/log_to_server.h"
 #include "services/network/test/test_shared_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -213,7 +212,6 @@
     return;
   }
 
-  log_to_server_.reset();
   register_request_.reset();
   signal_strategy_.reset();
   session_policies_finalized_ = false;
@@ -227,7 +225,6 @@
     CreateDeferredConnectContext create_connection_context) {
   DCHECK(host_context()->network_task_runner()->BelongsToCurrentThread());
   auto context = std::move(create_connection_context).Run(host_context());
-  log_to_server_ = std::move(context->log_to_server);
   register_request_ = std::move(context->register_request);
   signal_strategy_ = std::move(context->signal_strategy);
   signaling_token_getter_ = std::move(context->signaling_token_getter);
diff --git a/remoting/host/server_log_entry_host.cc b/remoting/host/server_log_entry_host.cc
deleted file mode 100644
index 8e9fc3ad..0000000
--- a/remoting/host/server_log_entry_host.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/host/server_log_entry_host.h"
-
-#include "base/strings/stringize_macros.h"
-#include "remoting/host/host_details.h"
-#include "remoting/signaling/server_log_entry.h"
-
-namespace remoting {
-
-namespace {
-const char kValueEventNameSessionState[] = "session-state";
-
-const char kValueRoleHost[] = "host";
-
-const char kKeySessionState[] = "session-state";
-const char kValueSessionStateConnected[] = "connected";
-const char kValueSessionStateClosed[] = "closed";
-
-const char kKeyOsName[] = "os-name";
-const char kKeyOsVersion[] = "os-version";
-
-const char kKeyHostVersion[] = "host-version";
-
-const char kKeyConnectionType[] = "connection-type";
-
-const char* GetValueSessionState(bool connected) {
-  return connected ? kValueSessionStateConnected : kValueSessionStateClosed;
-}
-
-}  // namespace
-
-std::unique_ptr<ServerLogEntry> MakeLogEntryForSessionStateChange(
-    bool connected) {
-  std::unique_ptr<ServerLogEntry> entry(new ServerLogEntry());
-  entry->AddRoleField(kValueRoleHost);
-  entry->AddEventNameField(kValueEventNameSessionState);
-  entry->Set(kKeySessionState, GetValueSessionState(connected));
-  return entry;
-}
-
-void AddHostFieldsToLogEntry(ServerLogEntry* entry) {
-  // TODO os name, os version, and version will be in the main message body,
-  // remove these fields at a later date to remove redundancy.
-  entry->Set(kKeyOsName, GetHostOperatingSystemName());
-  entry->Set(kKeyOsVersion, GetHostOperatingSystemVersion());
-  entry->Set(kKeyHostVersion, STRINGIZE(VERSION));
-  entry->AddCpuField();
-}
-
-void AddConnectionTypeToLogEntry(ServerLogEntry* entry,
-                                 protocol::TransportRoute::RouteType type) {
-  entry->Set(kKeyConnectionType, protocol::TransportRoute::GetTypeString(type));
-}
-
-}  // namespace remoting
diff --git a/remoting/host/server_log_entry_host.h b/remoting/host/server_log_entry_host.h
deleted file mode 100644
index 3187b44..0000000
--- a/remoting/host/server_log_entry_host.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_HOST_SERVER_LOG_ENTRY_HOST_H_
-#define REMOTING_HOST_SERVER_LOG_ENTRY_HOST_H_
-
-#include "remoting/protocol/transport.h"
-
-namespace remoting {
-
-class ServerLogEntry;
-
-// Constructs a log entry for a session state change.
-// Currently this is either connection or disconnection.
-std::unique_ptr<ServerLogEntry> MakeLogEntryForSessionStateChange(
-    bool connected);
-
-// Adds fields describing the host to this log entry.
-void AddHostFieldsToLogEntry(ServerLogEntry* entry);
-
-// Adds a field describing connection type (direct/stun/relay).
-void AddConnectionTypeToLogEntry(ServerLogEntry* entry,
-                                 protocol::TransportRoute::RouteType type);
-
-}  // namespace remoting
-
-#endif  // REMOTING_HOST_SERVER_LOG_ENTRY_HOST_H_
diff --git a/remoting/host/server_log_entry_host_unittest.cc b/remoting/host/server_log_entry_host_unittest.cc
deleted file mode 100644
index c64c89a1..0000000
--- a/remoting/host/server_log_entry_host_unittest.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/host/server_log_entry_host.h"
-
-#include <memory>
-
-#include "base/strings/stringize_macros.h"
-#include "build/build_config.h"
-#include "remoting/signaling/server_log_entry.h"
-#include "remoting/signaling/server_log_entry_unittest.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
-
-using jingle_xmpp::XmlAttr;
-using jingle_xmpp::XmlElement;
-
-namespace remoting {
-
-TEST(ServerLogEntryHostTest, MakeForSessionStateChange) {
-  std::unique_ptr<ServerLogEntry> entry(
-      MakeLogEntryForSessionStateChange(true));
-  std::unique_ptr<XmlElement> stanza = entry->ToStanza();
-  std::string error;
-  std::map<std::string, std::string> key_value_pairs;
-  key_value_pairs["role"] = "host";
-  key_value_pairs["event-name"] = "session-state";
-  key_value_pairs["session-state"] = "connected";
-  std::set<std::string> keys;
-  ASSERT_TRUE(VerifyStanza(key_value_pairs, keys, stanza.get(), &error))
-      << error;
-}
-
-TEST(ServerLogEntryHostTest, AddHostFields) {
-  std::unique_ptr<ServerLogEntry> entry(
-      MakeLogEntryForSessionStateChange(true));
-  AddHostFieldsToLogEntry(entry.get());
-  std::unique_ptr<XmlElement> stanza = entry->ToStanza();
-  std::string error;
-  std::map<std::string, std::string> key_value_pairs;
-  key_value_pairs["role"] = "host";
-  key_value_pairs["event-name"] = "session-state";
-  key_value_pairs["session-state"] = "connected";
-  std::set<std::string> keys;
-  keys.insert("cpu");
-#if BUILDFLAG(IS_WIN)
-  key_value_pairs["os-name"] = "Windows";
-  keys.insert("os-version");
-#elif BUILDFLAG(IS_APPLE)
-  key_value_pairs["os-name"] = "Mac";
-  keys.insert("os-version");
-#elif BUILDFLAG(IS_CHROMEOS)
-  key_value_pairs["os-name"] = "ChromeOS";
-  keys.insert("os-version");
-#elif BUILDFLAG(IS_LINUX)
-  key_value_pairs["os-name"] = "Linux";
-  keys.insert("os-version");
-#endif
-
-// The check below will compile but fail if VERSION isn't defined (STRINGIZE
-// silently converts undefined values).
-#ifndef VERSION
-#error VERSION must be defined
-#endif
-  key_value_pairs["host-version"] = STRINGIZE(VERSION);
-  ASSERT_TRUE(VerifyStanza(key_value_pairs, keys, stanza.get(), &error))
-      << error;
-}
-
-TEST(ServerLogEntryHostTest, AddModeField1) {
-  std::unique_ptr<ServerLogEntry> entry(
-      MakeLogEntryForSessionStateChange(true));
-  entry->AddModeField(ServerLogEntry::IT2ME);
-  std::unique_ptr<XmlElement> stanza = entry->ToStanza();
-  std::string error;
-  std::map<std::string, std::string> key_value_pairs;
-  key_value_pairs["role"] = "host";
-  key_value_pairs["event-name"] = "session-state";
-  key_value_pairs["session-state"] = "connected";
-  key_value_pairs["mode"] = "it2me";
-  std::set<std::string> keys;
-  ASSERT_TRUE(VerifyStanza(key_value_pairs, keys, stanza.get(), &error))
-      << error;
-}
-
-TEST(ServerLogEntryHostTest, AddModeField2) {
-  std::unique_ptr<ServerLogEntry> entry(
-      MakeLogEntryForSessionStateChange(true));
-  entry->AddModeField(ServerLogEntry::ME2ME);
-  std::unique_ptr<XmlElement> stanza = entry->ToStanza();
-  std::string error;
-  std::map<std::string, std::string> key_value_pairs;
-  key_value_pairs["role"] = "host";
-  key_value_pairs["event-name"] = "session-state";
-  key_value_pairs["session-state"] = "connected";
-  key_value_pairs["mode"] = "me2me";
-  std::set<std::string> keys;
-  ASSERT_TRUE(VerifyStanza(key_value_pairs, keys, stanza.get(), &error))
-      << error;
-}
-
-}  // namespace remoting
diff --git a/remoting/signaling/BUILD.gn b/remoting/signaling/BUILD.gn
index af7fb6b..451147d 100644
--- a/remoting/signaling/BUILD.gn
+++ b/remoting/signaling/BUILD.gn
@@ -30,10 +30,6 @@
     "message_tracker.h",
     "messaging_client.h",
     "registration_manager.h",
-    "remoting_log_to_server.cc",
-    "remoting_log_to_server.h",
-    "server_log_entry.cc",
-    "server_log_entry.h",
     "signal_strategy.cc",
     "signal_strategy.h",
     "signaling_address.cc",
@@ -43,8 +39,6 @@
     "signaling_tracker.h",
     "xmpp_constants.cc",
     "xmpp_constants.h",
-    "xmpp_log_to_server.cc",
-    "xmpp_log_to_server.h",
   ]
 
   configs += [
@@ -103,12 +97,8 @@
     "ftl_signal_strategy_unittest.cc",
     "iq_sender_unittest.cc",
     "message_tracker_unittest.cc",
-    "remoting_log_to_server_unittest.cc",
-    "server_log_entry_unittest.cc",
-    "server_log_entry_unittest.h",
     "signaling_address_unittest.cc",
     "signaling_id_util_unittest.cc",
-    "xmpp_log_to_server_unittest.cc",
   ]
 
   deps = [
diff --git a/remoting/signaling/log_to_server.h b/remoting/signaling/log_to_server.h
deleted file mode 100644
index 6a0e750..0000000
--- a/remoting/signaling/log_to_server.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_SIGNALING_LOG_TO_SERVER_H_
-#define REMOTING_SIGNALING_LOG_TO_SERVER_H_
-
-#include "remoting/signaling/server_log_entry.h"
-
-namespace remoting {
-
-// LogToServer sends log entries to a server.
-// The contents of the log entries are described in server_log_entry.cc.
-// They do not contain any personally identifiable information.
-class LogToServer {
- public:
-  virtual ~LogToServer() = default;
-
-  virtual void Log(const ServerLogEntry& entry) = 0;
-  virtual ServerLogEntry::Mode mode() const = 0;
-
- protected:
-  LogToServer() = default;
-};
-
-}  // namespace remoting
-
-#endif  // REMOTING_SIGNALING_LOG_TO_SERVER_H_
diff --git a/remoting/signaling/remoting_log_to_server.cc b/remoting/signaling/remoting_log_to_server.cc
deleted file mode 100644
index e9444b9..0000000
--- a/remoting/signaling/remoting_log_to_server.cc
+++ /dev/null
@@ -1,223 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/signaling/remoting_log_to_server.h"
-
-#include <sstream>
-
-#include "base/functional/bind.h"
-#include "base/logging.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "remoting/base/http_status.h"
-#include "remoting/base/protobuf_http_client.h"
-#include "remoting/base/protobuf_http_request.h"
-#include "remoting/base/protobuf_http_request_config.h"
-#include "remoting/base/service_urls.h"
-#include "remoting/proto/remoting/v1/telemetry_messages.pb.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-
-namespace remoting {
-
-namespace {
-
-const net::BackoffEntry::Policy kBackoffPolicy = {
-    // Number of initial errors (in sequence) to ignore before applying
-    // exponential back-off rules.
-    0,
-
-    // Initial delay for exponential back-off in ms.
-    1000,
-
-    // Factor by which the waiting time will be multiplied.
-    2,
-
-    // Fuzzing percentage. ex: 10% will spread requests randomly
-    // between 90%-100% of the calculated time.
-    0.5,
-
-    // Maximum amount of time we are willing to delay our request in ms.
-    60000,
-
-    // Time to keep an entry from being discarded even when it
-    // has no significant state, -1 to never discard.
-    -1,
-
-    // Starts with initial delay.
-    false,
-};
-
-constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
-    net::DefineNetworkTrafficAnnotation("remoting_log_to_server",
-                                        R"(
-        semantics {
-          sender: "Chrome Remote Desktop"
-          description:
-            "Sends telemetry logs for Chrome Remote Desktop."
-          trigger:
-            "These requests are sent periodically when a session is connected, "
-            "i.e. CRD host is running and is connected to a client."
-          user_data {
-            type: OTHER
-          }
-          data:
-            "Anonymous usage statistics, which includes CRD host version, OS "
-            "name, OS version, and CPU architecture (e.g. x86_64)."
-          destination: GOOGLE_OWNED_SERVICE
-          internal {
-            contacts { email: "garykac@chromium.org" }
-            contacts { email: "jamiewalch@chromium.org" }
-            contacts { email: "joedow@chromium.org" }
-            contacts { email: "lambroslambrou@chromium.org" }
-            contacts { email: "rkjnsn@chromium.org" }
-            contacts { email: "yuweih@chromium.org" }
-          }
-          last_reviewed: "2023-07-07"
-        }
-        policy {
-          cookies_allowed: NO
-          setting:
-            "This request cannot be stopped in settings, but will not be sent "
-            "if the user does not use Chrome Remote Desktop."
-          chrome_policy {
-            RemoteAccessHostAllowRemoteSupportConnections {
-              RemoteAccessHostAllowRemoteSupportConnections: false
-            }
-            RemoteAccessHostAllowEnterpriseRemoteSupportConnections {
-              RemoteAccessHostAllowEnterpriseRemoteSupportConnections: false
-            }
-          }
-        })");
-
-constexpr char kCreateLogEntryPath[] = "/v1/telemetry:createlogentry";
-
-using CreateLogEntryResponseCallback =
-    base::OnceCallback<void(const HttpStatus&,
-                            std::unique_ptr<apis::v1::CreateLogEntryResponse>)>;
-
-class TelemetryClient {
- public:
-  TelemetryClient(
-      OAuthTokenGetter* token_getter,
-      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
-
-  TelemetryClient(const TelemetryClient&) = delete;
-  TelemetryClient& operator=(const TelemetryClient&) = delete;
-
-  ~TelemetryClient();
-
-  void CreateLogEntry(const apis::v1::CreateLogEntryRequest& request,
-                      CreateLogEntryResponseCallback callback);
-
- private:
-  ProtobufHttpClient http_client_;
-};
-
-TelemetryClient::TelemetryClient(
-    OAuthTokenGetter* token_getter,
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
-    : http_client_(ServiceUrls::GetInstance()->remoting_server_endpoint(),
-                   token_getter,
-                   url_loader_factory) {}
-
-TelemetryClient::~TelemetryClient() = default;
-
-void TelemetryClient::CreateLogEntry(
-    const apis::v1::CreateLogEntryRequest& request,
-    CreateLogEntryResponseCallback callback) {
-  auto request_config =
-      std::make_unique<ProtobufHttpRequestConfig>(kTrafficAnnotation);
-  request_config->path = kCreateLogEntryPath;
-  request_config->request_message =
-      std::make_unique<apis::v1::CreateLogEntryRequest>(request);
-  auto http_request =
-      std::make_unique<ProtobufHttpRequest>(std::move(request_config));
-  http_request->SetResponseCallback(std::move(callback));
-  http_client_.ExecuteRequest(std::move(http_request));
-}
-
-}  // namespace
-
-RemotingLogToServer::RemotingLogToServer(
-    ServerLogEntry::Mode mode,
-    std::unique_ptr<OAuthTokenGetter> token_getter,
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
-    : mode_(mode),
-      token_getter_(std::move(token_getter)),
-      backoff_(&kBackoffPolicy),
-      create_log_entry_(base::BindRepeating(
-          &TelemetryClient::CreateLogEntry,
-          std::make_unique<TelemetryClient>(token_getter_.get(),
-                                            url_loader_factory))) {}
-
-RemotingLogToServer::~RemotingLogToServer() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-void RemotingLogToServer::Log(const ServerLogEntry& entry) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  apis::v1::CreateLogEntryRequest request;
-  *request.mutable_payload()->mutable_entry() = entry.ToGenericLogEntry();
-  SendLogRequestWithBackoff(request, kMaxSendLogAttempts);
-}
-
-void RemotingLogToServer::SendLogRequest(
-    const apis::v1::CreateLogEntryRequest& request,
-    int attempts_left) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (VLOG_IS_ON(1)) {
-    std::ostringstream log_stream;
-    log_stream << "Sending log entry with " << attempts_left
-               << " attempts left: \n";
-    for (const auto& field : request.payload().entry().field()) {
-      log_stream << field.key() << ": " << field.value() << "\n";
-    }
-    log_stream << "=========================================================";
-    VLOG(1) << log_stream.str();
-  }
-  create_log_entry_.Run(
-      request,
-      base::BindOnce(&RemotingLogToServer::OnSendLogRequestResult,
-                     base::Unretained(this), request, attempts_left - 1));
-}
-
-void RemotingLogToServer::SendLogRequestWithBackoff(
-    const apis::v1::CreateLogEntryRequest& request,
-    int attempts_left) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  auto time_until_release = backoff_.GetTimeUntilRelease();
-  VLOG(1) << "Scheduling request in " << time_until_release
-          << ", attempts left: " << attempts_left;
-  backoff_timer_.Start(
-      FROM_HERE, time_until_release,
-      base::BindOnce(&RemotingLogToServer::SendLogRequest,
-                     base::Unretained(this), request, attempts_left));
-}
-
-void RemotingLogToServer::OnSendLogRequestResult(
-    const apis::v1::CreateLogEntryRequest& request,
-    int attempts_left,
-    const HttpStatus& status,
-    std::unique_ptr<apis::v1::CreateLogEntryResponse> response) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (status.ok()) {
-    VLOG(1) << "One log has been successfully sent.";
-    backoff_.InformOfRequest(true);
-    return;
-  }
-  LOG(WARNING) << "Failed to send one log."
-               << " Error: " << static_cast<int>(status.error_code())
-               << " Message: " << status.error_message();
-  backoff_.InformOfRequest(false);
-  if (attempts_left <= 0) {
-    LOG(WARNING) << "Exceeded maximum retry attempts. Dropping it...";
-    return;
-  }
-  SendLogRequestWithBackoff(request, attempts_left);
-}
-
-ServerLogEntry::Mode RemotingLogToServer::mode() const {
-  return mode_;
-}
-
-}  // namespace remoting
diff --git a/remoting/signaling/remoting_log_to_server.h b/remoting/signaling/remoting_log_to_server.h
deleted file mode 100644
index 9e3c4b4..0000000
--- a/remoting/signaling/remoting_log_to_server.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_SIGNALING_REMOTING_LOG_TO_SERVER_H_
-#define REMOTING_SIGNALING_REMOTING_LOG_TO_SERVER_H_
-
-#include <memory>
-
-#include "base/functional/callback.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/sequence_checker.h"
-#include "base/timer/timer.h"
-#include "net/base/backoff_entry.h"
-#include "remoting/signaling/log_to_server.h"
-
-namespace network {
-class SharedURLLoaderFactory;
-}  // namespace network
-
-namespace remoting {
-
-namespace apis {
-namespace v1 {
-class CreateLogEntryRequest;
-class CreateLogEntryResponse;
-}  // namespace v1
-}  // namespace apis
-
-class HttpStatus;
-class OAuthTokenGetter;
-
-// RemotingLogToServer sends log entries to to the remoting telemetry server.
-class RemotingLogToServer : public LogToServer {
- public:
-  RemotingLogToServer(
-      ServerLogEntry::Mode mode,
-      std::unique_ptr<OAuthTokenGetter> token_getter,
-      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
-
-  RemotingLogToServer(const RemotingLogToServer&) = delete;
-  RemotingLogToServer& operator=(const RemotingLogToServer&) = delete;
-
-  ~RemotingLogToServer() override;
-
-  // LogToServer interface.
-  void Log(const ServerLogEntry& entry) override;
-  ServerLogEntry::Mode mode() const override;
-
- private:
-  static constexpr int kMaxSendLogAttempts = 5;
-
-  using CreateLogEntryResponseCallback = base::OnceCallback<void(
-      const HttpStatus&,
-      std::unique_ptr<apis::v1::CreateLogEntryResponse>)>;
-  using CreateLogEntryCallback =
-      base::RepeatingCallback<void(const apis::v1::CreateLogEntryRequest&,
-                                   CreateLogEntryResponseCallback callback)>;
-
-  friend class RemotingLogToServerTest;
-
-  void SendLogRequest(const apis::v1::CreateLogEntryRequest& request,
-                      int attempts_left);
-  void SendLogRequestWithBackoff(const apis::v1::CreateLogEntryRequest& request,
-                                 int attempts_left);
-  void OnSendLogRequestResult(
-      const apis::v1::CreateLogEntryRequest& request,
-      int attempts_left,
-      const HttpStatus& status,
-      std::unique_ptr<apis::v1::CreateLogEntryResponse> response);
-
-  ServerLogEntry::Mode mode_;
-  std::unique_ptr<OAuthTokenGetter> token_getter_;
-  net::BackoffEntry backoff_;
-  base::OneShotTimer backoff_timer_;
-
-  // Callback used to send the log entry to the server. Replaceable for
-  // unittest.
-  CreateLogEntryCallback create_log_entry_;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-};
-
-}  // namespace remoting
-
-#endif  // REMOTING_SIGNALING_REMOTING_LOG_TO_SERVER_H_
diff --git a/remoting/signaling/remoting_log_to_server_unittest.cc b/remoting/signaling/remoting_log_to_server_unittest.cc
deleted file mode 100644
index f0c2b28f..0000000
--- a/remoting/signaling/remoting_log_to_server_unittest.cc
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/signaling/remoting_log_to_server.h"
-
-#include "base/test/mock_callback.h"
-#include "base/test/task_environment.h"
-#include "remoting/base/fake_oauth_token_getter.h"
-#include "remoting/base/http_status.h"
-#include "remoting/proto/remoting/v1/telemetry_messages.pb.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace remoting {
-
-namespace {
-
-using testing::_;
-
-}  // namespace
-
-class RemotingLogToServerTest : public testing::Test {
- public:
-  RemotingLogToServerTest() {
-    EXPECT_EQ(ServerLogEntry::ME2ME, log_to_server_.mode());
-    log_to_server_.create_log_entry_ = mock_create_log_entry_.Get();
-  }
-
-  ~RemotingLogToServerTest() override {
-    task_environment_.FastForwardUntilNoTasksRemain();
-  }
-
- protected:
-  const net::BackoffEntry& GetBackoffEntry() const {
-    return log_to_server_.backoff_;
-  }
-
-  int GetMaxSendLogAttempts() const {
-    return log_to_server_.kMaxSendLogAttempts;
-  }
-
-  using CreateLogEntryResponseCallback =
-      RemotingLogToServer::CreateLogEntryResponseCallback;
-
-  base::test::TaskEnvironment task_environment_{
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
-
-  base::MockCallback<RemotingLogToServer::CreateLogEntryCallback>
-      mock_create_log_entry_;
-
-  RemotingLogToServer log_to_server_{
-      ServerLogEntry::ME2ME,
-      std::make_unique<FakeOAuthTokenGetter>(OAuthTokenGetter::SUCCESS,
-                                             OAuthTokenInfo()),
-      nullptr};
-};
-
-TEST_F(RemotingLogToServerTest, SuccessfullySendOneLog) {
-  EXPECT_CALL(mock_create_log_entry_, Run(_, _))
-      .WillOnce([&](const apis::v1::CreateLogEntryRequest& request,
-                    CreateLogEntryResponseCallback callback) {
-        ASSERT_EQ(1, request.payload().entry().field_size());
-        ASSERT_EQ("test-key", request.payload().entry().field(0).key());
-        ASSERT_EQ("test-value", request.payload().entry().field(0).value());
-        std::move(callback).Run(
-            HttpStatus::OK(),
-            std::make_unique<apis::v1::CreateLogEntryResponse>());
-      });
-
-  ServerLogEntry entry;
-  entry.Set("test-key", "test-value");
-  log_to_server_.Log(entry);
-
-  task_environment_.FastForwardUntilNoTasksRemain();
-
-  ASSERT_EQ(0, GetBackoffEntry().failure_count());
-}
-
-TEST_F(RemotingLogToServerTest, FailedToSend_RetryWithBackoff) {
-  EXPECT_CALL(mock_create_log_entry_, Run(_, _))
-      .Times(GetMaxSendLogAttempts())
-      .WillRepeatedly([&](const apis::v1::CreateLogEntryRequest& request,
-                          CreateLogEntryResponseCallback callback) {
-        ASSERT_EQ(1, request.payload().entry().field_size());
-        ASSERT_EQ("test-key", request.payload().entry().field(0).key());
-        ASSERT_EQ("test-value", request.payload().entry().field(0).value());
-        std::move(callback).Run(
-            HttpStatus(HttpStatus::Code::UNAVAILABLE, "unavailable"), nullptr);
-      });
-
-  ServerLogEntry entry;
-  entry.Set("test-key", "test-value");
-  log_to_server_.Log(entry);
-
-  for (int i = 1; i <= GetMaxSendLogAttempts(); i++) {
-    task_environment_.FastForwardBy(GetBackoffEntry().GetTimeUntilRelease());
-    ASSERT_EQ(i, GetBackoffEntry().failure_count());
-  }
-}
-
-TEST_F(RemotingLogToServerTest, FailedToSendTwoLogs_RetryThenSucceeds) {
-  CreateLogEntryResponseCallback response_callback_1;
-  CreateLogEntryResponseCallback response_callback_2;
-  EXPECT_CALL(mock_create_log_entry_, Run(_, _))
-      .WillOnce([&](const apis::v1::CreateLogEntryRequest& request,
-                    CreateLogEntryResponseCallback callback) {
-        ASSERT_EQ(1, request.payload().entry().field_size());
-        ASSERT_EQ("test-key-1", request.payload().entry().field(0).key());
-        ASSERT_EQ("test-value-1", request.payload().entry().field(0).value());
-        response_callback_1 = std::move(callback);
-      })
-      .WillOnce([&](const apis::v1::CreateLogEntryRequest& request,
-                    CreateLogEntryResponseCallback callback) {
-        ASSERT_EQ(1, request.payload().entry().field_size());
-        ASSERT_EQ("test-key-2", request.payload().entry().field(0).key());
-        ASSERT_EQ("test-value-2", request.payload().entry().field(0).value());
-        response_callback_2 = std::move(callback);
-      })
-      .WillOnce([&](const apis::v1::CreateLogEntryRequest& request,
-                    CreateLogEntryResponseCallback callback) {
-        ASSERT_EQ(1, request.payload().entry().field_size());
-        ASSERT_EQ("test-key-1", request.payload().entry().field(0).key());
-        ASSERT_EQ("test-value-1", request.payload().entry().field(0).value());
-        response_callback_1 = std::move(callback);
-      })
-      .WillOnce([&](const apis::v1::CreateLogEntryRequest& request,
-                    CreateLogEntryResponseCallback callback) {
-        ASSERT_EQ(1, request.payload().entry().field_size());
-        ASSERT_EQ("test-key-2", request.payload().entry().field(0).key());
-        ASSERT_EQ("test-value-2", request.payload().entry().field(0).value());
-        response_callback_2 = std::move(callback);
-      });
-
-  ServerLogEntry entry_1;
-  entry_1.Set("test-key-1", "test-value-1");
-  log_to_server_.Log(entry_1);
-  task_environment_.FastForwardUntilNoTasksRemain();
-
-  ServerLogEntry entry_2;
-  entry_2.Set("test-key-2", "test-value-2");
-  log_to_server_.Log(entry_2);
-  task_environment_.FastForwardUntilNoTasksRemain();
-
-  ASSERT_EQ(0, GetBackoffEntry().failure_count());
-
-  std::move(response_callback_1)
-      .Run(HttpStatus(HttpStatus::Code::UNAVAILABLE, "unavailable"), nullptr);
-  task_environment_.FastForwardUntilNoTasksRemain();
-  std::move(response_callback_2)
-      .Run(HttpStatus(HttpStatus::Code::UNAVAILABLE, "unavailable"), nullptr);
-  task_environment_.FastForwardUntilNoTasksRemain();
-  ASSERT_EQ(2, GetBackoffEntry().failure_count());
-
-  std::move(response_callback_1)
-      .Run(HttpStatus::OK(),
-           std::make_unique<apis::v1::CreateLogEntryResponse>());
-  std::move(response_callback_2)
-      .Run(HttpStatus::OK(),
-           std::make_unique<apis::v1::CreateLogEntryResponse>());
-  task_environment_.FastForwardUntilNoTasksRemain();
-  ASSERT_EQ(0, GetBackoffEntry().failure_count());
-}
-
-}  // namespace remoting
diff --git a/remoting/signaling/server_log_entry.cc b/remoting/signaling/server_log_entry.cc
deleted file mode 100644
index 8f2bd62f..0000000
--- a/remoting/signaling/server_log_entry.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/signaling/server_log_entry.h"
-
-#include "base/notreached.h"
-#include "base/system/sys_info.h"
-#include "remoting/base/constants.h"
-#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
-
-using base::SysInfo;
-using jingle_xmpp::QName;
-using jingle_xmpp::XmlElement;
-
-namespace remoting {
-
-namespace {
-
-const char kLogCommand[] = "log";
-const char kLogEntry[] = "entry";
-
-const char kKeyEventName[] = "event-name";
-
-const char kKeyRole[] = "role";
-
-const char kKeyMode[] = "mode";
-const char kValueModeIt2Me[] = "it2me";
-const char kValueModeMe2Me[] = "me2me";
-
-const char kKeyCpu[] = "cpu";
-
-}  // namespace
-
-ServerLogEntry::ServerLogEntry() = default;
-
-ServerLogEntry::ServerLogEntry(const ServerLogEntry& other) = default;
-
-ServerLogEntry::~ServerLogEntry() = default;
-
-void ServerLogEntry::Set(const std::string& key, const std::string& value) {
-  values_map_[key] = value;
-}
-
-void ServerLogEntry::AddCpuField() {
-  Set(kKeyCpu, SysInfo::OperatingSystemArchitecture());
-}
-
-void ServerLogEntry::AddModeField(ServerLogEntry::Mode mode) {
-  const char* mode_value = nullptr;
-  switch (mode) {
-    case IT2ME:
-      mode_value = kValueModeIt2Me;
-      break;
-    case ME2ME:
-      mode_value = kValueModeMe2Me;
-      break;
-    default:
-      NOTREACHED();
-  }
-  Set(kKeyMode, mode_value);
-}
-
-void ServerLogEntry::AddRoleField(const char* role) {
-  Set(kKeyRole, role);
-}
-
-void ServerLogEntry::AddEventNameField(const char* name) {
-  Set(kKeyEventName, name);
-}
-
-// static
-std::unique_ptr<XmlElement> ServerLogEntry::MakeStanza() {
-  return std::make_unique<XmlElement>(
-      QName(kChromotingXmlNamespace, kLogCommand));
-}
-
-std::unique_ptr<XmlElement> ServerLogEntry::ToStanza() const {
-  std::unique_ptr<XmlElement> stanza(
-      new XmlElement(QName(kChromotingXmlNamespace, kLogEntry)));
-  ValuesMap::const_iterator iter;
-  for (iter = values_map_.begin(); iter != values_map_.end(); ++iter) {
-    stanza->AddAttr(QName(std::string(), iter->first), iter->second);
-  }
-  return stanza;
-}
-
-apis::v1::GenericLogEntry ServerLogEntry::ToGenericLogEntry() const {
-  apis::v1::GenericLogEntry log_entry;
-  for (auto pair : values_map_) {
-    auto* field = log_entry.add_field();
-    field->set_key(pair.first);
-    field->set_value(pair.second);
-  }
-  return log_entry;
-}
-
-}  // namespace remoting
diff --git a/remoting/signaling/server_log_entry.h b/remoting/signaling/server_log_entry.h
deleted file mode 100644
index 10db6cf..0000000
--- a/remoting/signaling/server_log_entry.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_SIGNALING_SERVER_LOG_ENTRY_H_
-#define REMOTING_SIGNALING_SERVER_LOG_ENTRY_H_
-
-#include <map>
-#include <memory>
-#include <string>
-
-#include "remoting/proto/remoting/v1/generic_log_entry.pb.h"
-
-namespace jingle_xmpp {
-class XmlElement;
-}  // namespace jingle_xmpp
-
-namespace remoting {
-
-// Utility class for building log entries to send to the remoting bot. This is
-// a wrapper around a key/value map and is copyable so it can be used in STL
-// containers.
-class ServerLogEntry {
- public:
-  // The mode of a connection.
-  enum Mode { IT2ME, ME2ME };
-
-  ServerLogEntry();
-  ServerLogEntry(const ServerLogEntry& other);
-  ~ServerLogEntry();
-
-  // Sets an arbitrary key/value entry.
-  void Set(const std::string& key, const std::string& value);
-
-  // Adds a field describing the CPU type of the platform.
-  void AddCpuField();
-
-  // Adds a field describing the mode of a connection to this log entry.
-  void AddModeField(Mode mode);
-
-  // Adds a field describing the role (client/host).
-  void AddRoleField(const char* role);
-
-  // Adds a field describing the type of log entry.
-  void AddEventNameField(const char* name);
-
-  // Constructs a log stanza. The caller should add one or more log entry
-  // stanzas as children of this stanza, before sending the log stanza to
-  // the remoting bot.
-  static std::unique_ptr<jingle_xmpp::XmlElement> MakeStanza();
-
-  // Converts this object to an XML stanza.
-  std::unique_ptr<jingle_xmpp::XmlElement> ToStanza() const;
-
-  apis::v1::GenericLogEntry ToGenericLogEntry() const;
-
- private:
-  typedef std::map<std::string, std::string> ValuesMap;
-
-  ValuesMap values_map_;
-};
-
-}  // namespace remoting
-
-#endif  // REMOTING_SIGNALING_SERVER_LOG_ENTRY_H_
diff --git a/remoting/signaling/server_log_entry_unittest.cc b/remoting/signaling/server_log_entry_unittest.cc
deleted file mode 100644
index 3956789..0000000
--- a/remoting/signaling/server_log_entry_unittest.cc
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/signaling/server_log_entry_unittest.h"
-
-#include <sstream>
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
-
-using jingle_xmpp::QName;
-using jingle_xmpp::XmlAttr;
-using jingle_xmpp::XmlElement;
-
-namespace remoting {
-
-const char kJabberClientNamespace[] = "jabber:client";
-const char kChromotingNamespace[] = "google:remoting";
-
-XmlElement* GetLogElementFromStanza(XmlElement* stanza) {
-  if (stanza->Name() != QName(kJabberClientNamespace, "iq")) {
-    ADD_FAILURE() << "Expected element 'iq'";
-    return nullptr;
-  }
-  XmlElement* log_element = stanza->FirstChild()->AsElement();
-  if (log_element->Name() != QName(kChromotingNamespace, "log")) {
-    ADD_FAILURE() << "Expected element 'log'";
-    return nullptr;
-  }
-  if (log_element->NextChild()) {
-    ADD_FAILURE() << "Expected only 1 child of 'iq'";
-    return nullptr;
-  }
-  return log_element;
-}
-
-XmlElement* GetSingleLogEntryFromStanza(XmlElement* stanza) {
-  XmlElement* log_element = GetLogElementFromStanza(stanza);
-  if (!log_element) {
-    // Test failure already recorded, so just return nullptr here.
-    return nullptr;
-  }
-  XmlElement* entry = log_element->FirstChild()->AsElement();
-  if (entry->Name() != QName(kChromotingNamespace, "entry")) {
-    ADD_FAILURE() << "Expected element 'entry'";
-    return nullptr;
-  }
-  if (entry->NextChild()) {
-    ADD_FAILURE() << "Expected only 1 child of 'log'";
-    return nullptr;
-  }
-  return entry;
-}
-
-bool VerifyStanza(const std::map<std::string, std::string>& key_value_pairs,
-                  const std::set<std::string> keys,
-                  const XmlElement* elem,
-                  std::string* error) {
-  int attrCount = 0;
-  for (const XmlAttr* attr = elem->FirstAttr(); attr != nullptr;
-       attr = attr->NextAttr(), attrCount++) {
-    if (attr->Name().Namespace().length() != 0) {
-      *error = "attribute has non-empty namespace " + attr->Name().Namespace();
-      return false;
-    }
-    const std::string& key = attr->Name().LocalPart();
-    const std::string& value = attr->Value();
-    auto iter = key_value_pairs.find(key);
-    if (iter == key_value_pairs.end()) {
-      if (keys.find(key) == keys.end()) {
-        *error = "unexpected attribute " + key;
-        return false;
-      }
-    } else {
-      if (iter->second != value) {
-        *error = "attribute " + key + " has value " + iter->second +
-                 ": expected " + value;
-        return false;
-      }
-    }
-  }
-  int attr_count_expected = key_value_pairs.size() + keys.size();
-  if (attrCount != attr_count_expected) {
-    std::stringstream s;
-    s << "stanza has " << attrCount << " keys: expected "
-      << attr_count_expected;
-    *error = s.str();
-    return false;
-  }
-  return true;
-}
-
-}  // namespace remoting
diff --git a/remoting/signaling/server_log_entry_unittest.h b/remoting/signaling/server_log_entry_unittest.h
deleted file mode 100644
index 221d57c..0000000
--- a/remoting/signaling/server_log_entry_unittest.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_SIGNALING_SERVER_LOG_ENTRY_UNITTEST_H_
-#define REMOTING_SIGNALING_SERVER_LOG_ENTRY_UNITTEST_H_
-
-#include <map>
-#include <set>
-#include <string>
-
-namespace jingle_xmpp {
-class XmlElement;
-}  // namespace jingle_xmpp
-
-namespace remoting {
-
-extern const char kJabberClientNamespace[];
-extern const char kChromotingNamespace[];
-
-// Verifies that |stanza| contains a <log> element and returns it. Otherwise
-// returns nullptr and records a test failure.
-jingle_xmpp::XmlElement* GetLogElementFromStanza(
-    jingle_xmpp::XmlElement* stanza);
-
-// Verifies that |stanza| contains only 1 log entry, and returns the <entry>
-// element. Otherwise returns nullptr and records a test failure.
-jingle_xmpp::XmlElement* GetSingleLogEntryFromStanza(
-    jingle_xmpp::XmlElement* stanza);
-
-// Verifies a logging stanza.
-// |keyValuePairs| lists the keys that must have specified values, and |keys|
-// lists the keys that must be present, but may have arbitrary values.
-// There must be no other keys.
-bool VerifyStanza(const std::map<std::string, std::string>& key_value_pairs,
-                  const std::set<std::string> keys,
-                  const jingle_xmpp::XmlElement* elem,
-                  std::string* error);
-
-}  // namespace remoting
-
-#endif  // REMOTING_SIGNALING_SERVER_LOG_ENTRY_UNITTEST_H_
diff --git a/remoting/signaling/xmpp_log_to_server.cc b/remoting/signaling/xmpp_log_to_server.cc
deleted file mode 100644
index fbb60e76..0000000
--- a/remoting/signaling/xmpp_log_to_server.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/signaling/xmpp_log_to_server.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/functional/bind.h"
-#include "base/task/sequenced_task_runner.h"
-#include "remoting/base/constants.h"
-#include "remoting/signaling/iq_sender.h"
-#include "remoting/signaling/signal_strategy.h"
-#include "remoting/signaling/xmpp_constants.h"
-#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
-
-using jingle_xmpp::QName;
-using jingle_xmpp::XmlElement;
-
-namespace remoting {
-
-XmppLogToServer::XmppLogToServer(
-    ServerLogEntry::Mode mode,
-    SignalStrategy* signal_strategy,
-    const std::string& directory_bot_jid,
-    scoped_refptr<base::SequencedTaskRunner> caller_task_runner)
-    : mode_(mode),
-      signal_strategy_(signal_strategy),
-      directory_bot_jid_(directory_bot_jid) {
-  DETACH_FROM_SEQUENCE(sequence_checker_);
-  if (!caller_task_runner || caller_task_runner->RunsTasksInCurrentSequence()) {
-    Init();
-    return;
-  }
-  caller_task_runner->PostTask(
-      FROM_HERE,
-      base::BindOnce(&XmppLogToServer::Init, weak_factory_.GetWeakPtr()));
-}
-
-XmppLogToServer::~XmppLogToServer() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  signal_strategy_->RemoveListener(this);
-}
-
-void XmppLogToServer::OnSignalStrategyStateChange(SignalStrategy::State state) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (state == SignalStrategy::CONNECTED) {
-    iq_sender_ = std::make_unique<IqSender>(signal_strategy_);
-    SendPendingEntries();
-  } else if (state == SignalStrategy::DISCONNECTED) {
-    iq_sender_.reset();
-  }
-}
-
-bool XmppLogToServer::OnSignalStrategyIncomingStanza(
-    const jingle_xmpp::XmlElement* stanza) {
-  return false;
-}
-
-void XmppLogToServer::Log(const ServerLogEntry& entry) {
-  pending_entries_.push_back(entry);
-  SendPendingEntries();
-}
-
-void XmppLogToServer::Init() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  signal_strategy_->AddListener(this);
-}
-
-void XmppLogToServer::SendPendingEntries() {
-  if (iq_sender_ == nullptr) {
-    return;
-  }
-  if (pending_entries_.empty()) {
-    return;
-  }
-  // Make one stanza containing all the pending entries.
-  std::unique_ptr<XmlElement> stanza(ServerLogEntry::MakeStanza());
-  while (!pending_entries_.empty()) {
-    ServerLogEntry& entry = pending_entries_.front();
-    stanza->AddElement(entry.ToStanza().release());
-    pending_entries_.pop_front();
-  }
-  // Send the stanza to the server and ignore the response.
-  iq_sender_->SendIq(kIqTypeSet, directory_bot_jid_, std::move(stanza),
-                     IqSender::ReplyCallback());
-}
-
-ServerLogEntry::Mode XmppLogToServer::mode() const {
-  return mode_;
-}
-
-}  // namespace remoting
diff --git a/remoting/signaling/xmpp_log_to_server.h b/remoting/signaling/xmpp_log_to_server.h
deleted file mode 100644
index 2256865c..0000000
--- a/remoting/signaling/xmpp_log_to_server.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_SIGNALING_XMPP_LOG_TO_SERVER_H_
-#define REMOTING_SIGNALING_XMPP_LOG_TO_SERVER_H_
-
-#include <map>
-#include <string>
-
-#include "base/containers/circular_deque.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/task/sequenced_task_runner.h"
-#include "remoting/signaling/log_to_server.h"
-#include "remoting/signaling/server_log_entry.h"
-#include "remoting/signaling/signal_strategy.h"
-
-namespace jingle_xmpp {
-class XmlElement;
-}  // namespace jingle_xmpp
-
-namespace remoting {
-
-class IqSender;
-
-// XmppLogToServer sends log entries to a server through the signaling strategy.
-class XmppLogToServer : public LogToServer, public SignalStrategy::Listener {
- public:
-  // The instance will be initialized on |caller_task_runner|, and thereafter
-  // it must be used on the sequence of |caller_task_runner|. By default it will
-  // be initialized on the current active sequence.
-  XmppLogToServer(
-      ServerLogEntry::Mode mode,
-      SignalStrategy* signal_strategy,
-      const std::string& directory_bot_jid,
-      scoped_refptr<base::SequencedTaskRunner> caller_task_runner = {});
-
-  XmppLogToServer(const XmppLogToServer&) = delete;
-  XmppLogToServer& operator=(const XmppLogToServer&) = delete;
-
-  ~XmppLogToServer() override;
-
-  // SignalStrategy::Listener interface.
-  void OnSignalStrategyStateChange(SignalStrategy::State state) override;
-  bool OnSignalStrategyIncomingStanza(
-      const jingle_xmpp::XmlElement* stanza) override;
-
-  // LogToServer interface.
-  void Log(const ServerLogEntry& entry) override;
-  ServerLogEntry::Mode mode() const override;
-
- private:
-  void Init();
-  void SendPendingEntries();
-
-  ServerLogEntry::Mode mode_;
-  raw_ptr<SignalStrategy> signal_strategy_;
-  std::unique_ptr<IqSender> iq_sender_;
-  std::string directory_bot_jid_;
-
-  base::circular_deque<ServerLogEntry> pending_entries_;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  base::WeakPtrFactory<XmppLogToServer> weak_factory_{this};
-};
-
-}  // namespace remoting
-
-#endif  // REMOTING_SIGNALING_XMPP_LOG_TO_SERVER_H_
diff --git a/remoting/signaling/xmpp_log_to_server_unittest.cc b/remoting/signaling/xmpp_log_to_server_unittest.cc
deleted file mode 100644
index 31c50e9..0000000
--- a/remoting/signaling/xmpp_log_to_server_unittest.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2014 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/signaling/xmpp_log_to_server.h"
-
-#include <memory>
-
-#include "base/run_loop.h"
-#include "base/test/task_environment.h"
-#include "remoting/signaling/mock_signal_strategy.h"
-#include "remoting/signaling/server_log_entry_unittest.h"
-#include "remoting/signaling/signaling_address.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using jingle_xmpp::QName;
-using jingle_xmpp::XmlElement;
-using testing::_;
-using testing::DeleteArg;
-using testing::DoAll;
-using testing::InSequence;
-using testing::Return;
-
-namespace remoting {
-
-namespace {
-
-const char kTestBotJid[] = "remotingunittest@bot.talk.google.com";
-const char kClientJid[] = "host@domain.com/1234";
-
-MATCHER_P2(IsLogEntry, key, value, "") {
-  XmlElement* entry = GetSingleLogEntryFromStanza(arg);
-  if (!entry) {
-    return false;
-  }
-
-  return entry->Attr(QName(std::string(), key)) == value;
-}
-
-}  // namespace
-
-class XmppLogToServerTest : public testing::Test {
- public:
-  XmppLogToServerTest() : signal_strategy_(SignalingAddress(kClientJid)) {}
-  void SetUp() override {
-    EXPECT_CALL(signal_strategy_, AddListener(_));
-    EXPECT_CALL(signal_strategy_, RemoveListener(_));
-    xmpp_log_to_server_ = std::make_unique<XmppLogToServer>(
-        ServerLogEntry::ME2ME, &signal_strategy_, kTestBotJid);
-  }
-
- protected:
-  base::test::SingleThreadTaskEnvironment task_environment_;
-  base::RunLoop run_loop_;
-  MockSignalStrategy signal_strategy_;
-  std::unique_ptr<XmppLogToServer> xmpp_log_to_server_;
-};
-
-TEST_F(XmppLogToServerTest, LogWhenConnected) {
-  {
-    InSequence s;
-    EXPECT_CALL(signal_strategy_, AddListener(_));
-    EXPECT_CALL(signal_strategy_, GetNextId());
-    EXPECT_CALL(signal_strategy_, SendStanzaPtr(IsLogEntry("a", "1")))
-        .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-    EXPECT_CALL(signal_strategy_, GetNextId());
-    EXPECT_CALL(signal_strategy_, SendStanzaPtr(IsLogEntry("b", "2")))
-        .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
-    EXPECT_CALL(signal_strategy_, RemoveListener(_)).RetiresOnSaturation();
-  }
-
-  ServerLogEntry entry1;
-  ServerLogEntry entry2;
-  entry1.Set("a", "1");
-  entry2.Set("b", "2");
-  xmpp_log_to_server_->Log(entry1);
-  xmpp_log_to_server_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED);
-  xmpp_log_to_server_->Log(entry2);
-  run_loop_.RunUntilIdle();
-}
-
-TEST_F(XmppLogToServerTest, DontLogWhenDisconnected) {
-  EXPECT_CALL(signal_strategy_, SendStanzaPtr(_)).Times(0);
-
-  ServerLogEntry entry;
-  entry.Set("foo", "bar");
-  xmpp_log_to_server_->Log(entry);
-  run_loop_.RunUntilIdle();
-}
-
-}  // namespace remoting
diff --git a/services/screen_ai/screen_ai_ocr_perf_test.cc b/services/screen_ai/screen_ai_ocr_perf_test.cc
index 36c7443..da2911c4 100644
--- a/services/screen_ai/screen_ai_ocr_perf_test.cc
+++ b/services/screen_ai/screen_ai_ocr_perf_test.cc
@@ -12,6 +12,7 @@
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/containers/map_util.h"
+#include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/json/json_file_value_serializer.h"
@@ -43,12 +44,14 @@
   screen_ai_ocr_perf [options]
 
 Options:
-  --help        Show this help message and exit.
-  --jpeg_image  The image to test in JPEG format.
-  --output_path The path to store the perf result in JSON format.
+  --help         Show this help message and exit.
+  --jpeg_image   The single image to test in JPEG format.
+  --image_folder The path to a folder containing batch JPEG images to test.
+  --output_path  The path to store the perf result in JSON format.
 )";
 
 constexpr char kJpegImageOption[] = "jpeg_image";
+constexpr char kImageFolderOption[] = "image_folder";
 constexpr char kOutputPathOption[] = "output_path";
 
 constexpr int kWarmUpIterationCount = 3;
@@ -95,12 +98,24 @@
   }
 
   OcrTestEnvironment(const std::string& output_path,
-                     const std::string& jpeg_image_path)
-      : output_path_(output_path),
-        jpeg_image_(GetBitmap(base::FilePath(jpeg_image_path))) {}
+                     const std::string& jpeg_image_path,
+                     const std::string& image_folder)
+      : output_path_(output_path) {
+    if (!jpeg_image_path.empty()) {
+      jpeg_images_.push_back(GetBitmap(base::FilePath(jpeg_image_path)));
+    } else if (!image_folder.empty()) {
+      base::FileEnumerator enumerator(base::FilePath(image_folder),
+                                      /*recursive=*/false,
+                                      base::FileEnumerator::FILES);
+      for (base::FilePath current_image = enumerator.Next();
+           !current_image.empty(); current_image = enumerator.Next()) {
+        jpeg_images_.push_back(GetBitmap(base::FilePath(current_image)));
+      }
+    }
+  }
 
   void SetUp() override {
-    CHECK(!jpeg_image_.empty());
+    CHECK(!jpeg_images_.empty());
 
     base::FilePath directory_path(kLibraryDirectoryPath);
     base::FilePath library_path = directory_path.Append(kLibraryName);
@@ -146,7 +161,11 @@
     }
   }
 
-  void PerformOcr() { library_->PerformOcr(jpeg_image_); }
+  void PerformOcr() {
+    for (const auto& image : jpeg_images_) {
+      library_->PerformOcr(image);
+    }
+  }
 
   void Benchmark(const std::string& metrics_name,
                  base::RepeatingClosure target_ops) {
@@ -182,7 +201,7 @@
 
   base::Value::Dict perf_values_;
   base::FilePath output_path_;
-  SkBitmap jpeg_image_;
+  std::vector<SkBitmap> jpeg_images_;
   std::unique_ptr<ScreenAILibraryWrapper> library_;
 };
 
@@ -213,18 +232,27 @@
 
   std::string jpeg_image =
       cmd_line->GetSwitchValueASCII(screen_ai::kJpegImageOption);
+  std::string image_folder =
+      cmd_line->GetSwitchValueASCII(screen_ai::kImageFolderOption);
   std::string output_path =
       cmd_line->GetSwitchValueASCII(screen_ai::kOutputPathOption);
 
-  if (jpeg_image.empty() || output_path.empty()) {
-    LOG(ERROR) << "Missing required options: " << screen_ai::kJpegImageOption
-               << ", " << screen_ai::kOutputPathOption << "\n";
+  if (jpeg_image.empty() && image_folder.empty()) {
+    LOG(ERROR) << "Missing required option: " << screen_ai::kJpegImageOption
+               << " or " << screen_ai::kImageFolderOption << "\n";
+    return EXIT_FAILURE;
+  }
+
+  if (output_path.empty()) {
+    LOG(ERROR) << "Missing required option: " << screen_ai::kOutputPathOption
+               << "\n";
     return EXIT_FAILURE;
   }
 
   ::testing::InitGoogleTest(&argc, argv);
 
-  screen_ai::g_env = new screen_ai::OcrTestEnvironment(output_path, jpeg_image);
+  screen_ai::g_env =
+      new screen_ai::OcrTestEnvironment(output_path, jpeg_image, image_folder);
   ::testing::AddGlobalTestEnvironment(screen_ai::g_env);
   return RUN_ALL_TESTS();
 }
diff --git a/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom b/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom
index 4828bfc..3066550 100644
--- a/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom
+++ b/services/viz/privileged/mojom/compositing/frame_sink_manager.mojom
@@ -219,17 +219,11 @@
   EnableFrameSinkManagerTestApi(
       pending_receiver<FrameSinkManagerTestApi> receiver);
 
-  // Setup the connection between the Browser (at WebContentsImpl level) and
-  // the VizCompositor thread (at InputManager level) in both directions to
-  // allow transferring information from Viz to the Browser and vice versa,
-  // when the VizCompositor thread is handling input using RenderInputRouters
-  // with InputVizard.
-  SetupRenderInputRouterDelegateConnection(
-    mojo_base.mojom.UnguessableToken grouping_id,
-    pending_remote<input.mojom.RenderInputRouterDelegateClient>
-      rir_delegate_client_remote,
-    pending_receiver<input.mojom.RenderInputRouterDelegate>
-      rir_delegate_receiver);
+  // Sets up the RendererInputRouterDelegateRegistry interface for managing
+  // RenderInputRouterDelegate connections between RenderWidgetHosts (on
+  // CrBrowserMain thread) and the InputManager (on VizCompositor thread).
+  SetupRendererInputRouterDelegateRegistry(
+    pending_receiver<RendererInputRouterDelegateRegistry> receiver);
 
   // Notifies list of RenderInputRouters of their block state changes for input
   // event handling on the VizCompositorThread.
@@ -282,3 +276,22 @@
       blink.mojom.SameDocNavigationScreenshotDestinationToken destination_token,
       CopyOutputResult copy_output_result);
 };
+
+// Implemented by the GPU process (VizCompositorThread) and called from the
+// browser process (CrBrowserMain thread). This allows the
+// RenderInputRouterDelegate[Client] interface to use the same mojo pipe to
+// send/receive information for input handling between the CrBrowserMain and the
+// VizCompositorThread.
+interface RendererInputRouterDelegateRegistry {
+  // Setup the connection between the Browser (at RenderWidgetHost level) and
+  // the VizCompositor thread (at InputManager level) in both directions to
+  // allow transferring information from Viz to the Browser and vice versa,
+  // when the VizCompositor thread is handling input using RenderInputRouters
+  // with InputVizard. This connection is per FrameSinkId.
+  SetupRenderInputRouterDelegateConnection(
+      FrameSinkId id,
+      pending_associated_remote<input.mojom.RenderInputRouterDelegateClient>
+          rir_delegate_client_remote,
+      pending_associated_receiver<input.mojom.RenderInputRouterDelegate>
+          rir_delegate_receiver);
+};
diff --git a/services/webnn/ort/graph_builder_ort.h b/services/webnn/ort/graph_builder_ort.h
index ae1c2359a..fe51838e 100644
--- a/services/webnn/ort/graph_builder_ort.h
+++ b/services/webnn/ort/graph_builder_ort.h
@@ -39,8 +39,8 @@
   // external data (weights).
   //
   // Returns unexpected if it fails.
-  [[nodiscard]] base::expected<std::unique_ptr<ModelEditor::ModelInfo>,
-                               mojom::ErrorPtr>
+  [[nodiscard]] static base::expected<std::unique_ptr<ModelEditor::ModelInfo>,
+                                      mojom::ErrorPtr>
   CreateAndBuild(
       const mojom::GraphInfo& graph_info,
       ContextProperties context_properties,
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index b78d898..7f5c4e40 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -5232,6 +5232,21 @@
             ]
         }
     ],
+    "ClankMostVisitedTilesCustomization": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "MostVisitedTilesCustomization"
+                    ]
+                }
+            ]
+        }
+    ],
     "ClankMostVisitedTilesNewScoring": [
         {
             "platforms": [
@@ -23811,7 +23826,8 @@
     "TimedHTMLParserBudgetForAndroid": [
         {
             "platforms": [
-                "android"
+                "android",
+                "android_webview"
             ],
             "experiments": [
                 {
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle
index 954bf4c..b9fc5843 100644
--- a/third_party/androidx/build.gradle
+++ b/third_party/androidx/build.gradle
@@ -305,7 +305,7 @@
     google()
     maven {
         // This URL is generated by the fetch_all_androidx.py script.
-        url 'https://androidx.dev/snapshots/builds/13555495/artifacts/repository'
+        url 'https://androidx.dev/snapshots/builds/13558109/artifacts/repository'
     }
     mavenCentral()
 }
diff --git a/third_party/angle b/third_party/angle
index 2f6f051..90668ec 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit 2f6f0514563d81e439e04ba09eee9e8a1d6ca8d1
+Subproject commit 90668ecf2978f085de9a9bdef4d8e5bad79df71e
diff --git a/third_party/blink/public/mojom/mediastream/media_stream.mojom b/third_party/blink/public/mojom/mediastream/media_stream.mojom
index 482dfbeb..360ae63 100644
--- a/third_party/blink/public/mojom/mediastream/media_stream.mojom
+++ b/third_party/blink/public/mojom/mediastream/media_stream.mojom
@@ -55,6 +55,24 @@
 
 // Elements in this enum should not be deleted or rearranged; the only
 // permitted operation is to add new elements before NUM_MEDIA_REQUEST_RESULTS.
+//
+// This enum is used by GenerateStreams(), which is a critical part
+// of such Web API calls as getDisplayMedia() and getUserMedia().
+//
+// Much of the logic is shared, and so are the enum values.
+// However, some enum values are specific to gDM/gUM,
+// and some values are used slightly differently between
+// calls associated with gDM/gUM.
+//
+// These differences were not exhaustively documented.
+// We provide partial documentation starting now;
+// hopefully this can be extended over time.
+//
+// The non-exhaustive list of differences includes:
+// - Calls to gDM which result in the user explicitly rejecting the prompt
+//   result in PERMISSION_DENIED_BY_USER. This allows a distinct error name,
+//   message or type to be exposed to the caller.
+//   In contrast, gUM returns PERMISSION_DENIED in such cases - for now.
 enum MediaStreamRequestResult {
   OK,
   PERMISSION_DENIED,
@@ -75,6 +93,7 @@
   DEVICE_IN_USE,
   REQUEST_CANCELLED,
   START_TIMEOUT,
+  PERMISSION_DENIED_BY_USER,
   NUM_MEDIA_REQUEST_RESULTS,
 };
 
diff --git a/third_party/blink/public/mojom/payments/payment_request.mojom b/third_party/blink/public/mojom/payments/payment_request.mojom
index dfd2990..a054d85 100644
--- a/third_party/blink/public/mojom/payments/payment_request.mojom
+++ b/third_party/blink/public/mojom/payments/payment_request.mojom
@@ -179,8 +179,16 @@
   // Experimental members that allow specifying information about the card
   // network and issuer, including icons for both. These are controlled by the
   // SecurePaymentConfirmationNetworkAndIssuerIcons Blink runtime feature.
+  //
+  // Note: These parameters are deprecated in favour of
+  // |payment_entities_logos|, but are being kept for now to support partner
+  // testing while the updated API is in development.
   NetworkOrIssuerInformation? network_info;
   NetworkOrIssuerInformation? issuer_info;
+
+  // A list of logos representing entities that are facilitating the payment
+  // that this SPC call is for.
+  array<PaymentEntityLogo> payment_entities_logos;
 };
 
 struct NetworkOrIssuerInformation {
@@ -188,6 +196,12 @@
   url.mojom.Url icon;
 };
 
+struct PaymentEntityLogo {
+  // Only HTTP(s) or data URLs are permitted.
+  url.mojom.Url url;
+  string label;
+};
+
 struct PaymentMethodData {
   string supported_method;
 
diff --git a/third_party/blink/renderer/bindings/core/v8/script_promise_resolver_with_tracker.h b/third_party/blink/renderer/bindings/core/v8/script_promise_resolver_with_tracker.h
index a56e2db..e8ce91e 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_promise_resolver_with_tracker.h
+++ b/third_party/blink/renderer/bindings/core/v8/script_promise_resolver_with_tracker.h
@@ -127,8 +127,8 @@
       return;
 
     is_result_recorded_ = true;
-    base::UmaHistogramEnumeration(metric_name_prefix_ + "." + result_suffix_,
-                                  result);
+    base::UmaHistogramEnumeration(
+        base::StrCat({metric_name_prefix_, ".", result_suffix_}), result);
   }
 
   void RecordLatency() {
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni
index 3e985636..39168d3 100644
--- a/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -950,6 +950,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_payment_details_modifier.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_payment_details_update.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_payment_details_update.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_payment_entity_logo.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_payment_entity_logo.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_payment_handler_response.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_payment_handler_response.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_payment_item.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_modules.gni b/third_party/blink/renderer/bindings/idl_in_modules.gni
index 35714f5..37a640d9 100644
--- a/third_party/blink/renderer/bindings/idl_in_modules.gni
+++ b/third_party/blink/renderer/bindings/idl_in_modules.gni
@@ -557,6 +557,7 @@
   "//third_party/blink/renderer/modules/payments/payment_details_init.idl",
   "//third_party/blink/renderer/modules/payments/payment_details_modifier.idl",
   "//third_party/blink/renderer/modules/payments/payment_details_update.idl",
+  "//third_party/blink/renderer/modules/payments/payment_entity_logo.idl",
   "//third_party/blink/renderer/modules/payments/payment_handler_response.idl",
   "//third_party/blink/renderer/modules/payments/payment_item.idl",
   "//third_party/blink/renderer/modules/payments/payment_manager.idl",
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index da2b0c7ca6..47c6a924 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -398,11 +398,6 @@
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding_registry.h"
 #include "third_party/blink/renderer/platform/wtf/text/utf16.h"
 
-#ifndef NDEBUG
-using WeakDocumentSet = blink::HeapHashSet<blink::WeakMember<blink::Document>>;
-static WeakDocumentSet& LiveDocumentSet();
-#endif
-
 namespace blink {
 
 namespace {
@@ -414,6 +409,15 @@
   bool SkipNonAtomicInlineObservations() const final;
 };
 
+using WeakDocumentSet = blink::HeapHashSet<blink::WeakMember<blink::Document>>;
+
+WeakDocumentSet& LiveDocumentSet() {
+  using WeakDocumentSetHolder = blink::DisallowNewWrapper<WeakDocumentSet>;
+  DEFINE_STATIC_LOCAL(blink::Persistent<WeakDocumentSetHolder>, holder,
+                      (blink::MakeGarbageCollected<WeakDocumentSetHolder>()));
+  return holder->Value();
+}
+
 // Returns true if any of <object> ancestors don't start loading or are loading
 // plugins/frames/images. If there are no <object> ancestors, this function
 // returns false.
@@ -973,9 +977,7 @@
   DCHECK(!ParentDocument() ||
          !ParentDocument()->domWindow()->IsContextPaused());
 
-#ifndef NDEBUG
   LiveDocumentSet().insert(this);
-#endif
 }
 
 Document::~Document() {
@@ -9554,12 +9556,17 @@
 
 void Document::OnLocalRootWidgetCreated() {
   if (!features::kThrottleFrameRateOnInitialization.Get() || !GetFrame() ||
-      !GetFrame()->GetPage() || !GetFrame()->IsAttached() ||
-      !GetExecutionContext()->CrossOriginIsolatedCapability()) {
+      !GetFrame()->GetPage() || !GetFrame()->IsAttached()) {
     return;
   }
-  GetFrame()->GetPage()->GetChromeClient().SetShouldThrottleFrameRate(
-      true, *GetFrame());
+  bool allowed_by_security = CanThrottleFrameRate();
+  base::UmaHistogramBoolean(
+      "Blink.ThrottleFrameRate.AllowedBySecurity.DocumentInitialization",
+      allowed_by_security);
+  if (allowed_by_security) {
+    GetFrame()->GetPage()->GetChromeClient().SetShouldThrottleFrameRate(
+        true, *GetFrame());
+  }
 }
 
 void Document::ProcessScheduledShadowTreeCreationsNow() {
@@ -9605,12 +9612,16 @@
 }
 
 void Document::UpdateRenderFrameRate() {
-  if (!GetFrame() || !GetFrame()->GetPage() || !GetFrame()->IsAttached() ||
-      !GetExecutionContext()->CrossOriginIsolatedCapability()) {
+  if (!GetFrame() || !GetFrame()->GetPage() || !GetFrame()->IsAttached()) {
     return;
   }
-  GetFrame()->GetPage()->GetChromeClient().SetShouldThrottleFrameRate(
-      has_frame_rate_blocking_expect_link_elements_, *GetFrame());
+  bool allowed_by_security = CanThrottleFrameRate();
+  base::UmaHistogramBoolean("Blink.ThrottleFrameRate.AllowedBySecurity.API",
+                            allowed_by_security);
+  if (allowed_by_security) {
+    GetFrame()->GetPage()->GetChromeClient().SetShouldThrottleFrameRate(
+        has_frame_rate_blocking_expect_link_elements_, *GetFrame());
+  }
 }
 
 // static
@@ -9780,19 +9791,30 @@
   return cached_top_frame_site_for_visited_links_.value();
 }
 
+bool Document::CanThrottleFrameRate() {
+  // To prevent side-channel attacks by monitoring the frame rate to detect
+  // page loads from other origins, we only allow the frame rate to be throttled
+  // if the renderer process is only hosting pages from one origin.
+  CHECK(GetExecutionContext());
+  const SecurityOrigin* expected_security_origin =
+      GetExecutionContext()->GetSecurityOrigin();
+  for (blink::Document* document : blink::LiveDocumentSet()) {
+    if (!document->GetExecutionContext() ||
+        !document->GetExecutionContext()->GetSecurityOrigin()->IsSameOriginWith(
+            expected_security_origin)) {
+      return false;
+    }
+  }
+  return true;
+}
+
 template class CORE_TEMPLATE_EXPORT Supplement<Document>;
 
 }  // namespace blink
-#ifndef NDEBUG
-static WeakDocumentSet& LiveDocumentSet() {
-  using WeakDocumentSetHolder = blink::DisallowNewWrapper<WeakDocumentSet>;
-  DEFINE_STATIC_LOCAL(blink::Persistent<WeakDocumentSetHolder>, holder,
-                      (blink::MakeGarbageCollected<WeakDocumentSetHolder>()));
-  return holder->Value();
-}
 
+#ifndef NDEBUG
 void ShowLiveDocumentInstances() {
-  WeakDocumentSet& set = LiveDocumentSet();
+  blink::WeakDocumentSet& set = blink::LiveDocumentSet();
   fprintf(stderr, "There are %u documents currently alive:\n", set.size());
   for (blink::Document* document : set) {
     fprintf(stderr, "- Document %p URL: %s\n", document,
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 00ef003..cbda08b1 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -2494,6 +2494,8 @@
                                      const String& html,
                                      ExceptionState& exception_state);
 
+  bool CanThrottleFrameRate();
+
   // Mutable because the token is lazily-generated on demand if no token is
   // explicitly set.
   mutable std::optional<DocumentToken> token_;
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
index a8cf2d3..107dc31 100644
--- a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
+++ b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
@@ -255,6 +255,16 @@
   return buffer;
 }
 
+DOMArrayBuffer* DOMArrayBuffer::CreateUninitialized(size_t num_elements,
+                                                    size_t element_byte_size) {
+  ArrayBufferContents contents(
+      num_elements, element_byte_size, ArrayBufferContents::kNotShared,
+      ArrayBufferContents::kDontInitialize,
+      ArrayBufferContents::AllocationFailureBehavior::kCrash);
+  CHECK(contents.IsValid());
+  return Create(std::move(contents));
+}
+
 DOMArrayBuffer* DOMArrayBuffer::CreateUninitializedOrNull(
     size_t num_elements,
     size_t element_byte_size) {
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h
index 5fbaa02..384f2ca 100644
--- a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h
+++ b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h
@@ -44,12 +44,6 @@
     contents.ByteSpan().copy_from(source);
     return Create(std::move(contents));
   }
-  // TODO(tsepez): should be declared UNSAFE_BUFFER_USAGE.
-  static DOMArrayBuffer* Create(const void* source, size_t byte_length) {
-    // SAFETY: Caller guarantees that `source` contains `byte_length` bytes.
-    return Create(UNSAFE_BUFFERS(
-        base::span(static_cast<const uint8_t*>(source), byte_length)));
-  }
 
   static DOMArrayBuffer* Create(scoped_refptr<SharedBuffer>);
   static DOMArrayBuffer* Create(const Vector<base::span<const char>>&);
@@ -57,13 +51,10 @@
   static DOMArrayBuffer* CreateOrNull(size_t num_elements,
                                       size_t element_byte_size);
   static DOMArrayBuffer* CreateOrNull(base::span<const uint8_t> source);
-  // TODO(tsepez): should be declared UNSAFE_BUFFER_USAGE.
-  static DOMArrayBuffer* CreateOrNull(const void* source, size_t byte_length) {
-    // SAFETY: Caller guarantees that `source` contains `byte_length` bytes.
-    return CreateOrNull(UNSAFE_BUFFERS(
-        base::span(static_cast<const uint8_t*>(source), byte_length)));
-  }
 
+  // For use by DOMTypedArray.
+  static DOMArrayBuffer* CreateUninitialized(size_t num_elements,
+                                             size_t element_byte_size);
   // Only for use by XMLHttpRequest::responseArrayBuffer,
   // Internals::serializeObject, and
   // FetchDataLoaderAsArrayBuffer::OnStateChange.
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_typed_array.h b/third_party/blink/renderer/core/typed_arrays/dom_typed_array.h
index 53352a42..454fb5c6f 100644
--- a/third_party/blink/renderer/core/typed_arrays/dom_typed_array.h
+++ b/third_party/blink/renderer/core/typed_arrays/dom_typed_array.h
@@ -34,12 +34,11 @@
   static ThisType* Create(base::span<const ValueType> array)
     requires std::is_trivially_copyable_v<ValueType>
   {
-    // Intentionally avoids using `as_bytes`, since that requires
-    // `std::has_unique_object_representations_v<ValueType>`, which we neither
-    // need here nor can guarantee.
     DOMArrayBuffer* buffer =
-        DOMArrayBuffer::Create(array.data(), array.size_bytes());
-    return Create(buffer, 0, array.size());
+        DOMArrayBuffer::CreateUninitialized(array.size(), sizeof(ValueType));
+    ThisType* typed_array = Create(buffer, 0, array.size());
+    typed_array->AsSpan().copy_from(array);
+    return typed_array;
   }
 
   static ThisType* CreateOrNull(size_t length) {
@@ -51,12 +50,11 @@
   static ThisType* CreateOrNull(base::span<const ValueType> array)
     requires std::is_trivially_copyable_v<ValueType>
   {
-    // Intentionally avoids using `as_bytes`, since that requires
-    // `std::has_unique_object_representations_v<ValueType>`, which we neither
-    // need here nor can guarantee.
-    DOMArrayBuffer* buffer =
-        DOMArrayBuffer::CreateOrNull(array.data(), array.size_bytes());
-    return buffer ? Create(buffer, 0, array.size()) : nullptr;
+    ThisType* typed_array = CreateUninitializedOrNull(array.size());
+    if (typed_array) {
+      typed_array->AsSpan().copy_from(array);
+    }
+    return typed_array;
   }
 
   static ThisType* CreateUninitializedOrNull(size_t length) {
diff --git a/third_party/blink/renderer/modules/ai/language_model.cc b/third_party/blink/renderer/modules/ai/language_model.cc
index 5560b4b..578806a9 100644
--- a/third_party/blink/renderer/modules/ai/language_model.cc
+++ b/third_party/blink/renderer/modules/ai/language_model.cc
@@ -596,12 +596,6 @@
     return std::nullopt;
   }
 
-  if (!input->IsString() &&
-      !RuntimeEnabledFeatures::AIPromptAPIMultimodalInputEnabled()) {
-    exception_state.ThrowTypeError("Input type not supported");
-    return std::nullopt;
-  }
-
   AbortSignal* signal = options->getSignalOr(nullptr);
   if (HandleAbortSignal(signal, script_state, exception_state)) {
     return std::nullopt;
@@ -643,12 +637,6 @@
       MakeGarbageCollected<ScriptPromiseResolver<IDLUndefined>>(script_state);
   auto promise = resolver->Promise();
 
-  // The API impl only accepts a string by default for now, more to come soon!
-  if (!input->IsString() &&
-      !RuntimeEnabledFeatures::AIPromptAPIMultimodalInputEnabled()) {
-    exception_state.ThrowTypeError("Input type not supported");
-    return promise;
-  }
   if (!language_model_remote_) {
     ThrowSessionDestroyedException(exception_state);
     return promise;
@@ -716,13 +704,6 @@
     return EmptyPromise();
   }
 
-  // The API impl only accepts a string by default for now, more to come soon!
-  if (!input->IsString() &&
-      !RuntimeEnabledFeatures::AIPromptAPIMultimodalInputEnabled()) {
-    exception_state.ThrowTypeError("Input type not supported");
-    return EmptyPromise();
-  }
-
   base::UmaHistogramEnumeration(AIMetrics::GetAIAPIUsageMetricName(
                                     AIMetrics::AISessionType::kLanguageModel),
                                 AIMetrics::AIAPI::kSessionCountPromptTokens);
diff --git a/third_party/blink/renderer/modules/ai/language_model_prompt_builder.cc b/third_party/blink/renderer/modules/ai/language_model_prompt_builder.cc
index 32e7b20..b49ecc7 100644
--- a/third_party/blink/renderer/modules/ai/language_model_prompt_builder.cc
+++ b/third_party/blink/renderer/modules/ai/language_model_prompt_builder.cc
@@ -251,13 +251,19 @@
         break;
       }
     }
-    // Multimodal (non-text) input is not supported for the assistant role.
-    if (message->role() == V8LanguageModelMessageRole::Enum::kAssistant &&
-        is_multimodal) {
-      Reject(DOMException::Create(
-          "Multimodal input is not supported for the assistant role.",
-          DOMException::GetErrorName(DOMExceptionCode::kNotSupportedError)));
-      return;
+    if (is_multimodal) {
+      if (!RuntimeEnabledFeatures::AIPromptAPIMultimodalInputEnabled()) {
+        v8::Isolate* isolate = script_state_->GetIsolate();
+        Reject(ScriptValue(isolate, V8ThrowException::CreateTypeError(
+                                        isolate, "Input type not supported")));
+        return;
+      }
+      if (message->role() == V8LanguageModelMessageRole::Enum::kAssistant) {
+        Reject(DOMException::Create(
+            "Multimodal input is not supported for the assistant role.",
+            DOMException::GetErrorName(DOMExceptionCode::kNotSupportedError)));
+        return;
+      }
     }
   }
 
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_storage.cc b/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
index 1800d5d..97d3302 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
+++ b/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
@@ -288,7 +288,8 @@
                                 base::TimeDelta actual_delay =
                                     base::TimeTicks::Now() - start_time;
                                 base::UmaHistogramTimes(
-                                    "ServiceWorkerCache.Cache.Renderer." +
+                                    "ServiceWorkerCache.CacheStorage."
+                                    "Renderer." +
                                         operation_name + ".AblationDelay",
                                     actual_delay);
                               },
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices.cc b/third_party/blink/renderer/modules/mediastream/media_devices.cc
index 63b1a2384..707bae42 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_devices.cc
@@ -476,9 +476,11 @@
 
   // This timeout of base::Seconds(8) is an initial value and based on the data
   // in Media.MediaDevices.GetUserMedia.Latency, it should be iterated upon.
+  // Records the `Media.MediaDevices.GetUserMedia.Result2` histogram.
   auto* resolver = MakeGarbageCollected<
       ScriptPromiseResolverWithTracker<UserMediaRequestResult, MediaStream>>(
       script_state, "Media.MediaDevices.GetUserMedia", base::Seconds(8));
+  resolver->SetResultSuffix("Result2");
   const auto promise = resolver->Promise();
 
   DCHECK(options);  // Guaranteed by the default value in the IDL.
@@ -607,9 +609,11 @@
   // This timeout of base::Seconds(6) is an initial value and based on the data
   // in Media.MediaDevices.GetAllScreensMedia.Latency, it should be iterated
   // upon.
+  // Records the `Media.MediaDevices.GetAllScreensMedia.Result2` histogram.
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolverWithTracker<
       UserMediaRequestResult, IDLSequence<MediaStream>>>(
       script_state, "Media.MediaDevices.GetAllScreensMedia", base::Seconds(6));
+  resolver->SetResultSuffix("Result2");
   auto promise = resolver->Promise();
 
   ExecutionContext* const context = GetExecutionContext();
@@ -661,9 +665,11 @@
 
   // Using timeout of base::Seconds(12) based on the
   // Media.MediaDevices.GetDisplayMedia.Latency values.
+  // Records the `Media.MediaDevices.GetDisplayMedia.Result2` histogram.
   auto* resolver = MakeGarbageCollected<
       ScriptPromiseResolverWithTracker<UserMediaRequestResult, MediaStream>>(
       script_state, "Media.MediaDevices.GetDisplayMedia", base::Seconds(12));
+  resolver->SetResultSuffix("Result2");
   auto promise = resolver->Promise();
 
   if (!window) {
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
index 85f95b7..ee637397 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
@@ -119,6 +119,8 @@
       return "REQUEST_CANCELLED";
     case MediaStreamRequestResult::START_TIMEOUT:
       return "START_TIMEOUT";
+    case MediaStreamRequestResult::PERMISSION_DENIED_BY_USER:
+      return "PERMISSION_DENIED_BY_USER";
     case MediaStreamRequestResult::NUM_MEDIA_REQUEST_RESULTS:
       break;
   }
@@ -291,6 +293,8 @@
       return "Timeout starting video source";
     case MediaStreamRequestResult::CONSTRAINT_NOT_SATISFIED:
       return "Constraint not satisfied";
+    case MediaStreamRequestResult::PERMISSION_DENIED_BY_USER:
+      return "Permission denied by user";
     case MediaStreamRequestResult::NUM_MEDIA_REQUEST_RESULTS:
       break;  // Not a valid enum value.
   }
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_request.cc b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
index 7c17721..f674e9c 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_request.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
@@ -862,6 +862,10 @@
       exception_code = DOMExceptionCode::kNotAllowedError;
       result_enum = UserMediaRequestResult::kNotAllowedError;
       break;
+    case Result::PERMISSION_DENIED_BY_USER:
+      exception_code = DOMExceptionCode::kNotAllowedError;
+      result_enum = UserMediaRequestResult::kNotAllowedByUserError;
+      break;
     case Result::NO_HARDWARE:
       exception_code = DOMExceptionCode::kNotFoundError;
       result_enum = UserMediaRequestResult::kNotFoundError;
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_request.h b/third_party/blink/renderer/modules/mediastream/user_media_request.h
index 4aee660..87025ce 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_request.h
+++ b/third_party/blink/renderer/modules/mediastream/user_media_request.h
@@ -52,6 +52,8 @@
 
 enum class UserMediaRequestType { kUserMedia, kDisplayMedia, kAllScreensMedia };
 
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
 enum class UserMediaRequestResult {
   kOk = 0,
   kTimedOut = 1,
@@ -66,7 +68,8 @@
   kNotSupportedError = 10,
   kInsecureContext = 11,
   kInvalidStateError = 12,
-  kMaxValue = kInvalidStateError
+  kNotAllowedByUserError = 13,
+  kMaxValue = kNotAllowedByUserError
 };
 
 class MODULES_EXPORT UserMediaRequest final
diff --git a/third_party/blink/renderer/modules/payments/payment_entity_logo.idl b/third_party/blink/renderer/modules/payments/payment_entity_logo.idl
new file mode 100644
index 0000000..a1e6f8f
--- /dev/null
+++ b/third_party/blink/renderer/modules/payments/payment_entity_logo.idl
@@ -0,0 +1,9 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/secure-payment-confirmation/#sctn-paymententitylogo-dictionary
+dictionary PaymentEntityLogo {
+    required USVString url;
+    required USVString label;
+};
diff --git a/third_party/blink/renderer/modules/payments/secure_payment_confirmation_helper.cc b/third_party/blink/renderer/modules/payments/secure_payment_confirmation_helper.cc
index cf561130..230b28c7 100644
--- a/third_party/blink/renderer/modules/payments/secure_payment_confirmation_helper.cc
+++ b/third_party/blink/renderer/modules/payments/secure_payment_confirmation_helper.cc
@@ -10,9 +10,10 @@
 #include "third_party/blink/public/mojom/payments/payment_request.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_union_arraybuffer_arraybufferview.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_payment_credential_instrument.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_secure_payment_confirmation_request.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_network_or_issuer_information.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_payment_credential_instrument.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_payment_entity_logo.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_secure_payment_confirmation_request.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/modules/payments/secure_payment_confirmation_type_converter.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -175,6 +176,43 @@
     }
   }
 
+  if (request->hasPaymentEntitiesLogos()) {
+    for (const PaymentEntityLogo* logo : request->paymentEntitiesLogos()) {
+      // The IDL bindings code does not allow the sequence to contain null
+      // entries.
+      CHECK(logo);
+
+      if (logo->url().empty()) {
+        exception_state.ThrowTypeError(
+            "The \"secure-payment-confirmation\" method requires that each "
+            "entry in \"paymentEntitiesLogos\" has a non-empty \"url\" field.");
+        return nullptr;
+      }
+      KURL logo_url(logo->url());
+      if (!logo_url.IsValid()) {
+        exception_state.ThrowTypeError(
+            "The \"secure-payment-confirmation\" method requires that each "
+            "entry in \"paymentEntitiesLogos\" has a valid URL in the \"url\" "
+            "field.");
+        return nullptr;
+      }
+      if (!logo_url.ProtocolIsInHTTPFamily() && !logo_url.ProtocolIsData()) {
+        exception_state.ThrowTypeError(
+            "The \"secure-payment-confirmation\" method requires that each "
+            "entry in \"paymentEntitiesLogos\" has a URL whose scheme is one "
+            "of \"https\", \"http\", or \"data\" in the \"url\" field.");
+        return nullptr;
+      }
+      if (logo->label().empty()) {
+        exception_state.ThrowTypeError(
+            "The \"secure-payment-confirmation\" method requires that each "
+            "entry in \"paymentEntitiesLogos\" has a non-empty \"label\" "
+            "field.");
+        return nullptr;
+      }
+    }
+  }
+
   return mojo::ConvertTo<
       payments::mojom::blink::SecurePaymentConfirmationRequestPtr>(request);
 }
diff --git a/third_party/blink/renderer/modules/payments/secure_payment_confirmation_helper_test.cc b/third_party/blink/renderer/modules/payments/secure_payment_confirmation_helper_test.cc
index 4b1d695..3249f9b9 100644
--- a/third_party/blink/renderer/modules/payments/secure_payment_confirmation_helper_test.cc
+++ b/third_party/blink/renderer/modules/payments/secure_payment_confirmation_helper_test.cc
@@ -18,6 +18,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_authentication_extensions_prf_values.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_network_or_issuer_information.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_payment_credential_instrument.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_payment_entity_logo.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_public_key_credential_parameters.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_secure_payment_confirmation_request.h"
 #include "third_party/blink/renderer/modules/payments/payment_test_helper.h"
@@ -32,6 +33,11 @@
 
 static const uint8_t kPrfInputData[] = {1, 2, 3, 4, 5, 6};
 
+constexpr char kPngImageDataUrl[] =
+    "data:image/png;base64,"
+    "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFElEQVQYlWNk+M/"
+    "wn4GBgYGJAQoAHhgCAh6X4CYAAAAASUVORK5CYII=";
+
 WTF::Vector<uint8_t> CreateVector(base::span<const uint8_t> buffer) {
   WTF::Vector<uint8_t> vector;
   vector.AppendSpan(buffer);
@@ -124,6 +130,14 @@
   issuerInfo->setIcon("https://bank.example/icon.png");
   request->setIssuerInfo(issuerInfo);
 
+  PaymentEntityLogo* logo1 = PaymentEntityLogo::Create(scope.GetIsolate());
+  logo1->setUrl("https://entity1.example/icon.png");
+  logo1->setLabel("Label 1");
+  PaymentEntityLogo* logo2 = PaymentEntityLogo::Create(scope.GetIsolate());
+  logo2->setUrl(kPngImageDataUrl);
+  logo2->setLabel("Label 2");
+  request->setPaymentEntitiesLogos({logo1, logo2});
+
   ScriptValue script_value(scope.GetIsolate(),
                            ToV8Traits<SecurePaymentConfirmationRequest>::ToV8(
                                scope.GetScriptState(), request));
@@ -145,6 +159,11 @@
   EXPECT_EQ(parsed_request->issuer_info->name, "Issuer Name");
   EXPECT_EQ(parsed_request->issuer_info->icon.GetString(),
             "https://bank.example/icon.png");
+
+  // This field is behind a default-disabled flag, however when set directly
+  // into the request as above it will still be present and we can test that the
+  // mojo parsing works correctly.
+  EXPECT_EQ(parsed_request->payment_entities_logos.size(), 2u);
 }
 
 // Test that parsing a SecurePaymentConfirmationRequest with an empty
@@ -591,6 +610,99 @@
             scope.GetExceptionState().CodeAs<ESErrorType>());
 }
 
+// Test that parsing a SecurePaymentConfirmationRequest with a PaymentEntityLogo
+// entry that has an empty url throws.
+TEST(SecurePaymentConfirmationHelperTest, Parse_EmptyPaymentEntityLogoUrl) {
+  test::TaskEnvironment task_environment;
+  V8TestingScope scope;
+  SecurePaymentConfirmationRequest* request =
+      CreateSecurePaymentConfirmationRequest(scope);
+
+  PaymentEntityLogo* logo = PaymentEntityLogo::Create(scope.GetIsolate());
+  logo->setUrl("");
+  logo->setLabel("Label");
+  request->setPaymentEntitiesLogos({logo});
+
+  ScriptValue script_value(scope.GetIsolate(),
+                           ToV8Traits<SecurePaymentConfirmationRequest>::ToV8(
+                               scope.GetScriptState(), request));
+  SecurePaymentConfirmationHelper::ParseSecurePaymentConfirmationData(
+      script_value, *scope.GetExecutionContext(), scope.GetExceptionState());
+  EXPECT_TRUE(scope.GetExceptionState().HadException());
+  EXPECT_EQ(ESErrorType::kTypeError,
+            scope.GetExceptionState().CodeAs<ESErrorType>());
+}
+
+// Test that parsing a SecurePaymentConfirmationRequest with a PaymentEntityLogo
+// entry that has an invalid url throws.
+TEST(SecurePaymentConfirmationHelperTest, Parse_InvalidPaymentEntityLogoUrl) {
+  test::TaskEnvironment task_environment;
+  V8TestingScope scope;
+  SecurePaymentConfirmationRequest* request =
+      CreateSecurePaymentConfirmationRequest(scope);
+
+  PaymentEntityLogo* logo = PaymentEntityLogo::Create(scope.GetIsolate());
+  logo->setUrl("thisisnotaurl");
+  logo->setLabel("Label");
+  request->setPaymentEntitiesLogos({logo});
+
+  ScriptValue script_value(scope.GetIsolate(),
+                           ToV8Traits<SecurePaymentConfirmationRequest>::ToV8(
+                               scope.GetScriptState(), request));
+  SecurePaymentConfirmationHelper::ParseSecurePaymentConfirmationData(
+      script_value, *scope.GetExecutionContext(), scope.GetExceptionState());
+  EXPECT_TRUE(scope.GetExceptionState().HadException());
+  EXPECT_EQ(ESErrorType::kTypeError,
+            scope.GetExceptionState().CodeAs<ESErrorType>());
+}
+
+// Test that parsing a SecurePaymentConfirmationRequest with a PaymentEntityLogo
+// entry that has a url with a disallowed protocol throws.
+TEST(SecurePaymentConfirmationHelperTest,
+     Parse_DisallowedProtocolPaymentEntityLogoUrl) {
+  test::TaskEnvironment task_environment;
+  V8TestingScope scope;
+  SecurePaymentConfirmationRequest* request =
+      CreateSecurePaymentConfirmationRequest(scope);
+
+  PaymentEntityLogo* logo = PaymentEntityLogo::Create(scope.GetIsolate());
+  logo->setUrl("blob://blob.foo.com/logo.png");
+  logo->setLabel("Label");
+  request->setPaymentEntitiesLogos({logo});
+
+  ScriptValue script_value(scope.GetIsolate(),
+                           ToV8Traits<SecurePaymentConfirmationRequest>::ToV8(
+                               scope.GetScriptState(), request));
+  SecurePaymentConfirmationHelper::ParseSecurePaymentConfirmationData(
+      script_value, *scope.GetExecutionContext(), scope.GetExceptionState());
+  EXPECT_TRUE(scope.GetExceptionState().HadException());
+  EXPECT_EQ(ESErrorType::kTypeError,
+            scope.GetExceptionState().CodeAs<ESErrorType>());
+}
+
+// Test that parsing a SecurePaymentConfirmationRequest with a PaymentEntityLogo
+// entry that has an empty label throws.
+TEST(SecurePaymentConfirmationHelperTest, Parse_EmptyPaymentEntityLogoLabel) {
+  test::TaskEnvironment task_environment;
+  V8TestingScope scope;
+  SecurePaymentConfirmationRequest* request =
+      CreateSecurePaymentConfirmationRequest(scope);
+
+  PaymentEntityLogo* logo = PaymentEntityLogo::Create(scope.GetIsolate());
+  logo->setUrl("https://entity.example/icon.png");
+  logo->setLabel("");
+  request->setPaymentEntitiesLogos({logo});
+
+  ScriptValue script_value(scope.GetIsolate(),
+                           ToV8Traits<SecurePaymentConfirmationRequest>::ToV8(
+                               scope.GetScriptState(), request));
+  SecurePaymentConfirmationHelper::ParseSecurePaymentConfirmationData(
+      script_value, *scope.GetExecutionContext(), scope.GetExceptionState());
+  EXPECT_TRUE(scope.GetExceptionState().HadException());
+  EXPECT_EQ(ESErrorType::kTypeError,
+            scope.GetExceptionState().CodeAs<ESErrorType>());
+}
+
 // Test that parsing a SecurePaymentConfirmationRequest converts the browser
 // bound public key credential parameters.
 TEST(SecurePaymentConfirmationHelperTest, Parse_BrowserBroundPubKeyCredParams) {
diff --git a/third_party/blink/renderer/modules/payments/secure_payment_confirmation_request.idl b/third_party/blink/renderer/modules/payments/secure_payment_confirmation_request.idl
index d9e6a5d..453e2fb 100644
--- a/third_party/blink/renderer/modules/payments/secure_payment_confirmation_request.idl
+++ b/third_party/blink/renderer/modules/payments/secure_payment_confirmation_request.idl
@@ -24,8 +24,16 @@
     // were to launch this we should find a non-card specific way to encode
     // this information in the SecurePaymentConfirmationRequest, or better
     // encapsulate it into a single sub-dictionary.
+    //
+    // Note: These parameters are deprecated in favour of
+    // |paymentEntitiesLogos|, but are being kept for now to support partner
+    // testing while the updated API is in development.
     [RuntimeEnabled=SecurePaymentConfirmationNetworkAndIssuerIcons] NetworkOrIssuerInformation networkInfo;
     [RuntimeEnabled=SecurePaymentConfirmationNetworkAndIssuerIcons] NetworkOrIssuerInformation issuerInfo;
+
+    // A list of logos representing entities that are facilitating the payment
+    // that this SPC call is for.
+    [RuntimeEnabled=SecurePaymentConfirmationUxRefresh] sequence<PaymentEntityLogo> paymentEntitiesLogos;
 };
 
 dictionary NetworkOrIssuerInformation {
diff --git a/third_party/blink/renderer/modules/payments/secure_payment_confirmation_type_converter.cc b/third_party/blink/renderer/modules/payments/secure_payment_confirmation_type_converter.cc
index 0d54b93f..276f424 100644
--- a/third_party/blink/renderer/modules/payments/secure_payment_confirmation_type_converter.cc
+++ b/third_party/blink/renderer/modules/payments/secure_payment_confirmation_type_converter.cc
@@ -10,8 +10,9 @@
 #include "third_party/blink/public/mojom/webauthn/authenticator.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_union_arraybuffer_arraybufferview.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_authentication_extensions_client_inputs.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_payment_credential_instrument.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_network_or_issuer_information.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_payment_credential_instrument.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_payment_entity_logo.h"
 #include "third_party/blink/renderer/modules/credentialmanagement/credential_manager_type_converters.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -66,6 +67,12 @@
             blink::KURL(input->issuerInfo()->icon()));
   }
 
+  if (input->hasPaymentEntitiesLogos()) {
+    output->payment_entities_logos =
+        ConvertTo<WTF::Vector<payments::mojom::blink::PaymentEntityLogoPtr>>(
+            input->paymentEntitiesLogos());
+  }
+
   if (input->hasBrowserBoundPubKeyCredParams()) {
     output->browser_bound_pub_key_cred_params = ConvertTo<
         WTF::Vector<blink::mojom::blink::PublicKeyCredentialParametersPtr>>(
@@ -77,4 +84,11 @@
   return output;
 }
 
+payments::mojom::blink::PaymentEntityLogoPtr TypeConverter<
+    payments::mojom::blink::PaymentEntityLogoPtr,
+    blink::PaymentEntityLogo*>::Convert(const blink::PaymentEntityLogo* input) {
+  return payments::mojom::blink::PaymentEntityLogo::New(
+      blink::KURL(input->url()), input->label());
+}
+
 }  // namespace mojo
diff --git a/third_party/blink/renderer/modules/payments/secure_payment_confirmation_type_converter.h b/third_party/blink/renderer/modules/payments/secure_payment_confirmation_type_converter.h
index f6914e03..3c5a58e 100644
--- a/third_party/blink/renderer/modules/payments/secure_payment_confirmation_type_converter.h
+++ b/third_party/blink/renderer/modules/payments/secure_payment_confirmation_type_converter.h
@@ -19,6 +19,13 @@
       const blink::SecurePaymentConfirmationRequest* input);
 };
 
+template <>
+struct TypeConverter<payments::mojom::blink::PaymentEntityLogoPtr,
+                     blink::PaymentEntityLogo*> {
+  static payments::mojom::blink::PaymentEntityLogoPtr Convert(
+      const blink::PaymentEntityLogo* input);
+};
+
 }  // namespace mojo
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_SECURE_PAYMENT_CONFIRMATION_TYPE_CONVERTER_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc
index 7281405..fd52dfa9 100644
--- a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc
+++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc
@@ -869,9 +869,9 @@
       (candidate->SdpMLineIndex() ? String::Number(*candidate->SdpMLineIndex())
                                   : "null") +
       ", candidate: " + String(candidate->Candidate()) +
-      (!url.IsNull() ? ", url: " + url : String()) +
-      (!relay_protocol.IsNull() ? ", relayProtocol: " + relay_protocol
-                                : String());
+      (!url.empty() ? ", url: " + url : String()) +
+      (!relay_protocol.empty() ? ", relayProtocol: " + relay_protocol
+                               : String());
 
   // OnIceCandidate always succeeds as it's a callback from the browser.
   DCHECK(source != kSourceLocal || succeeded);
diff --git a/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.cc b/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.cc
index 9fd9bd9..678ef69 100644
--- a/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.cc
+++ b/third_party/blink/renderer/modules/webcodecs/fuzzer_utils.cc
@@ -91,8 +91,8 @@
     const wc_fuzzer::ConfigureVideoDecoder& proto) {
   auto* config = VideoDecoderConfig::Create();
   config->setCodec(proto.codec().c_str());
-  DOMArrayBuffer* data_copy = DOMArrayBuffer::Create(
-      proto.description().data(), proto.description().size());
+  DOMArrayBuffer* data_copy =
+      DOMArrayBuffer::Create(base::as_byte_span(proto.description()));
   config->setDescription(
       MakeGarbageCollected<AllowSharedBufferSource>(data_copy));
   return config;
@@ -105,8 +105,8 @@
   config->setSampleRate(proto.sample_rate());
   config->setNumberOfChannels(proto.number_of_channels());
 
-  DOMArrayBuffer* data_copy = DOMArrayBuffer::Create(
-      proto.description().data(), proto.description().size());
+  DOMArrayBuffer* data_copy =
+      DOMArrayBuffer::Create(base::as_byte_span(proto.description()));
   config->setDescription(
       MakeGarbageCollected<AllowSharedBufferSource>(data_copy));
 
@@ -358,7 +358,7 @@
     ScriptState* script_state,
     const wc_fuzzer::EncodedVideoChunk& proto) {
   auto* data = MakeGarbageCollected<AllowSharedBufferSource>(
-      DOMArrayBuffer::Create(proto.data().data(), proto.data().size()));
+      DOMArrayBuffer::Create(base::as_byte_span(proto.data())));
 
   auto* init = EncodedVideoChunkInit::Create();
   init->setTimestamp(proto.timestamp());
@@ -376,7 +376,7 @@
     ScriptState* script_state,
     const wc_fuzzer::EncodedAudioChunk& proto) {
   auto* data = MakeGarbageCollected<AllowSharedBufferSource>(
-      DOMArrayBuffer::Create(proto.data().data(), proto.data().size()));
+      DOMArrayBuffer::Create(base::as_byte_span(proto.data())));
 
   auto* init = EncodedAudioChunkInit::Create();
   init->setTimestamp(proto.timestamp());
diff --git a/third_party/blink/renderer/modules/webcodecs/image_decoder_fuzzer.cc b/third_party/blink/renderer/modules/webcodecs/image_decoder_fuzzer.cc
index 140bad1..14f5c49 100644
--- a/third_party/blink/renderer/modules/webcodecs/image_decoder_fuzzer.cc
+++ b/third_party/blink/renderer/modules/webcodecs/image_decoder_fuzzer.cc
@@ -109,8 +109,8 @@
   Persistent<ImageDecoderInit> image_decoder_init =
       MakeGarbageCollected<ImageDecoderInit>();
   image_decoder_init->setType(proto.config().type().c_str());
-  Persistent<DOMArrayBuffer> data_copy = DOMArrayBuffer::Create(
-      proto.config().data().data(), proto.config().data().size());
+  Persistent<DOMArrayBuffer> data_copy =
+      DOMArrayBuffer::Create(base::as_byte_span(proto.config().data()));
   image_decoder_init->setData(
       MakeGarbageCollected<V8ImageBufferSource>(data_copy));
   image_decoder_init->setColorSpaceConversion(ToColorSpaceConversion(
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc b/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc
index e06bc88..a6c4f51 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc
@@ -171,8 +171,13 @@
 
   // Keep mailbox texture alive until callback returns.
   auto* callback = BindWGPUOnceCallback(
+#if defined(WGPU_BREAKING_CHANGE_QUEUE_WORK_DONE_CALLBACK_MESSAGE)
+      [](scoped_refptr<WebGPUMailboxTexture> mailbox_texture,
+         wgpu::QueueWorkDoneStatus, wgpu::StringView) {},
+#else   // defined(WGPU_BREAKING_CHANGE_QUEUE_WORK_DONE_CALLBACK_MESSAGE)
       [](scoped_refptr<WebGPUMailboxTexture> mailbox_texture,
          wgpu::QueueWorkDoneStatus) {},
+#endif  // defined(WGPU_BREAKING_CHANGE_QUEUE_WORK_DONE_CALLBACK_MESSAGE)
       std::move(mailbox_texture));
 
   device()->queue()->GetHandle().OnSubmittedWorkDone(
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_queue.cc b/third_party/blink/renderer/modules/webgpu/gpu_queue.cc
index cd9a4cb..1b5b7e6 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_queue.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_queue.cc
@@ -436,6 +436,25 @@
   UseCounter::Count(execution_context, WebFeature::kWebGPUQueueSubmit);
 }
 
+#if defined(WGPU_BREAKING_CHANGE_QUEUE_WORK_DONE_CALLBACK_MESSAGE)
+void OnWorkDoneCallback(ScriptPromiseResolver<IDLUndefined>* resolver,
+                        wgpu::QueueWorkDoneStatus status,
+                        wgpu::StringView message) {
+  switch (status) {
+    case wgpu::QueueWorkDoneStatus::Success:
+      resolver->Resolve();
+      break;
+    case wgpu::QueueWorkDoneStatus::Error:
+      resolver->RejectWithDOMException(DOMExceptionCode::kOperationError,
+                                       String::FromUTF8(message));
+      break;
+    case wgpu::QueueWorkDoneStatus::CallbackCancelled:
+      resolver->RejectWithDOMException(DOMExceptionCode::kOperationError,
+                                       String::FromUTF8(message));
+      break;
+  }
+}
+#else   // defined(WGPU_BREAKING_CHANGE_QUEUE_WORK_DONE_CALLBACK_MESSAGE)
 void OnWorkDoneCallback(ScriptPromiseResolver<IDLUndefined>* resolver,
                         wgpu::QueueWorkDoneStatus status) {
   switch (status) {
@@ -454,6 +473,7 @@
       break;
   }
 }
+#endif  // defined(WGPU_BREAKING_CHANGE_QUEUE_WORK_DONE_CALLBACK_MESSAGE)
 
 ScriptPromise<IDLUndefined> GPUQueue::onSubmittedWorkDone(
     ScriptState* script_state) {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 27d8e0d..b973895a 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -352,6 +352,8 @@
         "Linux": "experimental",
         "default": "",
       },
+      base_feature_status: "enabled",
+      copied_from_base_feature_if: "overridden",
     },
     {
       // Gates access to the responseConstraint enhancement for "AIPromptAPI".
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/DEPS b/third_party/blink/renderer/platform/scheduler/main_thread/DEPS
index 8f8292bd..5bf2455 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/DEPS
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/DEPS
@@ -16,11 +16,11 @@
     "+base/task/sequence_manager/enqueue_order.h"
   ],
   "main_thread_scheduler_impl.cc": [
-    "+base/android/pre_freeze_background_memory_trimmer.h",
+    "+base/android/self_compaction_manager.h",
     "+components/performance_manager/scenario_api/performance_scenarios.h"
   ],
   "memory_purge_manager.cc": [
-    "+base/android/pre_freeze_background_memory_trimmer.h"
+    "+base/android/self_compaction_manager.h"
   ],
   "frame_scheduler_impl.h": [
     "+net/base/request_priority.h"
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
index d60b592..c7c326c 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -68,7 +68,7 @@
 #include "v8/include/v8.h"
 
 #if BUILDFLAG(IS_ANDROID)
-#include "base/android/pre_freeze_background_memory_trimmer.h"
+#include "base/android/self_compaction_manager.h"
 #endif
 
 namespace base {
@@ -2269,8 +2269,8 @@
 void MainThreadSchedulerImpl::OnPageFrozen(
     base::MemoryReductionTaskContext called_from) {
 #if BUILDFLAG(IS_ANDROID)
-  base::android::PreFreezeBackgroundMemoryTrimmer::
-      SetOnStartSelfCompactionCallback(base::BindRepeating(
+  base::android::SelfCompactionManager::SetOnStartSelfCompactionCallback(
+      base::BindRepeating(
           [](scoped_refptr<base::SequencedTaskRunner> task_runner,
              base::WeakPtr<MainThreadSchedulerImpl> s) {
             task_runner->PostTask(
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager.cc b/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager.cc
index 010beb4..65b8108 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager.cc
@@ -7,7 +7,7 @@
 #include "build/build_config.h"
 
 #if BUILDFLAG(IS_ANDROID)
-#include "base/android/pre_freeze_background_memory_trimmer.h"
+#include "base/android/self_compaction_manager.h"
 #endif
 #include "base/feature_list.h"
 #include "base/memory/memory_pressure_listener.h"
@@ -112,9 +112,9 @@
 #if BUILDFLAG(IS_ANDROID)
   // Cancel a pending compaction, since we are resuming now, and will
   // presumably touch most of that memory soon.
-  base::android::PreFreezeBackgroundMemoryTrimmer::MaybeCancelCompaction(
-      base::android::PreFreezeBackgroundMemoryTrimmer::
-          CompactCancellationReason::kPageResumed);
+  base::android::SelfCompactionManager::MaybeCancelCompaction(
+      base::android::SelfCompactionManager::CompactCancellationReason::
+          kPageResumed);
 #endif
 }
 
@@ -172,7 +172,7 @@
   if (AreAllPagesFrozen()) {
     base::MemoryPressureListener::SetNotificationsSuppressed(true);
 #if BUILDFLAG(IS_ANDROID)
-    base::android::PreFreezeBackgroundMemoryTrimmer::OnRunningCompact();
+    base::android::SelfCompactionManager::OnRunningCompact();
 #endif
   }
 
diff --git a/third_party/blink/renderer/platform/wtf/text/wtf_string.h b/third_party/blink/renderer/platform/wtf/text/wtf_string.h
index 6191f99..c077898 100644
--- a/third_party/blink/renderer/platform/wtf/text/wtf_string.h
+++ b/third_party/blink/renderer/platform/wtf/text/wtf_string.h
@@ -180,10 +180,6 @@
     return impl_->Bytes();
   }
 
-  // Return characters8() or characters16() depending on CharacterType.
-  template <typename CharacterType>
-  inline const CharacterType* GetCharacters() const;
-
   bool Is8Bit() const { return impl_->Is8Bit(); }
 
   [[nodiscard]] std::string Ascii() const;
diff --git a/third_party/blink/tools/blinkpy/common/config/builders.json b/third_party/blink/tools/blinkpy/common/config/builders.json
index f689298..844aaae 100644
--- a/third_party/blink/tools/blinkpy/common/config/builders.json
+++ b/third_party/blink/tools/blinkpy/common/config/builders.json
@@ -81,30 +81,6 @@
         },
         "is_try_builder": true
     },
-    "mac11.0-blink-rel": {
-        "main": "tryserver.blink",
-        "port_name": "mac-mac11",
-        "specifiers": ["Mac11", "Release"],
-        "steps": {
-            "blink_web_tests": {},
-            "blink_wpt_tests": {},
-            "chrome_wpt_tests": {},
-            "headless_shell_wpt_tests": {}
-        },
-        "is_try_builder": true
-    },
-    "mac11.0.arm64-blink-rel": {
-        "main": "tryserver.blink",
-        "port_name": "mac-mac11-arm64",
-        "specifiers": ["Mac11-arm64", "Release"],
-        "steps": {
-            "blink_web_tests": {},
-            "blink_wpt_tests": {},
-            "chrome_wpt_tests": {},
-            "headless_shell_wpt_tests": {}
-        },
-        "is_try_builder": true
-    },
     "mac12.0-blink-rel": {
         "main": "tryserver.blink",
         "port_name": "mac-mac12",
diff --git a/third_party/blink/tools/blinkpy/wpt_tests/logging.py b/third_party/blink/tools/blinkpy/wpt_tests/logging.py
index 5d44c63a..80b0c8d 100644
--- a/third_party/blink/tools/blinkpy/wpt_tests/logging.py
+++ b/third_party/blink/tools/blinkpy/wpt_tests/logging.py
@@ -12,11 +12,14 @@
 
 from datetime import datetime
 import logging
+from typing import Optional
 
 from blinkpy.common import path_finder
+from blinkpy.wpt_tests.test_loader import wpt_url_to_blink_test
 
 path_finder.bootstrap_wpt_imports()
 import mozlog
+from mozlog.formatters.base import BaseFormatter
 
 
 class GroupingFormatter(mozlog.formatters.GroupingFormatter):
@@ -33,15 +36,13 @@
         self._start = datetime.now()
 
     def get_test_name_output(self, subsuite, test_name):
-        if not test_name.startswith('/wpt_internal/'):
-            test_name = '/external/wpt' + test_name
-        return f'virtual/{subsuite}{test_name}' if subsuite else test_name[1:]
+        test_name = wpt_url_to_blink_test(test_name)
+        return f'virtual/{subsuite}/{test_name}' if subsuite else test_name
 
     def log(self, data):
-        timestamp = datetime.now().isoformat(sep=' ', timespec='milliseconds')
         # Place mandatory fields first so that logs are vertically aligned as
         # much as possible.
-        message = f'{timestamp} {data["level"]} {data["message"]}'
+        message = f'{format_timestamp()} {data["level"]} {data["message"]}'
         if 'stack' in data:
             message = f'{message}\n{data["stack"]}'
         return self.generate_output(text=message + '\n')
@@ -74,6 +75,20 @@
         super().__init__(*args, **kwargs)
         self.reset_before_suite = reset_before_suite
 
+    def __call__(self, data):
+        self.summary(data)
+
+        # pylint: disable=bad-super-call; intentional call to grandparent class
+        output = super(BaseFormatter, self).__call__(data)
+        if output is None:
+            return
+
+        timestamp = self.color_formatter.time(format_timestamp())
+        thread = data.get('thread', '')
+        if thread:
+            thread += ' '
+        return f'{timestamp} {thread}{output}\n'
+
     def suite_start(self, data) -> str:
         output = super().suite_start(data)
         if self.reset_before_suite:
@@ -87,6 +102,33 @@
             self.summary.current['harness_errors'].clear()
         return output
 
+    def process_output(self, data) -> Optional[str]:
+        if not self.verbose:
+            return None
+        return super().process_output(data)
+
+    def test_start(self, data) -> Optional[str]:
+        # Log the test ID as part of `test_end` so that results from different
+        # tests aren't interleaved confusingly.
+        return None
+
+    def test_end(self, data) -> Optional[str]:
+        test_id = self._get_test_id(data)
+        # We need this string replacement hack because the base formatter
+        # doesn't have an overridable hook for this.
+        # TODO(web-platform-tests/wpt#48948): Fork `MachFormatter` and write the
+        # desired format.
+        return super().test_end(data).replace('TEST_END', test_id, 1)
+
+    def _get_test_id(self, data) -> str:
+        test_name = wpt_url_to_blink_test(data['test'])
+        subsuite = data.get('subsuite')
+        return f'virtual/{subsuite}/{test_name}' if subsuite else test_name
+
+
+def format_timestamp() -> str:
+    return datetime.now().isoformat(sep=' ', timespec='milliseconds')
+
 
 class StructuredLogAdapter(logging.Handler):
 
diff --git a/third_party/blink/tools/blinkpy/wpt_tests/wpt_adapter.py b/third_party/blink/tools/blinkpy/wpt_tests/wpt_adapter.py
index 1158c43..e69ceba8 100644
--- a/third_party/blink/tools/blinkpy/wpt_tests/wpt_adapter.py
+++ b/third_party/blink/tools/blinkpy/wpt_tests/wpt_adapter.py
@@ -203,19 +203,16 @@
         if verbose_level >= 1:
             runner_options.log_mach = '-'
             runner_options.log_mach_level = 'info'
-            runner_options.log_mach_verbose = True
         if verbose_level >= 2:
-            runner_options.log_mach_level = 'debug'
+            # Log individual subtest results and `chromedriver` process output.
+            runner_options.log_mach_verbose = True
         if verbose_level >= 3:
+            # Trace test runner and testdriver events.
+            runner_options.log_mach_level = 'debug'
+            # Trace individual CDP requests and events.
             runner_options.webdriver_args.append('--verbose')
         else:
-            # Disable all `chromedriver` logs except from `chrome_launcher.cc`,
-            # which logs the `chrome` command that `WPTResultsProcessor` will
-            # extract.
-            runner_options.webdriver_args.extend([
-                '--log-level=INFO',
-                '--vmodule=chrome_launcher=0,*/chrome/test/chromedriver/*=-1',
-            ])
+            runner_options.webdriver_args.append('--log-level=WARNING')
 
         if self.options.use_upstream_wpt:
             runner_options.log_wptreport = [
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 9f60bf1..500a915 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1444,11 +1444,6 @@
 # Failing on Intel Mac11
 crbug.com/379233396 [ Mac11 ] external/wpt/ai/translator/* [ Failure ]
 
-# Failing (PRECONDITION_FAILED) without blink::features::kAIPromptAPIMultimodalInput flag
-crbug.com/419853199 wpt_internal/ai/language-model-api-availability-available-multimodal.https.window.html [ Failure Pass ]
-crbug.com/419853199 wpt_internal/ai/language-model-api-create-multimodal.https.window.html [ Failure Pass ]
-crbug.com/419853199 wpt_internal/ai/language-model-api-prompt-multimodal.https.window.html [ Failure Pass ]
-
 ### sheriff 2018-05-28
 
 crbug.com/767269 [ Win ] inspector-protocol/layout-fonts/cjk-ideograph-fallback-by-lang.js [ Failure Pass ]
@@ -2770,6 +2765,8 @@
 crbug.com/413411328 external/wpt/css/css-values/urls/referrer-policy/unsafe-url/url-image-referrerpolicy-same-origin.sub.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+[ Mac14 ] external/wpt/html/cross-origin-opener-policy/historical/popup-same-site-with-same-site.https.html [ Crash ]
+[ Mac12 ] external/wpt/html/cross-origin-opener-policy/historical/popup-same-site-with-same-site.https.html [ Crash ]
 crbug.com/420198856 [ Win10.20h2 ] virtual/close-watcher/external/wpt/close-watcher/iframes/dialog-same-origin-ynn.html [ Skip Timeout ]
 crbug.com/419216929 [ Win10.20h2 ] virtual/close-watcher/external/wpt/close-watcher/iframes/dialog-same-origin-ynyn.html [ Skip Timeout ]
 crbug.com/419216929 [ Mac12 ] virtual/close-watcher/external/wpt/close-watcher/iframes/dialog-same-origin-ynyn.html [ Skip Timeout ]
@@ -9389,7 +9386,7 @@
 crbug.com/418362694 [ Linux ] external/wpt/geolocation/enabled-by-permission-policy-attribute-redirect-on-load.https.sub.html [ Crash Timeout ]
 
 # Susceptible to subtle timing flakes
-crbug.com/415870039 external/wpt/web-animations/interfaces/Animation/finished.html [ Pass Failure ]
+crbug.com/415870039 external/wpt/web-animations/interfaces/Animation/finished.html [ Failure Pass ]
 
 # Skipped due to feature implementation in progress
 crbug.com/420393952 external/wpt/html/semantics/permission-element/quirks-mode-no-height-is-still-bounded.tentative.html [ Failure Skip ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index a7b31bf..caea408 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -6964,13 +6964,6 @@
        {}
       ]
      ],
-     "indent-outdent-after-closing-editable-dialog-element.html": [
-      "7f73de048d714c99ce47ae4da61d7128e53216e8",
-      [
-       null,
-       {}
-      ]
-     ],
      "insert-image-with-joining-header-element-and-body.html": [
       "cf5b2df225be06c833fea6d3bf2ceab6b1231018",
       [
@@ -86374,7 +86367,7 @@
         ]
        ],
        "corner-shape-render-fuzzy.html": [
-        "12cd2546bf484282a8cab7163c610b5b88d0b9f8",
+        "2d4b56f831b91eb70fd44abc02000213664a480b",
         [
          "css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html?border-radius=30%&corner-shape=superellipse(-1.5)&box-shadow=10px%2010px%200%2010px%20black",
          [
@@ -86636,10 +86629,10 @@
          }
         ],
         [
-         "css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html?corner-shape=superellipse(0.8)&border-radius=40px&border-width=10px&border-left-color=purple",
+         "css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html?corner-shape=superellipse(0.8)&border-radius=40px&border-width=10px",
          [
           [
-           "/css/css-borders/tentative/corner-shape/corner-shape-any-ref.html?corner-shape=superellipse(0.8)&border-radius=40px&border-width=10px&border-left-color=purple",
+           "/css/css-borders/tentative/corner-shape/corner-shape-any-ref.html?corner-shape=superellipse(0.8)&border-radius=40px&border-width=10px",
            "=="
           ]
          ],
@@ -86871,7 +86864,7 @@
         ]
        ],
        "corner-shape-render-precise.html": [
-        "5293589222a3f2d918bdbfeecd11280f667578c2",
+        "4a0c575b3b7cef4cbfb1dea4efc53ec40e01ef13",
         [
          "css/css-borders/tentative/corner-shape/corner-shape-render-precise.html?border-radius=50%&corner-shape=bevel&box-shadow=10px%2010px%200%2010px%20black",
          [
@@ -87055,6 +87048,32 @@
          }
         ],
         [
+         "css/css-borders/tentative/corner-shape/corner-shape-render-precise.html?corner-shape=notch&border-radius=30px&border-width=30px",
+         [
+          [
+           "/css/css-borders/tentative/corner-shape/corner-shape-any-ref.html?corner-shape=notch&border-radius=30px&border-width=30px",
+           "=="
+          ]
+         ],
+         {
+          "fuzzy": [
+           [
+            null,
+            [
+             [
+              0,
+              180
+             ],
+             [
+              0,
+              350
+             ]
+            ]
+           ]
+          ]
+         }
+        ],
+        [
          "css/css-borders/tentative/corner-shape/corner-shape-render-precise.html?corner-shape=square&border-bottom-left-radius=5px",
          [
           [
@@ -87263,10 +87282,10 @@
          }
         ],
         [
-         "css/css-borders/tentative/corner-shape/corner-shape-render-precise.html?corner-top-left-shape=bevel&border-width=10px&border-color=black",
+         "css/css-borders/tentative/corner-shape/corner-shape-render-precise.html?corner-top-left-shape=bevel&border-width=10px",
          [
           [
-           "/css/css-borders/tentative/corner-shape/corner-shape-any-ref.html?corner-top-left-shape=bevel&border-width=10px&border-color=black",
+           "/css/css-borders/tentative/corner-shape/corner-shape-any-ref.html?corner-top-left-shape=bevel&border-width=10px",
            "=="
           ]
          ],
@@ -87393,10 +87412,10 @@
          }
         ],
         [
-         "css/css-borders/tentative/corner-shape/corner-shape-render-precise.html?corner-top-right-shape=bevel&border-width=10px&border-color=black",
+         "css/css-borders/tentative/corner-shape/corner-shape-render-precise.html?corner-top-right-shape=bevel&border-width=10px",
          [
           [
-           "/css/css-borders/tentative/corner-shape/corner-shape-any-ref.html?corner-top-right-shape=bevel&border-width=10px&border-color=black",
+           "/css/css-borders/tentative/corner-shape/corner-shape-any-ref.html?corner-top-right-shape=bevel&border-width=10px",
            "=="
           ]
          ],
@@ -159351,6 +159370,37 @@
      ]
     },
     "css-masking": {
+     "animations": {
+      "clip-path-interpolation-shape-arc-direction-agnostic-radius.html": [
+       "aa91e1828a7841c4036f6c2d15639ebd2f1bf4e4",
+       [
+        null,
+        [
+         [
+          "/css/css-masking/animations/clip-path-interpolation-shape-arc-direction-agnostic-radius-ref.html",
+          "=="
+         ]
+        ],
+        {
+         "fuzzy": [
+          [
+           null,
+           [
+            [
+             0,
+             10
+            ],
+            [
+             0,
+             360
+            ]
+           ]
+          ]
+         ]
+        }
+       ]
+      ]
+     },
      "clip": {
       "clip-absolute-positioned-001.html": [
        "c5b0d9001c442012aea33142d47ca1a8d68e319e",
@@ -227031,6 +227081,19 @@
         {}
        ]
       ],
+      "individual-transform-3.html": [
+       "2c81cb12156134ee8deca6abf0043848ac8bc750",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-200px-square.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "stacking-context-001.html": [
        "1a754c5d70b607396ffe2db1d04f2294aeca1041",
        [
@@ -232085,6 +232148,19 @@
        {}
       ]
      ],
+     "transform-matrix-009.html": [
+      "81f04db0d103202180aba2625205643c376483af",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-200px-square.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "transform-origin": {
       "svg-origin-length-001.html": [
        "2f2256361cadd4f69aa08fd775a4305219a41fdd",
@@ -255296,6 +255372,35 @@
        }
       ]
      ],
+     "inline-child-with-composited-filter.html": [
+      "36ba9803e1edb2c87d8d3e57b5f2589d349df964",
+      [
+       null,
+       [
+        [
+         "/css/css-view-transitions/inline-child-with-filter-ref.html",
+         "=="
+        ]
+       ],
+       {
+        "fuzzy": [
+         [
+          null,
+          [
+           [
+            0,
+            2
+           ],
+           [
+            0,
+            2400
+           ]
+          ]
+         ]
+        ]
+       }
+      ]
+     ],
      "inline-child-with-filter.html": [
       "61f0f1f6a8c389cd7298c56d8c2e35c3f101027b",
       [
@@ -303826,6 +303931,34 @@
         {}
        ]
       ],
+      "permission-icon": {
+       "icon-hidden-reftest.html": [
+        "79055da1badfc827e5cc02ed3be7db3842b49855",
+        [
+         null,
+         [
+          [
+           "/html/semantics/permission-element/permission-icon/standard-location-permission-element-ref.html",
+           "!="
+          ]
+         ],
+         {}
+        ]
+       ],
+       "icon-unique-per-type-reftest.html": [
+        "d51b1c4d398a42c8e59f047c0e457c533eae16ee",
+        [
+         null,
+         [
+          [
+           "/html/semantics/permission-element/permission-icon/standard-location-permission-element-ref.html",
+           "!="
+          ]
+         ],
+         {}
+        ]
+       ]
+      },
       "pseudo-elements-in-div.tentative.html": [
        "24a2be07fabae34fd969fa89c233b2a209c0c08f",
        [
@@ -336136,11 +336269,11 @@
        ],
        "resources": {
         "corner-shape.js": [
-         "4757a43ad051f42a88ddefeba344bcea0b9a0149",
+         "c08a95c7d7511e84eb92015d13578e23ad2f2ec5",
          []
         ],
         "corner-utils.js": [
-         "ad3b235addff11e418d78e372b20c09a2ebd4a19",
+         "b6f329e82484f14f853c999dbd99a15771db1e8d",
          []
         ],
         "resolve-corner-style.js": [
@@ -355815,6 +355948,10 @@
        "758ef35275eeacc96b6e584f672f86c4b170e0e1",
        []
       ],
+      "clip-path-interpolation-shape-arc-direction-agnostic-radius-ref.html": [
+       "2869d38a982b23d72ae49543d16d01bda6f28b21",
+       []
+      ],
       "mask-border-outset-composition-expected.txt": [
        "4bba8f7a629ac8b69ed57c62b538575248620c2a",
        []
@@ -360397,6 +360534,10 @@
       ]
      },
      "overlay": {
+      "WEB_FEATURES.yml": [
+       "a1a4402ee421efa24e9b02a2337c90812759a4e2",
+       []
+      ],
       "green-ref.html": [
        "bef7405e96f8181f88fb073ebd212b4af6382e33",
        []
@@ -374622,6 +374763,10 @@
       "bf99b25f76b176520715a245ef3abf01258fdc5a",
       []
      ],
+     "inline-child-with-composited-filter-ref.html": [
+      "9dd26f2c3b1afb49d60bedb5e721dcb1f193d423",
+      []
+     ],
      "inline-child-with-filter-ref.html": [
       "44a41f1bf93366e06f2eae0cbfcd4acb126d192f",
       []
@@ -381279,7 +381424,7 @@
       []
      ],
      "idlharness.window-expected.txt": [
-      "b5b3128599152fc8361e9e39df200376c012e7c8",
+      "73b50e7884b31d31be24e60058480c17750b9fbe",
       []
      ],
      "initial-about-blank.window-expected.txt": [
@@ -406445,6 +406590,12 @@
        "8b48bb93febed1c7fd88f62fe747b3379b349e22",
        []
       ],
+      "permission-icon": {
+       "standard-location-permission-element-ref.html": [
+        "15ffe751c51b3f8caeaa8b93f1286a3950c9a815",
+        []
+       ]
+      },
       "pseudo-elements-in-div-ref.html": [
        "8e6267f9aa350333cef620d248dfce40b85b43e2",
        []
@@ -411620,7 +411771,7 @@
        []
       ],
       "OWNERS": [
-       "dee5bb0f00575c0ca7226355c1adbc5131914db4",
+       "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
        []
       ],
       "iframeChild.html": [
@@ -412715,6 +412866,10 @@
      "6f93db15a74e052913a277e5130226280a3f9311",
      []
     ],
+    "scoped-custom-elements-registry.idl": [
+     "46ca2d6b9c45805d8aa684af7fe91af6dd5d7919",
+     []
+    ],
     "screen-capture.idl": [
      "db9282ce0a57bb3b84ea45f5ed2d7e69bc3a8a32",
      []
@@ -413455,6 +413610,10 @@
      "9d5ea8bae27a7ed694cb383965a5ffd14dd22d9a",
      []
     ],
+    "WEB_FEATURES.yml": [
+     "335b072c1868c1817dbe7ed6c1901907aa8decbc",
+     []
+    ],
     "idlharness-expected.txt": [
      "c514368f772065595dae7a81b1c55d5c65a73f2b",
      []
@@ -426678,13 +426837,17 @@
        []
       ],
       "executor.sub.html": [
-       "bb2d58dc9c9cfac6d98380b0b587bc242fbd5e11",
+       "b89c45e4f5c25b274925afd6569d6384d5183fe4",
        []
       ],
       "executor.sub.html.headers": [
        "4030ea1d3ddb186a2b5361eb1a3f2404a45531fc",
        []
       ],
+      "post-navigation-handler.py": [
+       "1749517710ed19eda399f01321e1ffcedfc9b09b",
+       []
+      ],
       "prefetch.py": [
        "14ac4d1699ea0c52ac4b40f0a4a0f71c99147073",
        []
@@ -426905,6 +427068,10 @@
        "10a48df58cf9dd9f13eca87e69c54098af1b64b0",
        []
       ],
+      "image-with-headers-stash.py": [
+       "dcb8838d4a167d91ded325e7d3fc6b50055c7746",
+       []
+      ],
       "indexedb-utils.js": [
        "7c57000d5cf48a3bbf74c0b0d8f812922f0575ef",
        []
@@ -430964,6 +431131,10 @@
       "b92b53ee45cd98933a3c2fbcf404478eb8f66a06",
       []
      ],
+     "urlpattern-generate-test-data.json": [
+      "c118f0a73b5fe108ab1a1f39d41148648daa7baa",
+      []
+     ],
      "urlpattern-hasregexpgroups-tests.js": [
       "4be886e4a5390d7d43356d853cc00c7bbb23d361",
       []
@@ -436008,7 +436179,7 @@
      []
     ],
     "RTCConfiguration-iceServers-expected.txt": [
-     "92a76728663c4702649309d3919bfe16197efdaa",
+     "be4b1ea79a5e5ead781dfd7ccbed266251ff67e1",
      []
     ],
     "RTCDTMFSender-helper.js": [
@@ -491185,7 +491356,7 @@
      ]
     ],
     "encoding.https.any.js": [
-     "941639bdaec01d0eb619a5850b1d878bdf77f695",
+     "f5d2ca15e717a0837f1e08031ab682db5aa965ea",
      [
       "cookie-store/encoding.https.any.html",
       {
@@ -491226,7 +491397,7 @@
      ]
     ],
     "httponly_cookies.https.window.js": [
-     "605e94e67440aaedbcaa39f185270fe77b316ad3",
+     "836f47da3f6e0f8f2c89445d1b2fbdfdf9ddc9e6",
      [
       "cookie-store/httponly_cookies.https.window.html",
       {
@@ -511977,7 +512148,7 @@
        ]
       ],
       "clip-path-interpolation-shape.html": [
-       "f35552386f3a1d0f2a420f2951c4ae0f81b4cce0",
+       "f725e1fc6fa0cbde5928c1e45e5e7c5f72b1a7dd",
        [
         null,
         {}
@@ -530631,7 +530802,7 @@
       ]
      ],
      "if-conditionals.html": [
-      "caead7864d550f8732eff919c1b555c8f759508d",
+      "f6d981798ae7a03f97b4fd089ee02141c7f90813",
       [
        null,
        {}
@@ -531380,6 +531551,13 @@
        {}
       ]
      ],
+     "var-ident-function.html": [
+      "3453cd5b64942b9d7bccdde418baa50e8018205a",
+      [
+       null,
+       {}
+      ]
+     ],
      "var-parsing.html": [
       "0c69342f2ee11bdfdbe991be375a70732956bee7",
       [
@@ -548987,13 +549165,6 @@
        }
       ]
      ],
-     "move-inserted-node-from-DOMNodeInserted-during-exec-command-insertHTML.html": [
-      "41e012a62e9617f372f85d0a0cedefe8ad42fbd6",
-      [
-       null,
-       {}
-      ]
-     ],
      "no-beforeinput-when-no-selection.html": [
       "098a95863a606393502d4e2fc517fcb8ad144d35",
       [
@@ -653863,34 +654034,6 @@
           {}
          ]
         ],
-        "042.html": [
-         "df3a2f88f29f2e8035d8c778c3397ad464688e18",
-         [
-          null,
-          {}
-         ]
-        ],
-        "043.html": [
-         "bcfd90cba47880efa48f9e809f37209f5f024dd6",
-         [
-          null,
-          {}
-         ]
-        ],
-        "044.html": [
-         "8d412079e45f9f8a3d074d707db39a55e1d8b946",
-         [
-          null,
-          {}
-         ]
-        ],
-        "045.html": [
-         "254e0d13662786d8542d03de3547b39ecf684ede",
-         [
-          null,
-          {}
-         ]
-        ],
         "046.html": [
          "4f145d63e1d619df2df429ec6fd713e77e303cb3",
          [
@@ -653949,20 +654092,6 @@
           {}
          ]
         ],
-        "054.html": [
-         "29ede23414ec57950717a05e375cbc15547c0b4d",
-         [
-          null,
-          {}
-         ]
-        ],
-        "055.html": [
-         "c837d78174b108d8b90cca4dccbc91bef8e1efad",
-         [
-          null,
-          {}
-         ]
-        ],
         "056.html": [
          "e2d0868034e1b243e610b3e3afdea18d78c418c8",
          [
@@ -701506,7 +701635,7 @@
      ]
     ],
     "content-encoding.https.html": [
-     "0d67bfc7d4f9a9c471272a8a475655d1c5225552",
+     "80473552f08b0c5f857533bdebf7a168283d5953",
      [
       null,
       {}
@@ -704820,7 +704949,7 @@
       ]
      ],
      "animation-trigger-repeat.tentative.html": [
-      "cfbe9d3c9334148789d4cebc7a01a2f9e848b22d",
+      "6c01e762e5acd18a1def36673c93d7fcdedf4964",
       [
        null,
        {}
@@ -714647,6 +714776,15 @@
        {}
       ]
      ],
+     "no-prefetch-for-post.https.html": [
+      "7739f4f8c7105b2c4e9ed4671081b00d0c0b8c6e",
+      [
+       null,
+       {
+        "timeout": "long"
+       }
+      ]
+     ],
      "no-vary-search": {
       "prefetch-single-with-hint.https.html": [
        "f2d8b3090e1f8447f86bd62a6f24ca9daae06ec7",
@@ -715639,6 +715777,15 @@
        }
       ]
      ],
+     "headers.https.html": [
+      "2ef6b5ce072866d3c88ce7a86fcea6436de3364a",
+      [
+       null,
+       {
+        "timeout": "long"
+       }
+      ]
+     ],
      "iframe-added-post-activation.https.html": [
       "d22b511e108d8b7c7f0b63f28e5bf485eca98758",
       [
@@ -736856,13 +737003,6 @@
     },
     "legacy-domevents-tests": {
      "approved": {
-      "ProcessingInstruction.DOMCharacterDataModified.html": [
-       "2da0a389e2e3bc51861fef752b11a629203897d0",
-       [
-        null,
-        {}
-       ]
-      ],
       "dispatchEvent.click.checkbox.html": [
        "8cb548f84c60eb6b528c1049884649b26c4f18ba",
        [
@@ -736870,13 +737010,6 @@
         {}
        ]
       ],
-      "domnodeinserted.html": [
-       "e5064d8d46cd9aad4768aa81dacb18b989e2c993",
-       [
-        null,
-        {}
-       ]
-      ],
       "stopImmediatePropagation.effect.html": [
        "a414d60298acece6dce5d970e6f0448a99fd65da",
        [
@@ -740184,6 +740317,53 @@
       }
      ]
     ],
+    "urlpattern-generate.tentative.any.js": [
+     "1f6962942d88f88684c5302175202e0278d3d971",
+     [
+      "urlpattern/urlpattern-generate.tentative.any.html",
+      {
+       "script_metadata": [
+        [
+         "global",
+         "window,worker"
+        ]
+       ]
+      }
+     ],
+     [
+      "urlpattern/urlpattern-generate.tentative.any.serviceworker.html",
+      {
+       "script_metadata": [
+        [
+         "global",
+         "window,worker"
+        ]
+       ]
+      }
+     ],
+     [
+      "urlpattern/urlpattern-generate.tentative.any.sharedworker.html",
+      {
+       "script_metadata": [
+        [
+         "global",
+         "window,worker"
+        ]
+       ]
+      }
+     ],
+     [
+      "urlpattern/urlpattern-generate.tentative.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "global",
+         "window,worker"
+        ]
+       ]
+      }
+     ]
+    ],
     "urlpattern-hasregexpgroups.any.js": [
      "33133d2511b065ca94cc5e793066cc8111b4d6e6",
      [
@@ -796864,7 +797044,7 @@
      ]
     ],
     "RTCConfiguration-iceServers.html": [
-     "bc7831361ab5f417b46a507b0e5977bef9bedd49",
+     "65a6015f52a7233260ab8405fb43bc347fa0ff4b",
      [
       null,
       {}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/overlay/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-position/overlay/WEB_FEATURES.yml
new file mode 100644
index 0000000..a1a4402
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/overlay/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: overlay
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/individual-transform/individual-transform-3.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/individual-transform/individual-transform-3.html
new file mode 100644
index 0000000..2c81cb12
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/individual-transform/individual-transform-3.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Individual transform: non-invertible matrix</title>
+<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-transforms-2/#individual-transforms">
+<link rel="help" href="https://drafts.csswg.org/css-transforms-2/#ctm">
+<link rel="help" href="https://drafts.csswg.org/css-transforms-1/#transform-function-lists">
+<link rel="help" href="https://github.com/servo/servo/issues/37146">
+<link rel="match" href="../../reference/ref-filled-green-200px-square.html">
+<meta name="assert" content="Tests that the element isn't rendered when
+    the current transformation matrix is non-invertible because of `scale`.">
+
+<style>
+.wrapper {
+  width: 200px;
+  height: 200px;
+  background: green;
+}
+.wrapper > div {
+  width: 200px;
+  height: 20px;
+  background: red;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+
+<div class="wrapper">
+  <div style="scale: 0"></div>
+  <div style="scale: 0 0"></div>
+  <div style="scale: 0 1"></div>
+  <div style="scale: 1 0"></div>
+  <div style="scale: 0 0 0"></div>
+  <div style="scale: 0 0 1"></div>
+  <div style="scale: 0 1 0"></div>
+  <div style="scale: 0 1 1"></div>
+  <div style="scale: 1 0 0"></div>
+  <div style="scale: 1 0 1"></div>
+  <div style="scale: 1 1 0"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/transform-matrix-009.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/transform-matrix-009.html
new file mode 100644
index 0000000..81f04db0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/transform-matrix-009.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Test (Transforms): matrix() with zeros in the diagonal</title>
+<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
+<link rel="help" href="https://www.w3.org/TR/css-transforms-1/#funcdef-transform-matrix">
+<link rel="help" href="https://www.w3.org/TR/css-transforms-1/#transform-function-lists">
+<link rel="help" href="https://github.com/servo/servo/issues/37146">
+<link rel="match" href="../reference/ref-filled-green-200px-square.html">
+<meta name="assert" content="Tests that the element is still rendered,
+    even though the current transformation matrix has zeros in the diagonal,
+    as long as the matrix remains invertible.">
+
+<style>
+.wrapper {
+  width: 200px;
+  height: 200px;
+  background: red;
+}
+.test {
+  width: 200px;
+  height: 200px;
+  background: green;
+  transform: matrix(0,1, 1,0, 0,0);
+  /*
+    The resulting matrix is:
+    ┌         ┐
+    │ 0 1 0 0 │
+    │ 1 0 0 0 │
+    │ 0 0 1 0 │
+    │ 0 0 0 1 │
+    └         ┘
+    It could result from e.g. `scaleX(-1) rotate(90deg)`.
+  */
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+
+<div class="wrapper">
+  <div class="test"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-child-with-composited-filter-ref.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-child-with-composited-filter-ref.html
new file mode 100644
index 0000000..9dd26f2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-child-with-composited-filter-ref.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title>View transitions: inline child with filter (ref)</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="author" href="mailto:mattwoodrow@apple.com">
+
+<style>
+body { margin : 0; }
+#target {
+  width: 100px;
+  height: 100px;
+  background-color: grey;
+  overflow-clip-margin: 40px;
+  contain: paint;
+  view-transition-name: target;
+}
+
+#child {
+  position: relative;
+  left: 100px;
+  top: 100px;
+  color: lightgreen;
+  background-color: darkgreen;
+  filter: blur(30px);
+  transform: translateZ(0px);
+}
+</style>
+
+<div id="target">
+  <span id="child">INLINEBOX</span>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-child-with-composited-filter.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-child-with-composited-filter.html
new file mode 100644
index 0000000..36ba980
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/inline-child-with-composited-filter.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>View transitions: inline child with filter</title>
+<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/">
+<link rel="author" href="mailto:vmpstr@chromium.org">
+<link rel="author" href="mailto:mattwoodrow@apple.com">
+<link rel="match" href="inline-child-with-filter-ref.html">
+<meta name=fuzzy content="maxDifference=0-2;totalPixels=0-2400">
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+body { margin : 0; }
+#target {
+  width: 100px;
+  height: 100px;
+  background-color: grey;
+  overflow-clip-margin: 40px;
+  contain: paint;
+  view-transition-name: target;
+}
+
+#child {
+  position: relative;
+  left: 100px;
+  top: 100px;
+  color: lightgreen;
+  background-color: darkgreen;
+  filter: blur(30px);
+  transform: translateZ(0px);
+}
+
+html::view-transition-group(root) { animation-duration: 300s; }
+html::view-transition-old(target) {
+  animation: unset;
+  opacity: 1;
+}
+html::view-transition-new(target) {
+  animation: unset;
+  opacity: 0;
+}
+</style>
+
+<div id="target">
+  <span id="child">INLINEBOX</span>
+</div>
+
+<script>
+failIfNot(document.startViewTransition, "Missing document.startViewTransition");
+
+async function runTest() {
+  let transition = document.startViewTransition(async () => {
+    document.getElementById("target").remove();
+  });
+  transition.ready.then(() => requestAnimationFrame(takeScreenshot));
+}
+onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/custom-elements/registries/idlharness.window-expected.txt b/third_party/blink/web_tests/external/wpt/custom-elements/registries/idlharness.window-expected.txt
index b5b3128..73b50e78 100644
--- a/third_party/blink/web_tests/external/wpt/custom-elements/registries/idlharness.window-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/custom-elements/registries/idlharness.window-expected.txt
@@ -1,5 +1,19 @@
 This is a testharness.js-based test.
-[FAIL] idl_test setup
-  promise_test: Unhandled rejection with value: object "Error fetching /interfaces/scoped-custom-elements-registry.idl."
+[FAIL] idl_test validation
+  Validation error at line 4 in scoped-custom-elements-registry, inside `partial interface CustomElementRegistry`:\n  undefined initialize(Node root)\n            ^ The operation "initialize" has already been defined for the base interface "CustomElementRegistry" either in itself or in a mixin\n\nValidation error at line 320 in dom, inside `dictionary ImportNodeOptions`:\ndictionary ImportNodeOptions {\n           ^ The name "ImportNodeOptions" of type "dictionary" was already seen
+[FAIL] Partial interface CustomElementRegistry: member names are unique
+  assert_true: member undefined is unique expected true got false
+[FAIL] Partial interface HTMLTemplateElement: member names are unique
+  assert_true: member shadowRootCustomElementRegistry is unique expected true got false
+[FAIL] Partial interface Element: member names are unique
+  assert_true: member customElementRegistry is unique expected true got false
+[FAIL] Partial dictionary ShadowRootInit: member names are unique
+  assert_true: member customElementRegistry is unique expected true got false
+[FAIL] Partial dictionary ElementCreationOptions: member names are unique
+  assert_true: member customElementRegistry is unique expected true got false
+[FAIL] Document includes DocumentOrShadowRoot: member names are unique
+  assert_true: member customElementRegistry is unique expected true got false
+[FAIL] ShadowRoot includes DocumentOrShadowRoot: member names are unique
+  assert_true: member customElementRegistry is unique expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/OWNERS b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/OWNERS
index dee5bb0f..e69de29 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/testdriver/actions/OWNERS
@@ -1 +0,0 @@
-lanwei@chromium.org
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/scoped-custom-elements-registry.idl b/third_party/blink/web_tests/external/wpt/interfaces/scoped-custom-elements-registry.idl
new file mode 100644
index 0000000..46ca2d6b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/interfaces/scoped-custom-elements-registry.idl
@@ -0,0 +1,38 @@
+[Exposed=Window]
+partial interface CustomElementRegistry {
+  constructor();
+  undefined initialize(Node root);
+};
+
+[Exposed=Window]
+partial interface HTMLTemplateElement {
+  [CEReactions] attribute DOMString shadowRootCustomElementRegistry;
+};
+
+[Exposed=Window]
+partial interface Document {
+  readonly attribute CustomElementRegistry? customElementRegistry;
+};
+
+[Exposed=Window]
+partial interface Element {
+  readonly attribute CustomElementRegistry? customElementRegistry;
+};
+
+[Exposed=Window]
+partial interface ShadowRoot {
+  readonly attribute CustomElementRegistry? customElementRegistry;
+};
+
+dictionary ImportNodeOptions {
+  CustomElementRegistry customElementRegistry;
+  boolean selfOnly = false;
+};
+
+partial dictionary ShadowRootInit {
+  CustomElementRegistry customElementRegistry;
+};
+
+partial dictionary ElementCreationOptions {
+  CustomElementRegistry customElementRegistry;
+};
diff --git a/third_party/blink/web_tests/external/wpt/layout-instability/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/layout-instability/WEB_FEATURES.yml
new file mode 100644
index 0000000..335b072
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/layout-instability/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: layout-instability
+  files: "**"
diff --git a/third_party/blink/web_tests/platform/mac-mac11/external/wpt/custom-elements/registries/idlharness.window-expected.txt b/third_party/blink/web_tests/platform/mac-mac11/external/wpt/custom-elements/registries/idlharness.window-expected.txt
new file mode 100644
index 0000000..b5b3128
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11/external/wpt/custom-elements/registries/idlharness.window-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] idl_test setup
+  promise_test: Unhandled rejection with value: object "Error fetching /interfaces/scoped-custom-elements-registry.idl."
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac11/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/idlharness.window-expected.txt b/third_party/blink/web_tests/platform/mac-mac11/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/idlharness.window-expected.txt
new file mode 100644
index 0000000..b5b3128
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac11/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/idlharness.window-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] idl_test setup
+  promise_test: Unhandled rejection with value: object "Error fetching /interfaces/scoped-custom-elements-registry.idl."
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/idlharness.window-expected.txt b/third_party/blink/web_tests/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/idlharness.window-expected.txt
new file mode 100644
index 0000000..bc8bef8a
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/scoped-custom-element-registry-disabled/external/wpt/custom-elements/registries/idlharness.window-expected.txt
@@ -0,0 +1,31 @@
+This is a testharness.js-based test.
+[FAIL] idl_test setup
+  promise_test: Unhandled rejection with value: object "TypeError: Failed to construct 'CustomElementRegistry': Illegal constructor"
+[FAIL] idl_test validation
+  Validation error at line 4 in scoped-custom-elements-registry, inside `partial interface CustomElementRegistry`:\n  undefined initialize(Node root)\n            ^ The operation "initialize" has already been defined for the base interface "CustomElementRegistry" either in itself or in a mixin\n\nValidation error at line 320 in dom, inside `dictionary ImportNodeOptions`:\ndictionary ImportNodeOptions {\n           ^ The name "ImportNodeOptions" of type "dictionary" was already seen
+[FAIL] Partial interface CustomElementRegistry: member names are unique
+  assert_true: member undefined is unique expected true got false
+[FAIL] Partial interface HTMLTemplateElement: member names are unique
+  assert_true: member shadowRootCustomElementRegistry is unique expected true got false
+[FAIL] Partial interface Element: member names are unique
+  assert_true: member customElementRegistry is unique expected true got false
+[FAIL] Partial dictionary ShadowRootInit: member names are unique
+  assert_true: member customElementRegistry is unique expected true got false
+[FAIL] Partial dictionary ElementCreationOptions: member names are unique
+  assert_true: member customElementRegistry is unique expected true got false
+[FAIL] Document includes DocumentOrShadowRoot: member names are unique
+  assert_true: member customElementRegistry is unique expected true got false
+[FAIL] ShadowRoot includes DocumentOrShadowRoot: member names are unique
+  assert_true: member customElementRegistry is unique expected true got false
+[FAIL] HTMLTemplateElement interface: attribute shadowRootCustomElementRegistry
+  assert_true: The prototype object must have a property "shadowRootCustomElementRegistry" expected true got false
+[FAIL] CustomElementRegistry interface: operation initialize(Node)
+  assert_own_property: interface prototype object missing non-static operation expected property "initialize" missing
+[FAIL] Document interface: attribute customElementRegistry
+  assert_true: The prototype object must have a property "customElementRegistry" expected true got false
+[FAIL] ShadowRoot interface: attribute customElementRegistry
+  assert_true: The prototype object must have a property "customElementRegistry" expected true got false
+[FAIL] Element interface: attribute customElementRegistry
+  assert_true: The prototype object must have a property "customElementRegistry" expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-create-multimodal.https.window.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-create-multimodal.https.window.js
index eed3549e..c9b2e98 100644
--- a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-create-multimodal.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-create-multimodal.https.window.js
@@ -49,7 +49,6 @@
     { expectedInputs: [{type: 'image'}], initialPrompts: [{role: 'user', content: [audioContent]}] },
   ];
   for (const options of kUnsupportedCreateOptions) {
-    // TODO(crbug.com/419599702): Ensure the model actually gets initialPrompts.
-    await promise_rejects_js(t, TypeError, LanguageModel.create(options), JSON.stringify(options));
+    await promise_rejects_dom(t, 'NotSupportedError', LanguageModel.create(options), JSON.stringify(options));
   }
 }, 'LanguageModel.create() fails with unsupported multimodal initialPrompts');
diff --git a/third_party/catapult b/third_party/catapult
index 61f9c08..3af14c3 160000
--- a/third_party/catapult
+++ b/third_party/catapult
@@ -1 +1 @@
-Subproject commit 61f9c08d6ae028f8440b1ddddb330cfdf028c159
+Subproject commit 3af14c3b4e2496ad1b85e1f33823f006e30fe8e0
diff --git a/third_party/depot_tools b/third_party/depot_tools
index 0772b51..0b1d80a 160000
--- a/third_party/depot_tools
+++ b/third_party/depot_tools
@@ -1 +1 @@
-Subproject commit 0772b51a975ba1ecf983b52665528d5b1db8a433
+Subproject commit 0b1d80ab9e9f1413234641d193639e5daa92dd5b
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index a178b7d..c7d5f74c 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit a178b7d51c21c468b397db564aa21e34c7cc0aa2
+Subproject commit c7d5f74c859abdd3219524ec9f77ce98d54a9a15
diff --git a/third_party/libc++abi/src b/third_party/libc++abi/src
index 9810fb23..241ef36 160000
--- a/third_party/libc++abi/src
+++ b/third_party/libc++abi/src
@@ -1 +1 @@
-Subproject commit 9810fb23f6ba666f017c2b67c67de2bcac2b44bd
+Subproject commit 241ef367ab2d135197377a82da5f7aee49a082f8
diff --git a/third_party/mutter/README.chromium b/third_party/mutter/README.chromium
index fb321c9..024161e 100644
--- a/third_party/mutter/README.chromium
+++ b/third_party/mutter/README.chromium
@@ -1,7 +1,7 @@
 Name: mutter
 URL: https://gitlab.gnome.org/GNOME/mutter
 Version: 48.alpha
-Revision: e99ff5359c4134093efe3cb2aa208e4addf565c6
+Revision: 881058e0a3c395b93986d734d2cff164376a1ec7
 License: GPL-2.0
 License File: LICENSE
 Shipped: no
diff --git a/third_party/mutter/src b/third_party/mutter/src
index e99ff53..881058e 160000
--- a/third_party/mutter/src
+++ b/third_party/mutter/src
@@ -1 +1 @@
-Subproject commit e99ff5359c4134093efe3cb2aa208e4addf565c6
+Subproject commit 881058e0a3c395b93986d734d2cff164376a1ec7
diff --git a/third_party/node/README.chromium b/third_party/node/README.chromium
index 98bc57a..c0c9a42 100644
--- a/third_party/node/README.chromium
+++ b/third_party/node/README.chromium
@@ -389,6 +389,9 @@
 License: MIT
 Security Critical: no
 Shipped: no
+Mitigated: CVE-2022-37620
+CVE-2022-37620: Local patch was applied to completely remove affected code as
+there is no upstream fix.
 
 Description:
 HTMLMinifier is a highly configurable, well-tested, JavaScript-based HTML
@@ -398,8 +401,16 @@
 of shipped HTML files though.
 
 Local Modifications:
-Removed uglify-js dependency since we don't plan to use the --minify-js flag in
-Chromium.
+ - Removed uglify-js dependency since we don't plan to use the --minify-js flag
+   in Chromium.
+ - Applied local patch patches/html_minifier2.patch to address vulnerability,
+   see https://osv.dev/vulnerability/GHSA-pfq8-rq6v-vf5m and
+   https://github.com/kangax/html-minifier/issues/1135. The local patch
+   completely removes the affected code, making it impossible to trigger it from
+   client code, since there is no later version with the vulnerability fixed
+   provided by the tool's authors. The tool should eventually be replaced with a
+   more modern tool as part of crbug.com/40943411.
+
 
 -------------------- DEPENDENCY DIVIDER --------------------
 
diff --git a/third_party/node/node_modules.tar.gz.sha1 b/third_party/node/node_modules.tar.gz.sha1
index 6457c93..5ac4e316 100644
--- a/third_party/node/node_modules.tar.gz.sha1
+++ b/third_party/node/node_modules.tar.gz.sha1
@@ -1 +1 @@
-13eea9a3163f9e91f343e6a3197079986d7276b2
+782009f3247d27e3c0a9663eb3a35c78bdca6745
diff --git a/third_party/node/patches/html_minifier2.patch b/third_party/node/patches/html_minifier2.patch
new file mode 100644
index 0000000..c5feaf2
--- /dev/null
+++ b/third_party/node/patches/html_minifier2.patch
@@ -0,0 +1,63 @@
+diff --git a/node_modules/html-minifier/src/htmlminifier.js b/node_modules/html-minifier/src/htmlminifier.js
+index eb19dd6b33ff3..e9dd3141874d4 100644
+--- a/node_modules/html-minifier/src/htmlminifier.js
++++ b/node_modules/html-minifier/src/htmlminifier.js
+@@ -868,56 +868,8 @@ function minify(value, options, partialMarkup) {
+     return token;
+   });
+ 
+-  var customFragments = options.ignoreCustomFragments.map(function(re) {
+-    return re.source;
+-  });
+-  if (customFragments.length) {
+-    var reCustomIgnore = new RegExp('\\s*(?:' + customFragments.join('|') + ')+\\s*', 'g');
+-    // temporarily replace custom ignored fragments with unique attributes
+-    value = value.replace(reCustomIgnore, function(match) {
+-      if (!uidAttr) {
+-        uidAttr = uniqueId(value);
+-        uidPattern = new RegExp('(\\s*)' + uidAttr + '([0-9]+)' + uidAttr + '(\\s*)', 'g');
+-        if (options.minifyCSS) {
+-          options.minifyCSS = (function(fn) {
+-            return function(text, type) {
+-              text = text.replace(uidPattern, function(match, prefix, index) {
+-                var chunks = ignoredCustomMarkupChunks[+index];
+-                return chunks[1] + uidAttr + index + uidAttr + chunks[2];
+-              });
+-              var ids = [];
+-              new CleanCSS().minify(wrapCSS(text, type)).warnings.forEach(function(warning) {
+-                var match = uidPattern.exec(warning);
+-                if (match) {
+-                  var id = uidAttr + match[2] + uidAttr;
+-                  text = text.replace(id, ignoreCSS(id));
+-                  ids.push(id);
+-                }
+-              });
+-              text = fn(text, type);
+-              ids.forEach(function(id) {
+-                text = text.replace(ignoreCSS(id), id);
+-              });
+-              return text;
+-            };
+-          })(options.minifyCSS);
+-        }
+-        if (options.minifyJS) {
+-          options.minifyJS = (function(fn) {
+-            return function(text, type) {
+-              return fn(text.replace(uidPattern, function(match, prefix, index) {
+-                var chunks = ignoredCustomMarkupChunks[+index];
+-                return chunks[1] + uidAttr + index + uidAttr + chunks[2];
+-              }), type);
+-            };
+-          })(options.minifyJS);
+-        }
+-      }
+-      var token = uidAttr + ignoredCustomMarkupChunks.length + uidAttr;
+-      ignoredCustomMarkupChunks.push(/^(\s*)[\s\S]*?(\s*)$/.exec(match));
+-      return '\t' + token + '\t';
+-    });
+-  }
++  // Chromium patch for https://github.com/kangax/html-minifier/issues/1135.
++  // Removed ignoreCustomFragments processing completely as it is not needed anyway.
+ 
+   if (options.sortAttributes && typeof options.sortAttributes !== 'function' ||
+       options.sortClassName && typeof options.sortClassName !== 'function') {
diff --git a/third_party/node/update_npm_deps b/third_party/node/update_npm_deps
index ec800ee..0cd3a57d 100755
--- a/third_party/node/update_npm_deps
+++ b/third_party/node/update_npm_deps
@@ -64,6 +64,7 @@
 echo 'Step 3: Applying local patches...'
 patch -d node_modules/@types/d3/ -p1 < patches/chromium_d3_types_index.patch
 patch -d node_modules/html-minifier/ -p1 < patches/html_minifier.patch
+patch -p1 < patches/html_minifier2.patch
 patch -p1 < patches/lit_html.patch
 patch -p1 < patches/types_chai.patch
 patch -p1 < patches/types_trusted_types.patch
diff --git a/third_party/pdfium b/third_party/pdfium
index cf433ae..66b63bb 160000
--- a/third_party/pdfium
+++ b/third_party/pdfium
@@ -1 +1 @@
-Subproject commit cf433ae5520d061db56391155b59b34e67484f39
+Subproject commit 66b63bba62fc2587bf91d3a055a9079f5984b8c6
diff --git a/third_party/rust/chromium_crates_io/Cargo.lock b/third_party/rust/chromium_crates_io/Cargo.lock
index 4fbe5da..79c58cc 100644
--- a/third_party/rust/chromium_crates_io/Cargo.lock
+++ b/third_party/rust/chromium_crates_io/Cargo.lock
@@ -74,7 +74,7 @@
 
 [[package]]
 name = "cc"
-version = "1.2.23"
+version = "1.2.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "shlex",
diff --git a/third_party/rust/chromium_crates_io/supply-chain/config.toml b/third_party/rust/chromium_crates_io/supply-chain/config.toml
index 03fe52f..89f449b 100644
--- a/third_party/rust/chromium_crates_io/supply-chain/config.toml
+++ b/third_party/rust/chromium_crates_io/supply-chain/config.toml
@@ -74,7 +74,7 @@
 [policy."calendrical_calculations:0.2.0"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
-[policy."cc:1.2.23"]
+[policy."cc:1.2.24"]
 criteria = []
 
 [policy."cfg-if:1.0.0"]
diff --git a/third_party/rust/chromium_crates_io/vendor/cc-v1/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/cc-v1/Cargo.toml
index 2453d9a2..4076815 100644
--- a/third_party/rust/chromium_crates_io/vendor/cc-v1/Cargo.toml
+++ b/third_party/rust/chromium_crates_io/vendor/cc-v1/Cargo.toml
@@ -6,13 +6,13 @@
 # by `tools/crates/run_gnrt.py vendor`. Do not edit!
 #
 # This is an empty placeholder that has replaced the
-# `cc-1.2.23` crate.
+# `cc-1.2.24` crate.
 #
 # See `//tools/crates/gnrt/removed_crate.md` to learn more.
 
 [package]
 name = "cc"
-version = "1.2.23"
+version = "1.2.24"
 
 [package.metadata.gnrt]
 is_placeholder = true
diff --git a/third_party/rust/chromium_crates_io/vendor/cc-v1/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/cc-v1/src/lib.rs
index 4ce2fe1..b5b46e96 100644
--- a/third_party/rust/chromium_crates_io/vendor/cc-v1/src/lib.rs
+++ b/third_party/rust/chromium_crates_io/vendor/cc-v1/src/lib.rs
@@ -6,6 +6,6 @@
 // by `tools/crates/run_gnrt.py vendor`. Do not edit!
 //
 // This is an empty placeholder that has replaced the
-// `cc-1.2.23` crate.
+// `cc-1.2.24` crate.
 //
 // See `//tools/crates/gnrt/removed_crate.md` to learn more.
diff --git a/third_party/skia b/third_party/skia
index e2dc10a..82d326f 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit e2dc10af85db2b3c8e95fe0b7f5817614fb31419
+Subproject commit 82d326fc2148181e8d9ca848b17237fa4db75331
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps
index 9b8253b..7a77f5b 160000
--- a/third_party/vulkan-deps
+++ b/third_party/vulkan-deps
@@ -1 +1 @@
-Subproject commit 9b8253ba5637b5ad10835a8e412f3b29b4cd9dae
+Subproject commit 7a77f5b6428118e42f8a35586578a4fabeba7135
diff --git a/third_party/vulkan-validation-layers/src b/third_party/vulkan-validation-layers/src
index ee2b1e4..30f98bc 160000
--- a/third_party/vulkan-validation-layers/src
+++ b/third_party/vulkan-validation-layers/src
@@ -1 +1 @@
-Subproject commit ee2b1e4837b496cacac158f13bac28ad543223f3
+Subproject commit 30f98bc36f99860a6c2cd18c4af5f3f387e0b933
diff --git a/third_party/wayland-protocols/BUILD.gn b/third_party/wayland-protocols/BUILD.gn
index da8491c..4bcbc2c 100644
--- a/third_party/wayland-protocols/BUILD.gn
+++ b/third_party/wayland-protocols/BUILD.gn
@@ -168,11 +168,6 @@
 }
 
 wayland_protocol("ui_controls_protocol") {
-  sources = [ "unstable/ui-controls/ui-controls-unstable-v2.xml" ]
-}
-
-wayland_protocol("ui_controls_v1_protocol") {
-  # This is used by exo.
   sources = [ "unstable/ui-controls/ui-controls-unstable-v1.xml" ]
 }
 
diff --git a/third_party/wayland-protocols/unstable/ui-controls/ui-controls-unstable-v2.xml b/third_party/wayland-protocols/unstable/ui-controls/ui-controls-unstable-v2.xml
deleted file mode 100644
index ed579528..0000000
--- a/third_party/wayland-protocols/unstable/ui-controls/ui-controls-unstable-v2.xml
+++ /dev/null
@@ -1,139 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<protocol name="ui_controls_unstable_v2">
-  <copyright>
-    Copyright 2022 The Chromium Authors.
-
-    Permission is hereby granted, free of charge, to any person obtaining a
-    copy of this software and associated documentation files (the "Software"),
-    to deal in the Software without restriction, including without limitation
-    the rights to use, copy, modify, merge, publish, distribute, sublicense,
-    and/or sell copies of the Software, and to permit persons to whom the
-    Software is furnished to do so, subject to the following conditions:
-
-    The above copyright notice and this permission notice (including the next
-    paragraph) shall be included in all copies or substantial portions of the
-    Software.
-
-    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-    DEALINGS IN THE SOFTWARE.
-  </copyright>
-
-  <interface name="zcr_ui_controls_v2" version="1">
-    <description summary="requests for input emulation">
-      This global provides requests for different type of input emulation that
-      mirror the semantics of Chrome's ui_controls functions.
-    </description>
-
-    <enum name="key_state" bitfield="true">
-      <description
-          summary="whether to press, release, or press and release a key">
-        These flags signal which key events to emulate: press; release; or
-        press, then release.
-      </description>
-      <!-- same values as ui_controls::KeyEventType -->
-      <entry name="press" value="1"/>
-      <entry name="release" value="2"/>
-    </enum>
-
-    <enum name="mouse_button">
-      <description summary="which mouse button to emulate">
-        Which mouse button to emulate an event for.
-      </description>
-      <!-- same values as ui_controls::MouseButton -->
-      <entry name="left" value="0"/>
-      <entry name="middle" value="1"/>
-      <entry name="right" value="2"/>
-    </enum>
-
-    <enum name="mouse_button_state" bitfield="true">
-      <description summary="whether to press, release, or click a mouse button">
-        These flags signal which mouse button events to emulate: press; release;
-        or press, then release.
-      </description>
-      <!-- same values as ui_controls::MouseButtonState -->
-      <entry name="up" value="1"/>
-      <entry name="down" value="2"/>
-    </enum>
-
-    <enum name="modifier" bitfield="true">
-      <description summary="pressed modifiers">
-        These flags signal which modifiers should be pressed during an emulated
-        input, if any.
-      </description>
-      <!-- same values as ui_controls::AcceleratorState -->
-      <entry name="none" value="0"/>
-      <entry name="shift" value="1"/>
-      <entry name="control" value="2"/>
-      <entry name="alt" value="4"/>
-    </enum>
-
-    <request name="send_key_events">
-      <description summary="emulate a key press/release/press and release">
-        Requests the compositor to emulate a key press, release, or press and
-        release for the key corresponding to the given keycode, together with
-        the specified modifiers. The compositor will decide which specific
-        events to generate in response to this request. After the compositor has
-        finished processing this request, a request_processed event with a
-        matching `id` will be emitted.
-      </description>
-      <arg name="key" type="uint" summary="evdev key code"/>
-      <arg name="key_state" type="uint" enum="key_state"
-           summary="whether to press, release, or press and release the key"/>
-      <arg name="pressed_modifiers" type="uint" enum="modifier"
-           summary="pressed modifier keys"/>
-      <arg name="id" type="uint"
-           summary="will be echoed back in the matching sent event"/>
-    </request>
-
-    <request name="send_mouse_move">
-      <description summary="emulate a mouse move to the given location">
-        Requests the compositor to emulate a mouse move to the given location.
-        The compositor will decide which specific events to generate in response
-        to this request. After the compositor has finished processing this
-        request, a request_processed event with a matching `id` will be emitted.
-
-        If `surface` is null, `x` and `y` are global screen coordinates; else,
-        they are surface-local coordinates relative to `surface`.
-      </description>
-      <arg name="x" type="int" summary="x-coordinate in DIP"/>
-      <arg name="y" type="int" summary="x-coordinate in DIP"/>
-      <arg name="surface" type="object" interface="wl_surface"
-           allow-null="true" summary="surface that x and y are relative to"/>
-      <arg name="id" type="uint"
-           summary="will be echoed back in the matching sent event"/>
-    </request>
-
-    <request name="send_mouse_button">
-      <description summary="emulate a mouse button press/release/click">
-        Requests the compositor to emulate an up (if `state` is up) / down (if
-        `state` is down) / click (i.e. down and up, if `state` is down|up) for
-        the specified mouse button at the current mouse position, together with
-        the specified modifiers. The compositor will decide which specific
-        events to generate in response to this request. After the compositor has
-        finished processing this request, a request_processed event with a
-        matching `id` will be emitted.
-      </description>
-      <arg name="button" type="uint" enum="mouse_button"
-           summary="button code of the mouse button"/>
-      <arg name="button_state" type="uint" enum="mouse_button_state"
-           summary="whether to press, release, or click the button"/>
-      <arg name="pressed_modifiers" type="uint" enum="modifier"
-           summary="pressed modifier keys"/>
-      <arg name="id" type="uint"
-           summary="will be echoed back in the matching sent event"/>
-    </request>
-
-    <event name="request_processed">
-      <description summary="request has been processed">
-        The request with ID `id` has been fully processed.
-      </description>
-      <arg name="id" type="uint" summary="ID of the processed request"/>
-    </event>
-
-  </interface>
-</protocol>
diff --git a/third_party/webgpu-cts/src b/third_party/webgpu-cts/src
index 905c7cb..00bbf54 160000
--- a/third_party/webgpu-cts/src
+++ b/third_party/webgpu-cts/src
@@ -1 +1 @@
-Subproject commit 905c7cbfeaac1cf3feb4c6056dd6f3dbaa06b074
+Subproject commit 00bbf5422c1b7a71285c51b2dc1e1637e618b916
diff --git a/third_party/weston/src b/third_party/weston/src
index bdba2f9..4eb10b1 160000
--- a/third_party/weston/src
+++ b/third_party/weston/src
@@ -1 +1 @@
-Subproject commit bdba2f9adaca673fd58339d8140bc04727ee279d
+Subproject commit 4eb10b123b483327214d8da5da67e8bbeeaed8fe
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index c992acaa..a1abe83 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -10216,6 +10216,16 @@
   </description>
 </action>
 
+<action name="DomDistiller.Android.OnStartedReaderMode">
+  <owner>wylieb@google.com</owner>
+  <owner>chrome-reader-mode-team@google.com</owner>
+  <description>
+    Recorded when a user started reader mode through an interaction with a
+    message or the magic toolbar button. This doesn't record when the actual
+    viewer appears, but rather when the viewer is requested.
+  </description>
+</action>
+
 <action name="DomDistiller.Android.ThemeChanged">
   <owner>wylieb@google.com</owner>
   <owner>chrome-reader-mode-team@google.com</owner>
@@ -10225,6 +10235,9 @@
 </action>
 
 <action name="DomDistiller_DistilledPageOpened">
+  <obsolete>
+    Long dead, reimplemented as DomDistiller.Android.OnStartedReaderMode.
+  </obsolete>
   <owner>smaslo@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
   <description>User opens reader mode on a page.</description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index dbd3c5d..f7e09f6 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -12372,7 +12372,6 @@
   <int value="-582570706" label="PPAPISharedImagesSwapChain:disabled"/>
   <int value="-582300629" label="UserNotes:enabled"/>
   <int value="-581236612" label="ConnectivityDiagnosticsWebUi:disabled"/>
-  <int value="-581218894" label="TabResumptionModuleAndroid:disabled"/>
   <int value="-580897686" label="SharedHighlightingAmp:enabled"/>
   <int value="-580051880" label="BirchWeather:disabled"/>
   <int value="-579897981" label="EnableEdgeDetection:enabled"/>
@@ -16435,7 +16434,6 @@
   <int value="957333504" label="OmniboxSteadyStateHeight:enabled"/>
   <int value="957458620" label="MediaRouterOTRInstance:enabled"/>
   <int value="960413971" label="GlanceablesV2CalendarView:disabled"/>
-  <int value="960696967" label="TabResumptionModuleAndroid:enabled"/>
   <int value="960883599" label="IPH_SupervisedUserProfileSignin:enabled"/>
   <int value="961019394" label="IOSPromoRefreshedPasswordBubble:disabled"/>
   <int value="962191833" label="StopAppIndexingReport:disabled"/>
@@ -20086,6 +20084,7 @@
   <int value="16" label="Device In Use (NotReadableError)"/>
   <int value="17" label="Request cancelled (?)"/>
   <int value="18" label="Start timeout (AbortError)"/>
+  <int value="19" label="Permission denied by user (NotAllowedError)"/>
 </enum>
 
 <enum name="MediaStreamType">
diff --git a/tools/metrics/histograms/metadata/blink/histograms.xml b/tools/metrics/histograms/metadata/blink/histograms.xml
index 82e08c7..3a11aee 100644
--- a/tools/metrics/histograms/metadata/blink/histograms.xml
+++ b/tools/metrics/histograms/metadata/blink/histograms.xml
@@ -5087,6 +5087,29 @@
   </summary>
 </histogram>
 
+<histogram name="Blink.ThrottleFrameRate.AllowedBySecurity.API" enum="Boolean"
+    expires_after="2025-12-31">
+  <owner>gjc@google.com</owner>
+  <owner>chrome-loading@google.com</owner>
+  <summary>
+    Whether the frame rate throttling feature is allowed by the security check.
+    Recorded each time the link blocking=&quot;full-frame-rate&quot; API is
+    triggered.
+  </summary>
+</histogram>
+
+<histogram
+    name="Blink.ThrottleFrameRate.AllowedBySecurity.DocumentInitialization"
+    enum="Boolean" expires_after="2025-12-31">
+  <owner>gjc@google.com</owner>
+  <owner>chrome-loading@google.com</owner>
+  <summary>
+    Whether the frame rate throttling feature is allowed by the security check.
+    Recorded each time the browser attempts to throttle the frame rate when the
+    document is initialized and the corresponding feature is enabled.
+  </summary>
+</histogram>
+
 <histogram name="Blink.UpdateViewportIntersection.RemoteFrameNeedsUpdate"
     enum="BooleanYesNo" expires_after="2025-10-26">
   <owner>lizeb@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/chromeos/histograms.xml b/tools/metrics/histograms/metadata/chromeos/histograms.xml
index da9ab22..1ba89cf 100644
--- a/tools/metrics/histograms/metadata/chromeos/histograms.xml
+++ b/tools/metrics/histograms/metadata/chromeos/histograms.xml
@@ -1176,9 +1176,9 @@
 </histogram>
 
 <histogram name="ChromeOS.CWP.CollectPerf"
-    enum="ChromeOSProfileCollectionStatus" expires_after="2025-06-22">
-  <owner>aalexand@google.com</owner>
+    enum="ChromeOSProfileCollectionStatus" expires_after="2026-06-22">
   <owner>gmx@chromium.org</owner>
+  <owner>aalexand@google.com</owner>
   <owner>cwp-team@google.com</owner>
   <summary>
     A count of successes and various failure modes related to collecting and
diff --git a/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml b/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml
index b23e00a..26a040b8 100644
--- a/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml
+++ b/tools/metrics/histograms/metadata/chromeos_settings/histograms.xml
@@ -218,7 +218,7 @@
     name="ChromeOS.Settings.Device.Keyboard.AutoBrightnessEnabled.Changed"
     enum="BooleanToggled" expires_after="2025-12-31">
   <owner>longbowei@google.com</owner>
-  <owner>dpad@google.com</owner>
+  <owner>jimmyxgong@chromium.org</owner>
   <owner>cros-device-enablement@google.com</owner>
   <summary>
     Records each time a user toggles the keyboard auto-brightness setting via
@@ -229,7 +229,7 @@
 <histogram name="ChromeOS.Settings.Device.Keyboard.BrightnessSliderAdjusted"
     units="%" expires_after="2025-12-31">
   <owner>longbo@google.com</owner>
-  <owner>dpad@google.com</owner>
+  <owner>jimmyxgong@chromium.org</owner>
   <owner>cros-device-enablement@google.com</owner>
   <summary>
     Records each time a user changes the keyboard brightness using slider in
@@ -263,7 +263,7 @@
 <histogram name="ChromeOS.Settings.Device.KeyboardColorLinkClicks"
     enum="Boolean" expires_after="2025-12-31">
   <owner>longbowei@google.com</owner>
-  <owner>dpad@google.com</owner>
+  <owner>jimmyxgong@chromium.org</owner>
   <owner>cros-device-enablement@google.com</owner>
   <summary>
     Records when a user clicks the &quot;Keyboard Color&quot; link within
@@ -489,7 +489,7 @@
 
 <histogram name="ChromeOS.Settings.Keyboard.Modifiers.Hash" units="hash"
     expires_after="2026-03-22">
-  <owner>dpad@google.com</owner>
+  <owner>jimmyxgong@chromium.org</owner>
   <owner>cros-device-enablement@google.com</owner>
   <summary>
     Records the configured modifier remapping set for all modifiers as a hash.
@@ -502,7 +502,7 @@
 <histogram
     name="ChromeOS.Settings.Keyboard.Modifiers.{Modifier}RemappedTo.Changed"
     enum="KeyboardModifierRemappingKeys" expires_after="2026-03-22">
-  <owner>dpad@google.com</owner>
+  <owner>jimmyxgong@chromium.org</owner>
   <owner>cros-device-enablement@google.com</owner>
   <summary>
     Records the configured modifier remapping for the {Modifier} key when a user
@@ -524,7 +524,7 @@
 <histogram
     name="ChromeOS.Settings.Keyboard.Modifiers.{Modifier}RemappedTo.Started"
     enum="KeyboardModifierRemappingKeys" expires_after="2026-03-22">
-  <owner>dpad@google.com</owner>
+  <owner>jimmyxgong@chromium.org</owner>
   <owner>cros-device-enablement@google.com</owner>
   <summary>
     Records the configured modifier remapping for the {Modifier} key when a user
diff --git a/tools/metrics/histograms/metadata/media/enums.xml b/tools/metrics/histograms/metadata/media/enums.xml
index 538d419..3c137a9e 100644
--- a/tools/metrics/histograms/metadata/media/enums.xml
+++ b/tools/metrics/histograms/metadata/media/enums.xml
@@ -2001,6 +2001,7 @@
   <int value="10" label="Not Supported Error"/>
   <int value="11" label="Insecure Context"/>
   <int value="12" label="Invalid State Error"/>
+  <int value="13" label="Explicit User Rejection"/>
 </enum>
 
 <enum name="V4l2VideoDecoderFunctions">
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index 4032680d9..911db388 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -4289,6 +4289,30 @@
   </summary>
 </histogram>
 
+<histogram name="Media.MediaDevices.GetAllScreensMedia.Latency" units="ms"
+    expires_after="2023-05-01">
+  <owner>simonha@google.com</owner>
+  <owner>video-cmi-apis@google.com</owner>
+  <summary>
+    The latency of calls to the navigator.mediaDevices.GetAllScreensMedia() API
+    which resolve, including both successes and failures. Note very long calls
+    which record a GetAllScreensMedia.Result of kTimedOut but do eventually
+    resolve will have their latency recorded.
+  </summary>
+</histogram>
+
+<histogram name="Media.MediaDevices.GetAllScreensMedia.Result2"
+    enum="UserMediaRequestResult" expires_after="2023-05-01">
+  <owner>simonha@google.com</owner>
+  <owner>video-cmi-apis@google.com</owner>
+  <summary>
+    The results of all calls to the navigator.mediaDevices.GetAllScreensMedia()
+    API, including successful promise resolutions, error codes, or kTimedOut, if
+    the promise was still pending after 6 seconds. The suffix 2 was added at
+    milestone 138, after kNotAllowedByUserError was added.
+  </summary>
+</histogram>
+
 <histogram name="Media.MediaDevices.GetDisplayMedia.Latency" units="ms"
     expires_after="2025-11-02">
   <owner>toprice@chromium.org</owner>
@@ -4302,7 +4326,7 @@
   </summary>
 </histogram>
 
-<histogram name="Media.MediaDevices.GetDisplayMedia.Result"
+<histogram name="Media.MediaDevices.GetDisplayMedia.Result2"
     enum="UserMediaRequestResult" expires_after="2025-11-09">
   <owner>toprice@chromium.org</owner>
   <owner>agpalak@chromium.org</owner>
@@ -4310,30 +4334,8 @@
   <summary>
     The results of all calls to the navigator.mediaDevices.GetDisplayMedia()
     API, including successful promise resolutions, error codes, or kTimedOut, if
-    the promise was still pending after 6 seconds.
-  </summary>
-</histogram>
-
-<histogram name="Media.MediaDevices.GetDisplayMediaSet.Latency" units="ms"
-    expires_after="2023-05-01">
-  <owner>simonha@google.com</owner>
-  <owner>video-cmi-apis@google.com</owner>
-  <summary>
-    The latency of calls to the navigator.mediaDevices.GetDisplayMediaSet() API
-    which resolve, including both successes and failures. Note very long calls
-    which record a GetDisplayMediaSet.Result of kTimedOut but do eventually
-    resolve will have their latency recorded.
-  </summary>
-</histogram>
-
-<histogram name="Media.MediaDevices.GetDisplayMediaSet.Result"
-    enum="UserMediaRequestResult" expires_after="2023-05-01">
-  <owner>simonha@google.com</owner>
-  <owner>video-cmi-apis@google.com</owner>
-  <summary>
-    The results of all calls to the navigator.mediaDevices.GetDisplayMediaSet()
-    API, including successful promise resolutions, error codes, or kTimedOut, if
-    the promise was still pending after 6 seconds.
+    the promise was still pending after 6 seconds. The suffix 2 was added at
+    milestone 138, after kNotAllowedByUserError was added.
   </summary>
 </histogram>
 
@@ -4361,7 +4363,7 @@
   </summary>
 </histogram>
 
-<histogram name="Media.MediaDevices.GetUserMedia.Result"
+<histogram name="Media.MediaDevices.GetUserMedia.Result2"
     enum="UserMediaRequestResult" expires_after="2025-10-26">
   <owner>toprice@chromium.org</owner>
   <owner>agpalak@chromium.org</owner>
@@ -4370,6 +4372,9 @@
     The results of all calls to the navigator.mediaDevices.GetUserMedia() API,
     including successful promise resolutions, error codes, or kTimedOut, if the
     promise was still pending after 8 seconds.
+
+    The suffix 2 was added at milestone 138, after kNotAllowedByUserError was
+    added.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index 95e0402c..8bc1ce5 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -866,7 +866,7 @@
 </histogram>
 
 <histogram name="Navigation.DeferSpeculativeRFHAction"
-    enum="DeferSpeculativeRFHAction" expires_after="2025-06-08">
+    enum="DeferSpeculativeRFHAction" expires_after="2025-12-08">
   <owner>gjc@google.com</owner>
   <owner>rakina@chromium.org</owner>
   <owner>chrome-navigation@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/web_rtc/histograms.xml b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
index f31aee3b..9741e7e 100644
--- a/tools/metrics/histograms/metadata/web_rtc/histograms.xml
+++ b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
@@ -1128,7 +1128,7 @@
 </histogram>
 
 <histogram name="WebRTC.DesktopCapture.Win.WgcCapturerResult"
-    enum="WebRtcWgcCapturerResult" expires_after="2025-07-05">
+    enum="WebRtcWgcCapturerResult" expires_after="2025-11-19">
   <owner>alcooper@chromium.org</owner>
   <owner>henrika@chromium.org</owner>
   <owner>edgecapabilitiesdev@microsoft.com</owner>
@@ -1139,7 +1139,7 @@
 </histogram>
 
 <histogram name="WebRTC.DesktopCapture.Win.WgcCaptureSessionGetFrameResult"
-    enum="WebRtcWgcCaptureSessionGetFrameResult" expires_after="2025-07-05">
+    enum="WebRtcWgcCaptureSessionGetFrameResult" expires_after="2025-11-19">
   <owner>alcooper@chromium.org</owner>
   <owner>henrika@chromium.org</owner>
   <owner>edgecapabilitiesdev@microsoft.com</owner>
@@ -1149,7 +1149,7 @@
 </histogram>
 
 <histogram name="WebRTC.DesktopCapture.Win.WgcCaptureSessionStartResult"
-    enum="WebRtcWgcCaptureSessionStartResult" expires_after="2025-07-05">
+    enum="WebRtcWgcCaptureSessionStartResult" expires_after="2025-11-19">
   <owner>alcooper@chromium.org</owner>
   <owner>henrika@chromium.org</owner>
   <owner>edgecapabilitiesdev@microsoft.com</owner>
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index 70d6153..700f3705a 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -170,7 +170,6 @@
  <item id="remoting_directory_get_host_list" added_in_milestone="86" content_hash_code="03933aa0" os_list="linux,windows,chromeos,android" file_path="remoting/base/directory_service_client.cc" />
  <item id="remoting_directory_register_host" added_in_milestone="86" content_hash_code="046c936d" os_list="linux,windows,chromeos,android" file_path="remoting/base/directory_service_client.cc" />
  <item id="remoting_ice_config_request" added_in_milestone="86" content_hash_code="001d0a98" os_list="linux,windows,chromeos,android" file_path="remoting/protocol/ice_config_fetcher_default.cc" />
- <item id="remoting_log_to_server" added_in_milestone="86" content_hash_code="04dfdf0a" os_list="linux,windows,chromeos,android" file_path="remoting/signaling/remoting_log_to_server.cc" />
  <item id="remoting_register_support_host_request" added_in_milestone="86" content_hash_code="04fd7da8" os_list="linux,windows,chromeos" file_path="remoting/host/remoting_register_support_host_request.cc" />
  <item id="remoting_telemetry_log_writer" added_in_milestone="86" content_hash_code="04df471b" os_list="linux,windows,chromeos,android" file_path="remoting/base/telemetry_log_writer.cc" />
  <item id="render_view_context_menu" added_in_milestone="62" content_hash_code="04240bc2" os_list="linux,windows,chromeos" file_path="chrome/browser/renderer_context_menu/render_view_context_menu.cc" />
diff --git a/tools/traffic_annotation/summary/grouping.xml b/tools/traffic_annotation/summary/grouping.xml
index 218c9256..44af999 100644
--- a/tools/traffic_annotation/summary/grouping.xml
+++ b/tools/traffic_annotation/summary/grouping.xml
@@ -116,7 +116,6 @@
       <annotation id="ftl_messaging_client_receive_messages"/>
       <annotation id="ftl_messaging_client_send_messages"/>
       <annotation id="ftl_registration_manager"/>
-      <annotation id="remoting_log_to_server"/>
       <annotation id="remoting_provision_corp_machine"/>
       <annotation id="omnibox_result_change"/>
       <annotation id="browser_switcher_ieem_sitelist"/>
diff --git a/ui/android/java/src/org/chromium/ui/interpolators/Interpolators.java b/ui/android/java/src/org/chromium/ui/interpolators/Interpolators.java
index bab6e695..be21773 100644
--- a/ui/android/java/src/org/chromium/ui/interpolators/Interpolators.java
+++ b/ui/android/java/src/org/chromium/ui/interpolators/Interpolators.java
@@ -63,10 +63,6 @@
     public static final LinearInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
     public static final OvershootInterpolator OVERSHOOT_INTERPOLATOR = new OvershootInterpolator();
 
-    /** Custom interpolator for the new background tab animation arc motion. */
-    public static final Interpolator NEW_BACKGROUND_TAB_ANIMATION_PATH_INTERPOLATOR =
-            PathInterpolatorCompat.create(0.41f, 0.12f, 0.38f, 1f);
-
     /**
      * Custom interpolator for the new background tab fake tab switcher button translation animator.
      */
@@ -76,8 +72,4 @@
     /** Custom interpolator for the new background tab fake tab switcher button shrink animator. */
     public static final Interpolator NEW_BACKGROUND_TAB_ANIMATION_BOUNCE_INTERPOLATOR =
             PathInterpolatorCompat.create(0.2f, 0f, 0f, 2f);
-
-    /** Custom interpolator for the new background tab animation arc motion. */
-    public static final Interpolator NEW_BACKGROUND_TAB_ANIMATION_SECOND_PATH_INTERPOLATOR =
-            PathInterpolatorCompat.create(0.34f, 0.17f, 0.26f, 0.99f);
 }
diff --git a/ui/ozone/platform/wayland/emulate/wayland_input_emulate.cc b/ui/ozone/platform/wayland/emulate/wayland_input_emulate.cc
index 90e202a6..4c50dab3 100644
--- a/ui/ozone/platform/wayland/emulate/wayland_input_emulate.cc
+++ b/ui/ozone/platform/wayland/emulate/wayland_input_emulate.cc
@@ -4,7 +4,7 @@
 
 #include "ui/ozone/platform/wayland/emulate/wayland_input_emulate.h"
 
-#include <ui-controls-unstable-v2-client-protocol.h>
+#include <ui-controls-unstable-v1-client-protocol.h>
 #include <wayland-client-protocol.h>
 
 #include <cstdint>
@@ -21,6 +21,7 @@
 #include "ui/ozone/platform/wayland/host/wayland_toplevel_window.h"
 #include "ui/ozone/platform/wayland/host/wayland_window.h"
 #include "ui/ozone/platform/wayland/host/xdg_popup.h"
+#include "ui/ozone/platform/wayland/host/xdg_surface.h"
 #include "ui/ozone/platform/wayland/host/xdg_toplevel.h"
 
 #if BUILDFLAG(IS_CHROMEOS)
@@ -29,6 +30,13 @@
 #include "ui/display/test/display_test_util.h"
 #endif
 
+namespace {
+
+// send_key_events() is only available since version 2.
+constexpr uint32_t kMinVersion = 2;
+
+}  // namespace
+
 namespace wl {
 
 WaylandInputEmulate::PendingRequest::PendingRequest(
@@ -67,16 +75,16 @@
     LOG(FATAL) << "ui-controls protocol extension is not available.";
   }
 
-  static constexpr zcr_ui_controls_v2_listener kUiControlsListener = {
+  static constexpr zcr_ui_controls_v1_listener kUiControlsListener = {
       .request_processed = &OnRequestProcessed};
-  zcr_ui_controls_v2_add_listener(ui_controls_, &kUiControlsListener, this);
+  zcr_ui_controls_v1_add_listener(ui_controls_, &kUiControlsListener, this);
 }
 
 WaylandInputEmulate::~WaylandInputEmulate() {
   auto* wayland_proxy = wl::WaylandProxy::GetInstance();
   wayland_proxy->SetDelegate(nullptr);
 
-  zcr_ui_controls_v2_destroy(ui_controls_);
+  zcr_ui_controls_v1_destroy(ui_controls_);
   wl_registry_destroy(registry_);
 }
 
@@ -99,7 +107,7 @@
           << " state=" << key_state
           << " accelerator_state=" << accelerator_state;
 
-  zcr_ui_controls_v2_send_key_events(
+  zcr_ui_controls_v1_send_key_events(
       ui_controls_, ui::KeycodeConverter::DomCodeToEvdevCode(dom_code),
       key_state, accelerator_state, request_id);
 
@@ -133,12 +141,16 @@
 
   auto* wayland_proxy = wl::WaylandProxy::GetInstance();
 
-  struct wl_surface* target_surface = nullptr;
+  struct xdg_surface* target_surface = nullptr;
   gfx::Point target_location = mouse_screen_location;
   if (widget) {
     auto* window = wayland_proxy->GetWaylandWindowForAcceleratedWidget(widget);
-    struct wl_surface* surface =
-        window->root_surface() ? window->root_surface()->surface() : nullptr;
+    struct xdg_surface* xdg_surface = nullptr;
+    if (auto* toplevel_window = window->AsWaylandToplevelWindow()) {
+      xdg_surface = toplevel_window->xdg_toplevel()->xdg_surface();
+    } else if (auto* popup = window->AsWaylandPopup()) {
+      xdg_surface = popup->xdg_popup()->xdg_surface();
+    }
     bool screen_coordinates = false;
     if (force_use_screen_coordinates_once_) {
       screen_coordinates = true;
@@ -147,9 +159,9 @@
 
     // If we can't use screen coordinates, we must have a surface so we can use
     // surface-local coordinates.
-    DCHECK(screen_coordinates || surface);
+    DCHECK(screen_coordinates || xdg_surface);
 
-    target_surface = screen_coordinates ? nullptr : surface;
+    target_surface = screen_coordinates ? nullptr : xdg_surface;
     // Ignore `force_use_screen_coordinates_once_` for selecting which
     // coordinates to use. This is because the only difference between
     // `mouse_screen_location` and `mouse_surface_location` is that the former
@@ -167,7 +179,7 @@
   VLOG(1) << "Requesting pointer motion: location="
           << target_location.ToString();
 
-  zcr_ui_controls_v2_send_mouse_move(ui_controls_, target_location.x(),
+  zcr_ui_controls_v1_send_mouse_move(ui_controls_, target_location.x(),
                                      target_location.y(), target_surface,
                                      request_id);
   wayland_proxy->FlushForTesting();
@@ -190,13 +202,37 @@
   VLOG(1) << "Requesting pointer button: button=" << button
           << " button_state=" << button_state;
 
-  zcr_ui_controls_v2_send_mouse_button(ui_controls_, button, button_state,
+  zcr_ui_controls_v1_send_mouse_button(ui_controls_, button, button_state,
                                        accelerator_state, request_id);
 
   auto* wayland_proxy = wl::WaylandProxy::GetInstance();
   wayland_proxy->FlushForTesting();
 }
 
+void WaylandInputEmulate::EmulateTouch(int action,
+                                       const gfx::Point& touch_screen_location,
+                                       int touch_id,
+                                       uint32_t request_id) {
+  if (AnyWindowWaitingForBufferCommit()) {
+    auto pending_request =
+        std::make_unique<PendingRequest>(PendingRequestType::Touch, request_id);
+    pending_request->action = action;
+    pending_request->touch_screen_location = touch_screen_location;
+    pending_request->touch_id = touch_id;
+    pending_requests_.emplace_back(std::move(pending_request));
+    return;
+  }
+
+  VLOG(1) << "Requesting touch: location=" << touch_screen_location.ToString()
+          << " action=" << action << " touch_id=" << touch_id;
+
+  zcr_ui_controls_v1_send_touch(
+      ui_controls_, action, touch_id, touch_screen_location.x(),
+      touch_screen_location.y(), /*surface=*/nullptr, request_id);
+  auto* wayland_proxy = wl::WaylandProxy::GetInstance();
+  wayland_proxy->FlushForTesting();
+}
+
 void WaylandInputEmulate::ForceUseScreenCoordinatesOnce() {
   force_use_screen_coordinates_once_ = true;
 }
@@ -294,7 +330,7 @@
 
 // static
 void WaylandInputEmulate::OnRequestProcessed(void* data,
-                                             zcr_ui_controls_v2* ui_controls,
+                                             zcr_ui_controls_v1* ui_controls,
                                              uint32_t id) {
   auto* self = static_cast<WaylandInputEmulate*>(data);
   self->request_processed_callback_.Run(id);
@@ -307,10 +343,11 @@
                                    const char* interface,
                                    uint32_t version) {
   auto* self = static_cast<WaylandInputEmulate*>(data);
-  if (std::string_view(interface) == "zcr_ui_controls_v2") {
+  if (UNSAFE_TODO(strcmp(interface, "zcr_ui_controls_v1")) == 0 &&
+      version >= kMinVersion) {
     const wl_interface* wayland_interface =
-        static_cast<const wl_interface*>(&zcr_ui_controls_v2_interface);
-    self->ui_controls_ = static_cast<zcr_ui_controls_v2*>(
+        static_cast<const wl_interface*>(&zcr_ui_controls_v1_interface);
+    self->ui_controls_ = static_cast<zcr_ui_controls_v1*>(
         wl_registry_bind(registry, name, wayland_interface, version));
   }
 }
@@ -385,6 +422,10 @@
         EmulatePointerButton(event->button, event->button_state,
                              event->accelerator_state, event->request_id);
         break;
+      case PendingRequestType::Touch:
+        EmulateTouch(event->action, event->touch_screen_location,
+                     event->touch_id, event->request_id);
+        break;
     }
   }
 }
diff --git a/ui/ozone/platform/wayland/emulate/wayland_input_emulate.h b/ui/ozone/platform/wayland/emulate/wayland_input_emulate.h
index f867225..b63933f7 100644
--- a/ui/ozone/platform/wayland/emulate/wayland_input_emulate.h
+++ b/ui/ozone/platform/wayland/emulate/wayland_input_emulate.h
@@ -23,7 +23,7 @@
 
 struct wl_buffer;
 struct wl_registry;
-struct zcr_ui_controls_v2;
+struct zcr_ui_controls_v1;
 struct wl_callback;
 
 namespace wl {
@@ -56,6 +56,12 @@
                             int accelerator_state,
                             uint32_t request_id);
 
+  // |touch_screen_location| is in DIP.
+  void EmulateTouch(int action,
+                    const gfx::Point& touch_screen_location,
+                    int touch_id,
+                    uint32_t request_id);
+
   void ForceUseScreenCoordinatesOnce();
 
  private:
@@ -63,6 +69,7 @@
     KeyPress,
     MouseMove,
     MouseButton,
+    Touch,
   };
 
   // Pending emulation request.
@@ -138,9 +145,9 @@
                           bool is_configured) override;
   void OnWindowRoleAssigned(gfx::AcceleratedWidget widget) override;
 
-  // zcr_ui_controls_v2_listener callbacks:
+  // zcr_ui_controls_v1_listener callbacks:
   static void OnRequestProcessed(void* data,
-                                 zcr_ui_controls_v2* ui_controls,
+                                 zcr_ui_controls_v1* ui_controls,
                                  uint32_t id);
 
   // wl_registry_listener callbacks:
@@ -179,7 +186,7 @@
   base::RepeatingCallback<void(uint32_t)> request_processed_callback_;
 
   // If true, the next `EmulatePointerMotion` call will use global screen
-  // coordinates, i.e. send zcr_ui_controls_v2.mouse_move with the `surface`
+  // coordinates, i.e. send zcr_ui_controls_v1.mouse_move with the `surface`
   // parameter set to NULL.
   // Note: this does not affect whether `EmulatePointerMotion` uses the
   // coordinates from its `mouse_surface_location` or `mouse_screen_location`
@@ -190,7 +197,7 @@
   // class belongs to cannot depend on the "wayland" target in the
   // //ui/ozone/platform/wayland/BUILD.gn
   raw_ptr<wl_registry> registry_ = nullptr;
-  raw_ptr<zcr_ui_controls_v2> ui_controls_ = nullptr;
+  raw_ptr<zcr_ui_controls_v1> ui_controls_ = nullptr;
 };
 
 }  // namespace wl
diff --git a/v8 b/v8
index e180c60..61ddd47 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit e180c60cc3eb265924e992248b0fe2c68e122cab
+Subproject commit 61ddd471ece346840bbebbb308dceb4b4ce31b28