diff --git a/DEPS b/DEPS
index 2368dfde..452cfd8 100644
--- a/DEPS
+++ b/DEPS
@@ -299,7 +299,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'src_internal_revision': 'eac1a0fd11368b363bfe25628d47c633d8f7660b',
+  'src_internal_revision': '4c4da7a117aa9100f7a27e9f37a7e92b4bfcde60',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
@@ -311,7 +311,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'e93c143a91fc0fd9eb83baad4af26d39ab418b6a',
+  'angle_revision': '432d1d1efdbd0e8d5788529fe193e0eb1e8456bf',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -319,11 +319,11 @@
   # 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': 'd45defc2d92a7961131319d92b35eba648926707',
+  'pdfium_revision': 'f92aa15fa160f203a0064ec9b7e4a853784d0134',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': 'a70ec8dd2cc1816e9deadda2f6e536640380e20c',
+  'boringssl_revision': 'ab301d01c2bf15da3716500e518425c085c25503',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
@@ -375,7 +375,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': '083971e6b02dd794b3cb84d01033455889be7976',
+  'catapult_revision': '0f4bac59a38c6aa5ad9874778f822d76ea737d35',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
@@ -395,7 +395,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': '520dadff7b7ab40a273f261ca5d5253be7fb3710',
+  'devtools_frontend_revision': '6c841fc0da4e1eeec9f198fd14167572e1f6656a',
   # 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.
@@ -419,7 +419,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.
-  'dawn_revision': 'bddeca3e8f226b857070fb90b6068886fee7a93e',
+  'dawn_revision': '3d21836f05819cda0631ba692b9a7dbb536f2ec8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -523,7 +523,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling llvm-libc
   # and whatever else without interference from each other.
-  'llvm_libc_revision':    'c43b02cfdbd4a75e9ba233f3b5bfd8322e3bf1d8',
+  'llvm_libc_revision':    'bf95cc5da608540ccddbd22f1866d713eaba3ac8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling llvm-libc
   # and whatever else without interference from each other.
@@ -1152,7 +1152,7 @@
   },
 
   'src/chrome/release_scripts': {
-      'url': Var('chrome_git') + '/chrome/tools/release/scripts' + '@' + 'a1c867ddbae2844edbaa27f2b5c8f063d04fbbbd',
+      'url': Var('chrome_git') + '/chrome/tools/release/scripts' + '@' + '6ad235a921b16b76e60316629f799e4fef593769',
       'condition': 'checkout_chrome_release_scripts',
   },
 
@@ -1484,7 +1484,7 @@
     'packages': [
       {
         'package': 'chromium/chrome/test/data/variations/cipd',
-        'version': '0X3nbRZK8kfh4OuODtCtUqIRZLbBGRZfHD8zqG_fO0kC',
+        'version': 't6OEiJwO4GHUzNYxsQ2TFE-X8bOKC9txraBfKTS-ZgwC',
       },
     ],
     'dep_type': 'cipd',
@@ -1495,7 +1495,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '283021f4101c7fdf0b717c7ab26c6f8059b28746',
+    'cfb3b184379b5491aafc36c95a2d8effd010eea2',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -2238,7 +2238,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/kotlin_stdlib',
-              'version': 'KFgAvgfE4Ssv7PMRYGJVo89rhJCPGQitmhEh39RETFgC',
+              'version': '74gAxjfyJIVJGIA4z0V-jCmMW6A6dDJSoWMh7qhlzp4C',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -2712,7 +2712,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/r8',
-              'version': 'bA3htCoEd_EArHekDGQSNpmBzQrcby2ioG6SFyl3AtwC',
+              'version': 'sxgLKZyJNZMVi8cot5yvRzqCFQxX_HbbR0psaeto5RcC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -4689,7 +4689,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        'dd18c245f49db25fee815e2386da4e9689d1b8d7',
+        'e82bd56d69ca3919d547f78ca8f417e4b8ef7ffc',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 718e090..882fcda 100644
--- a/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -8980,7 +8980,9 @@
     getter displayHeight
     getter displayWidth
     getter duration
+    getter flip
     getter format
+    getter rotation
     getter timestamp
     getter visibleRect
     method allocationSize
diff --git a/base/containers/contains.h b/base/containers/contains.h
index c140340..0b71102 100644
--- a/base/containers/contains.h
+++ b/base/containers/contains.h
@@ -11,8 +11,8 @@
 // `container`.
 
 #include <algorithm>
+#include <concepts>
 #include <ranges>
-#include <type_traits>
 #include <utility>
 
 namespace base {
diff --git a/base/containers/span.h b/base/containers/span.h
index 5757dea..1dd00d71 100644
--- a/base/containers/span.h
+++ b/base/containers/span.h
@@ -14,7 +14,6 @@
 #include <stdint.h>
 
 #include <algorithm>
-#include <array>
 #include <concepts>
 #include <functional>
 #include <initializer_list>
diff --git a/base/features.cc b/base/features.cc
index 72db06b1..79791ac 100644
--- a/base/features.cc
+++ b/base/features.cc
@@ -50,19 +50,6 @@
              "FastFilePathIsParent",
              FEATURE_ENABLED_BY_DEFAULT);
 
-// Use the Rust JSON parser. Enabled everywhere.
-BASE_FEATURE(kUseRustJsonParser,
-             "UseRustJsonParser",
-             FEATURE_ENABLED_BY_DEFAULT);
-
-// If true, use the Rust JSON parser in-thread; otherwise, it runs in a thread
-// pool.
-BASE_FEATURE_PARAM(bool,
-                   kUseRustJsonParserInCurrentSequence,
-                   &kUseRustJsonParser,
-                   "UseRustJsonParserInCurrentSequence",
-                   true);
-
 // Use non default low memory device threshold.
 // Value should be given via |LowMemoryDeviceThresholdMB|.
 #if BUILDFLAG(IS_ANDROID)
diff --git a/base/features.h b/base/features.h
index 8b0dfea4..0e4c48d 100644
--- a/base/features.h
+++ b/base/features.h
@@ -19,8 +19,6 @@
 
 BASE_EXPORT BASE_DECLARE_FEATURE(kFastFilePathIsParent);
 
-BASE_EXPORT BASE_DECLARE_FEATURE(kUseRustJsonParser);
-
 BASE_EXPORT BASE_DECLARE_FEATURE_PARAM(bool,
                                        kUseRustJsonParserInCurrentSequence);
 
diff --git a/base/json/json_reader.cc b/base/json/json_reader.cc
index f32622d..3fcccc9 100644
--- a/base/json/json_reader.cc
+++ b/base/json/json_reader.cc
@@ -7,13 +7,13 @@
 #include <string_view>
 #include <utility>
 
-#include "base/features.h"
-#include "base/json/json_parser.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
 
-#if !BUILDFLAG(IS_NACL)
+#if BUILDFLAG(IS_NACL)
+#include "base/json/json_parser.h"
+#else
 #include "base/strings/string_view_rust.h"
 #include "third_party/rust/serde_json_lenient/v0_2/wrapper/functions.h"
 #include "third_party/rust/serde_json_lenient/v0_2/wrapper/lib.rs.h"
@@ -142,17 +142,13 @@
   return parser.Parse(json);
 #else   // BUILDFLAG(IS_NACL)
   SCOPED_UMA_HISTOGRAM_TIMER_MICROS(kSecurityJsonParsingTime);
-  if (UsingRust()) {
-    JSONReader::Result result =
-        serde_json_lenient::DecodeJSONInRust(json, options, max_depth);
-    if (!result.has_value()) {
-      return std::nullopt;
-    }
-    return std::move(*result);
-  } else {
-    internal::JSONParser parser(options, max_depth);
-    return parser.Parse(json);
+
+  JSONReader::Result result =
+      serde_json_lenient::DecodeJSONInRust(json, options, max_depth);
+  if (!result.has_value()) {
+    return std::nullopt;
   }
+  return std::move(*result);
 #endif  // BUILDFLAG(IS_NACL)
 }
 
@@ -196,38 +192,9 @@
   return std::move(*value);
 #else   // BUILDFLAG(IS_NACL)
   SCOPED_UMA_HISTOGRAM_TIMER_MICROS(kSecurityJsonParsingTime);
-  if (UsingRust()) {
-    return serde_json_lenient::DecodeJSONInRust(json, options,
-                                                internal::kAbsoluteMaxDepth);
-  } else {
-    internal::JSONParser parser(options);
-    auto value = parser.Parse(json);
-    if (!value) {
-      Error error;
-      error.message = parser.GetErrorMessage();
-      error.line = parser.error_line();
-      error.column = parser.error_column();
-      return base::unexpected(std::move(error));
-    }
-
-    return std::move(*value);
-  }
+  return serde_json_lenient::DecodeJSONInRust(json, options,
+                                              internal::kAbsoluteMaxDepth);
 #endif  // BUILDFLAG(IS_NACL)
 }
 
-// static
-bool JSONReader::UsingRust() {
-  // If features have not yet been enabled, we cannot check the feature, so fall
-  // back to the C++ parser. In practice, this seems to apply to
-  // `ReadPrefsFromDisk()`, which is parsing trusted JSON.
-  if (!base::FeatureList::GetInstance()) {
-    return false;
-  }
-#if BUILDFLAG(IS_NACL)
-  return false;
-#else
-  return base::FeatureList::IsEnabled(base::features::kUseRustJsonParser);
-#endif
-}
-
 }  // namespace base
diff --git a/base/json/json_reader.h b/base/json/json_reader.h
index 5349d3c..1b1c536 100644
--- a/base/json/json_reader.h
+++ b/base/json/json_reader.h
@@ -133,9 +133,6 @@
   static Result ReadAndReturnValueWithError(
       std::string_view json,
       int options = JSON_PARSE_CHROMIUM_EXTENSIONS);
-
-  // Determine whether the Rust parser is in use.
-  static bool UsingRust();
 };
 
 }  // namespace base
diff --git a/base/json/json_reader_unittest.cc b/base/json/json_reader_unittest.cc
index ae2dca9..79de5e0 100644
--- a/base/json/json_reader_unittest.cc
+++ b/base/json/json_reader_unittest.cc
@@ -19,7 +19,6 @@
 #include "base/base_paths.h"
 #include "base/containers/heap_array.h"
 #include "base/containers/span.h"
-#include "base/features.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/path_service.h"
@@ -27,7 +26,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/gmock_expected_support.h"
 #include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -53,32 +51,20 @@
 
 namespace base {
 
-class JSONReaderTest : public testing::TestWithParam<bool> {
- public:
-  void SetUp() override {
-    feature_list_.InitWithFeatureState(base::features::kUseRustJsonParser,
-                                       using_rust_);
-  }
-
- protected:
-  bool using_rust_ = GetParam();
-  base::test::ScopedFeatureList feature_list_;
-};
-
-TEST_P(JSONReaderTest, Whitespace) {
+TEST(JSONReaderTest, Whitespace) {
   std::optional<Value> root = JSONReader::Read("   null   ");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_none());
 }
 
-TEST_P(JSONReaderTest, InvalidString) {
+TEST(JSONReaderTest, InvalidString) {
   // These are invalid because they do not represent a JSON value,
   // see https://tools.ietf.org/rfc/rfc8259.txt
   EXPECT_FALSE(JSONReader::Read(""));
   EXPECT_FALSE(JSONReader::Read("nu"));
 }
 
-TEST_P(JSONReaderTest, SimpleBool) {
+TEST(JSONReaderTest, SimpleBool) {
   base::HistogramTester histograms;
   std::optional<Value> root = JSONReader::Read("true  ");
   ASSERT_TRUE(root);
@@ -86,7 +72,7 @@
   histograms.ExpectTotalCount("Security.JSONParser.ParsingTime", 1);
 }
 
-TEST_P(JSONReaderTest, EmbeddedComments) {
+TEST(JSONReaderTest, EmbeddedComments) {
   std::optional<Value> root = JSONReader::Read("/* comment */null");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_none());
@@ -142,21 +128,21 @@
   EXPECT_FALSE(JSONReader::Read("/33"));
 }
 
-TEST_P(JSONReaderTest, Ints) {
+TEST(JSONReaderTest, Ints) {
   std::optional<Value> root = JSONReader::Read("43");
   ASSERT_TRUE(root);
   ASSERT_TRUE(root->is_int());
   EXPECT_EQ(43, root->GetInt());
 }
 
-TEST_P(JSONReaderTest, NonDecimalNumbers) {
+TEST(JSONReaderTest, NonDecimalNumbers) {
   // According to RFC 8259, oct, hex, and leading zeros are invalid JSON.
   EXPECT_FALSE(JSONReader::Read("043"));
   EXPECT_FALSE(JSONReader::Read("0x43"));
   EXPECT_FALSE(JSONReader::Read("00"));
 }
 
-TEST_P(JSONReaderTest, NumberZero) {
+TEST(JSONReaderTest, NumberZero) {
   // Test 0 (which needs to be special cased because of the leading zero
   // clause).
   std::optional<Value> root = JSONReader::Read("0");
@@ -165,7 +151,7 @@
   EXPECT_EQ(0, root->GetInt());
 }
 
-TEST_P(JSONReaderTest, LargeIntPromotion) {
+TEST(JSONReaderTest, LargeIntPromotion) {
   // Numbers that overflow ints should succeed, being internally promoted to
   // storage as doubles
   std::optional<Value> root = JSONReader::Read("2147483648");
@@ -178,7 +164,7 @@
   EXPECT_DOUBLE_EQ(-2147483649.0, root->GetDouble());
 }
 
-TEST_P(JSONReaderTest, LargerIntIsLossy) {
+TEST(JSONReaderTest, LargerIntIsLossy) {
   // Parse LONG_MAX as a JSON number (not a JSON string). The result of the
   // parse is a base::Value, either a (32-bit) int or a (64-bit) double.
   // LONG_MAX would overflow an int and can only be approximated by a double.
@@ -195,7 +181,7 @@
   EXPECT_EQ(std::string(etc808), StringPrintf("%f", root->GetDouble()));
 }
 
-TEST_P(JSONReaderTest, Doubles) {
+TEST(JSONReaderTest, Doubles) {
   std::optional<Value> root = JSONReader::Read("43.1");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_double());
@@ -239,14 +225,14 @@
   ASSERT_FALSE(value.has_value());
 }
 
-TEST_P(JSONReaderTest, FractionalNumbers) {
+TEST(JSONReaderTest, FractionalNumbers) {
   // Fractional parts must have a digit before and after the decimal point.
   EXPECT_FALSE(JSONReader::Read("1."));
   EXPECT_FALSE(JSONReader::Read(".1"));
   EXPECT_FALSE(JSONReader::Read("1.e10"));
 }
 
-TEST_P(JSONReaderTest, ExponentialNumbers) {
+TEST(JSONReaderTest, ExponentialNumbers) {
   // Exponent must have a digit following the 'e'.
   EXPECT_FALSE(JSONReader::Read("1e"));
   EXPECT_FALSE(JSONReader::Read("1E"));
@@ -254,7 +240,7 @@
   EXPECT_FALSE(JSONReader::Read("1e1.0"));
 }
 
-TEST_P(JSONReaderTest, InvalidInfNAN) {
+TEST(JSONReaderTest, InvalidInfNAN) {
   // The largest finite double is roughly 1.8e308.
   EXPECT_FALSE(JSONReader::Read("1e1000"));
   EXPECT_FALSE(JSONReader::Read("-1e1000"));
@@ -263,7 +249,7 @@
   EXPECT_FALSE(JSONReader::Read("inf"));
 }
 
-TEST_P(JSONReaderTest, InvalidNumbers) {
+TEST(JSONReaderTest, InvalidNumbers) {
   EXPECT_TRUE(JSONReader::Read("4.3"));
   EXPECT_FALSE(JSONReader::Read("4."));
   EXPECT_FALSE(JSONReader::Read("4.3.1"));
@@ -272,7 +258,7 @@
   EXPECT_FALSE(JSONReader::Read("42a"));
 }
 
-TEST_P(JSONReaderTest, Zeroes) {
+TEST(JSONReaderTest, Zeroes) {
   std::optional<Value> root = JSONReader::Read("0");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_int());
@@ -297,21 +283,21 @@
   EXPECT_TRUE(std::signbit(root->GetDouble()));
 }
 
-TEST_P(JSONReaderTest, SimpleString) {
+TEST(JSONReaderTest, SimpleString) {
   std::optional<Value> root = JSONReader::Read("\"hello world\"");
   ASSERT_TRUE(root);
   ASSERT_TRUE(root->is_string());
   EXPECT_EQ("hello world", root->GetString());
 }
 
-TEST_P(JSONReaderTest, EmptyString) {
+TEST(JSONReaderTest, EmptyString) {
   std::optional<Value> root = JSONReader::Read("\"\"");
   ASSERT_TRUE(root);
   ASSERT_TRUE(root->is_string());
   EXPECT_EQ("", root->GetString());
 }
 
-TEST_P(JSONReaderTest, BasicStringEscapes) {
+TEST(JSONReaderTest, BasicStringEscapes) {
   std::optional<Value> root =
       JSONReader::Read("\" \\\"\\\\\\/\\b\\f\\n\\r\\t\"");
   ASSERT_TRUE(root);
@@ -319,7 +305,7 @@
   EXPECT_EQ(" \"\\/\b\f\n\r\t", root->GetString());
 }
 
-TEST_P(JSONReaderTest, UnicodeEscapes) {
+TEST(JSONReaderTest, UnicodeEscapes) {
   // Test hex and unicode escapes including the null character.
   std::optional<Value> root =
       JSONReader::Read("\"\\x41\\xFF\\x00\\u1234\\u0000\"");
@@ -336,7 +322,7 @@
   EXPECT_TRUE(JSONReader::Read("\"\\uD834\\uDD1E\""));  // U+1D11E
 }
 
-TEST_P(JSONReaderTest, InvalidStrings) {
+TEST(JSONReaderTest, InvalidStrings) {
   EXPECT_FALSE(JSONReader::Read("\"no closing quote"));
   EXPECT_FALSE(JSONReader::Read("\"\\z invalid escape char\""));
   EXPECT_FALSE(JSONReader::Read("\"\\xAQ invalid hex code\""));
@@ -345,7 +331,7 @@
   EXPECT_FALSE(JSONReader::Read("\"extra backslash at end of input\\\""));
 }
 
-TEST_P(JSONReaderTest, BasicArray) {
+TEST(JSONReaderTest, BasicArray) {
   std::optional<Value> root = JSONReader::Read("[true, false, null]");
   ASSERT_TRUE(root);
   Value::List* list = root->GetIfList();
@@ -359,7 +345,7 @@
   EXPECT_EQ(*list, *root2);
 }
 
-TEST_P(JSONReaderTest, EmptyArray) {
+TEST(JSONReaderTest, EmptyArray) {
   std::optional<Value> value = JSONReader::Read("[]");
   ASSERT_TRUE(value);
   Value::List* list = value->GetIfList();
@@ -367,7 +353,7 @@
   EXPECT_TRUE(list->empty());
 }
 
-TEST_P(JSONReaderTest, CompleteArray) {
+TEST(JSONReaderTest, CompleteArray) {
   std::optional<Value> value = JSONReader::Read("[\"a\", 3, 4.56, null]");
   ASSERT_TRUE(value);
   Value::List* list = value->GetIfList();
@@ -375,7 +361,7 @@
   EXPECT_EQ(4U, list->size());
 }
 
-TEST_P(JSONReaderTest, NestedArrays) {
+TEST(JSONReaderTest, NestedArrays) {
   std::optional<Value> value = JSONReader::Read(
       "[[true], [], {\"smell\": \"nice\",\"taste\": \"yummy\" }, [false, [], "
       "[null]], null]");
@@ -393,7 +379,7 @@
   EXPECT_EQ(*list, *root2);
 }
 
-TEST_P(JSONReaderTest, InvalidArrays) {
+TEST(JSONReaderTest, InvalidArrays) {
   // Missing close brace.
   EXPECT_FALSE(JSONReader::Read("[[true], [], [false, [], [null]], null"));
 
@@ -408,7 +394,7 @@
   EXPECT_FALSE(JSONReader::Read("[true,]"));
 }
 
-TEST_P(JSONReaderTest, ArrayTrailingComma) {
+TEST(JSONReaderTest, ArrayTrailingComma) {
   // Valid if we set |allow_trailing_comma| to true.
   std::optional<Value> value =
       JSONReader::Read("[true,]", JSON_ALLOW_TRAILING_COMMAS);
@@ -421,7 +407,7 @@
   EXPECT_TRUE(value1.GetBool());
 }
 
-TEST_P(JSONReaderTest, ArrayTrailingCommaNoEmptyElements) {
+TEST(JSONReaderTest, ArrayTrailingCommaNoEmptyElements) {
   // Don't allow empty elements, even if |allow_trailing_comma| is
   // true.
   EXPECT_FALSE(JSONReader::Read("[,]", JSON_ALLOW_TRAILING_COMMAS));
@@ -430,13 +416,13 @@
   EXPECT_FALSE(JSONReader::Read("[true,,false]", JSON_ALLOW_TRAILING_COMMAS));
 }
 
-TEST_P(JSONReaderTest, EmptyDictionary) {
+TEST(JSONReaderTest, EmptyDictionary) {
   std::optional<Value> dict_val = JSONReader::Read("{}");
   ASSERT_TRUE(dict_val);
   ASSERT_TRUE(dict_val->is_dict());
 }
 
-TEST_P(JSONReaderTest, CompleteDictionary) {
+TEST(JSONReaderTest, CompleteDictionary) {
   std::optional<Value> root1 = JSONReader::Read(
       "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", \"bool\": "
       "false, \"more\": {} }");
@@ -495,7 +481,7 @@
   EXPECT_EQ(*root1_dict, *root2_dict);
 }
 
-TEST_P(JSONReaderTest, NestedDictionaries) {
+TEST(JSONReaderTest, NestedDictionaries) {
   std::optional<Value> root1 = JSONReader::Read(
       "{\"inner\":{\"array\":[true, 3, 4.56, null]},\"false\":false,\"d\":{}}");
   ASSERT_TRUE(root1);
@@ -520,7 +506,7 @@
   EXPECT_EQ(*root1_dict, *root2);
 }
 
-TEST_P(JSONReaderTest, DictionaryKeysWithPeriods) {
+TEST(JSONReaderTest, DictionaryKeysWithPeriods) {
   std::optional<Value> root =
       JSONReader::Read("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}");
   ASSERT_TRUE(root);
@@ -552,7 +538,7 @@
   EXPECT_EQ(1, *integer_value);
 }
 
-TEST_P(JSONReaderTest, DuplicateKeys) {
+TEST(JSONReaderTest, DuplicateKeys) {
   std::optional<Value> root = JSONReader::Read("{\"x\":1,\"x\":2,\"y\":3}");
   ASSERT_TRUE(root);
   const Value::Dict* root_dict = root->GetIfDict();
@@ -563,7 +549,7 @@
   EXPECT_EQ(2, *integer_value);
 }
 
-TEST_P(JSONReaderTest, InvalidDictionaries) {
+TEST(JSONReaderTest, InvalidDictionaries) {
   // No closing brace.
   EXPECT_FALSE(JSONReader::Read("{\"a\": true"));
 
@@ -593,7 +579,7 @@
                                 JSON_ALLOW_TRAILING_COMMAS));
 }
 
-TEST_P(JSONReaderTest, StackOverflow) {
+TEST(JSONReaderTest, StackOverflow) {
   std::string evil(1000000, '[');
   evil.append(std::string(1000000, ']'));
   EXPECT_FALSE(JSONReader::Read(evil));
@@ -612,7 +598,7 @@
   EXPECT_EQ(5001U, list->size());
 }
 
-TEST_P(JSONReaderTest, UTF8Input) {
+TEST(JSONReaderTest, UTF8Input) {
   std::optional<Value> root = JSONReader::Read("\"\xe7\xbd\x91\xe9\xa1\xb5\"");
   ASSERT_TRUE(root);
   ASSERT_TRUE(root->is_string());
@@ -676,13 +662,13 @@
   }
 }
 
-TEST_P(JSONReaderTest, InvalidUTF8Input) {
+TEST(JSONReaderTest, InvalidUTF8Input) {
   EXPECT_FALSE(JSONReader::Read("\"345\xb0\xa1\xb0\xa2\""));
   EXPECT_FALSE(JSONReader::Read("\"123\xc0\x81\""));
   EXPECT_FALSE(JSONReader::Read("\"abc\xc0\xae\""));
 }
 
-TEST_P(JSONReaderTest, UTF16Escapes) {
+TEST(JSONReaderTest, UTF16Escapes) {
   std::optional<Value> root = JSONReader::Read("\"\\u20ac3,14\"");
   ASSERT_TRUE(root);
   ASSERT_TRUE(root->is_string());
@@ -697,7 +683,7 @@
   EXPECT_EQ("\xf0\x9f\x92\xa9\xf0\x9f\x91\xac", root->GetString());
 }
 
-TEST_P(JSONReaderTest, InvalidUTF16Escapes) {
+TEST(JSONReaderTest, InvalidUTF16Escapes) {
   const char* const cases[] = {
       "\"\\u123\"",          // Invalid scalar.
       "\"\\ud83d\"",         // Invalid scalar.
@@ -719,7 +705,7 @@
   }
 }
 
-TEST_P(JSONReaderTest, LiteralRoots) {
+TEST(JSONReaderTest, LiteralRoots) {
   std::optional<Value> root = JSONReader::Read("null");
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_none());
@@ -740,7 +726,7 @@
   EXPECT_EQ("root", root->GetString());
 }
 
-TEST_P(JSONReaderTest, ReadFromFile) {
+TEST(JSONReaderTest, ReadFromFile) {
   FilePath path;
   ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &path));
   path = path.AppendASCII("json");
@@ -756,7 +742,7 @@
 
 // Tests that the root of a JSON object can be deleted safely while its
 // children outlive it.
-TEST_P(JSONReaderTest, StringOptimizations) {
+TEST(JSONReaderTest, StringOptimizations) {
   Value dict_literal_0;
   Value dict_literal_1;
   Value dict_string_0;
@@ -832,7 +818,7 @@
 // A smattering of invalid JSON designed to test specific portions of the
 // parser implementation against buffer overflow. Best run with DCHECKs so
 // that the one in NextChar fires.
-TEST_P(JSONReaderTest, InvalidSanity) {
+TEST(JSONReaderTest, InvalidSanity) {
   const auto kInvalidJson = std::to_array<const char*>({
       "/* test *",
       "{\"foo\"",
@@ -850,7 +836,7 @@
   }
 }
 
-TEST_P(JSONReaderTest, IllegalTrailingNull) {
+TEST(JSONReaderTest, IllegalTrailingNull) {
   const auto json = std::to_array<char>({'"', 'n', 'u', 'l', 'l', '"', '\0'});
   std::string json_string(json.data(), sizeof(json));
   auto root = JSONReader::ReadAndReturnValueWithError(json_string);
@@ -858,7 +844,7 @@
   EXPECT_NE("", root.error().message);
 }
 
-TEST_P(JSONReaderTest, ASCIIControlCodes) {
+TEST(JSONReaderTest, ASCIIControlCodes) {
   // A literal NUL byte or a literal new line, in a JSON string, should be
   // rejected. RFC 8259 section 7 says "the characters that MUST be escaped
   // [include]... the control characters (U+0000 through U+001F)".
@@ -883,13 +869,13 @@
   }
 }
 
-TEST_P(JSONReaderTest, MaxNesting) {
+TEST(JSONReaderTest, MaxNesting) {
   std::string json(R"({"outer": { "inner": {"foo": true}}})");
   EXPECT_FALSE(JSONReader::Read(json, JSON_PARSE_RFC, 3));
   EXPECT_TRUE(JSONReader::Read(json, JSON_PARSE_RFC, 4));
 }
 
-TEST_P(JSONReaderTest, Decode4ByteUtf8Char) {
+TEST(JSONReaderTest, Decode4ByteUtf8Char) {
   // kUtf8Data contains a 4 byte unicode character (a smiley!) that JSONReader
   // should be able to handle. The UTF-8 encoding of U+1F607 SMILING FACE WITH
   // HALO is "\xF0\x9F\x98\x87".
@@ -903,7 +889,7 @@
   EXPECT_EQ("\xF0\x9F\x98\x87", (*list)[0].GetString());
 }
 
-TEST_P(JSONReaderTest, DecodeUnicodeNonCharacter) {
+TEST(JSONReaderTest, DecodeUnicodeNonCharacter) {
   // Tests Unicode code points (encoded as escaped UTF-16) that are not valid
   // characters.
   EXPECT_TRUE(JSONReader::Read("[\"\\uFDD0\"]"));         // U+FDD0
@@ -945,13 +931,13 @@
   EXPECT_TRUE(JSONReader::Read("[\"\\uDBFF\\uDFFF\"]"));  // U+10FFFF
 }
 
-TEST_P(JSONReaderTest, DecodeNegativeEscapeSequence) {
+TEST(JSONReaderTest, DecodeNegativeEscapeSequence) {
   EXPECT_FALSE(JSONReader::Read("[\"\\x-A\"]"));
   EXPECT_FALSE(JSONReader::Read("[\"\\u-00A\"]"));
 }
 
 // Verifies invalid code points are replaced.
-TEST_P(JSONReaderTest, ReplaceInvalidCharacters) {
+TEST(JSONReaderTest, ReplaceInvalidCharacters) {
   // U+D800 is a lone high surrogate.
   const std::string invalid_high = "\"\xED\xA0\x80\"";
   std::optional<Value> value =
@@ -970,7 +956,7 @@
   EXPECT_EQ(U_FFFD U_FFFD U_FFFD, value->GetString());
 }
 
-TEST_P(JSONReaderTest, ReplaceInvalidUTF16EscapeSequence) {
+TEST(JSONReaderTest, ReplaceInvalidUTF16EscapeSequence) {
   // U+D800 is a lone high surrogate.
   const std::string invalid_high = "\"_\\uD800_\"";
   std::optional<Value> value =
@@ -987,7 +973,7 @@
   EXPECT_EQ("_" U_FFFD "_", value->GetString());
 }
 
-TEST_P(JSONReaderTest, InvalidUTF16HighSurrogates) {
+TEST(JSONReaderTest, InvalidUTF16HighSurrogates) {
   // U+dbaa is a high surrogate and expects a low surrogate, which U+001e is
   // not, so the entire surrogate pair should be replaced by
   // REPLACEMENT_CHARACTER.
@@ -1004,7 +990,7 @@
   ASSERT_FALSE(value);
 }
 
-TEST_P(JSONReaderTest, InvalidUTF16HighSurrogatesAndEscapes) {
+TEST(JSONReaderTest, InvalidUTF16HighSurrogatesAndEscapes) {
   // U+dbaa is a lone high surrogate, and should be replaced with
   // REPLACEMENT_CHARACTER and not affect interpretation of the following `\`
   // character as a part of the escape sequence `\"`.
@@ -1021,7 +1007,7 @@
   ASSERT_FALSE(value);
 }
 
-TEST_P(JSONReaderTest, ParseNumberErrors) {
+TEST(JSONReaderTest, ParseNumberErrors) {
   struct Cases {
     const char* input;
     bool parse_success;
@@ -1059,7 +1045,7 @@
   }
 }
 
-TEST_P(JSONReaderTest, UnterminatedInputs) {
+TEST(JSONReaderTest, UnterminatedInputs) {
   const auto kCases = std::to_array<const char*>({
       // clang-format off
       "/",
@@ -1091,7 +1077,7 @@
   }
 }
 
-TEST_P(JSONReaderTest, LineColumnCounting) {
+TEST(JSONReaderTest, LineColumnCounting) {
   struct Cases {
     const char* input;
     int error_line;
@@ -1165,7 +1151,7 @@
   }
 }
 
-TEST_P(JSONReaderTest, ChromiumExtensions) {
+TEST(JSONReaderTest, ChromiumExtensions) {
   // All of these cases should parse with JSON_PARSE_CHROMIUM_EXTENSIONS but
   // fail with JSON_PARSE_RFC.
   struct Cases {
@@ -1207,7 +1193,7 @@
 // For every control character, place it unescaped in a string and ensure that:
 // a) It doesn't parse with JSON_PARSE_RFC
 // b) It doesn't parse with JSON_PARSE_CHROMIUM_EXTENSIONS
-TEST_P(JSONReaderTest, UnescapedControls) {
+TEST(JSONReaderTest, UnescapedControls) {
   std::string input = "\"foo\"";
   // ECMA-404 (JSON standard) section 9: characters from 0x00 to 0x1f must be
   // escaped.
@@ -1223,11 +1209,7 @@
   }
 }
 
-TEST_P(JSONReaderTest, UsingRust) {
-  ASSERT_EQ(JSONReader::UsingRust(), using_rust_);
-}
-
-TEST_P(JSONReaderTest, ReadingJsonIntoDictAndList) {
+TEST(JSONReaderTest, ReadingJsonIntoDictAndList) {
   {
     std::optional<base::Value::List> list = JSONReader::ReadList("[1, 2, 3]");
     ASSERT_TRUE(list);
@@ -1256,11 +1238,4 @@
 
 FUZZ_TEST(JSONReaderTest, CanParseAnythingWithoutCrashing);
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         JSONReaderTest,
-                         testing::Bool(),
-                         [](const testing::TestParamInfo<bool>& info) {
-                           return info.param ? "Rust" : "Cpp";
-                         });
-
 }  // namespace base
diff --git a/build/config/linux/cached_results.scope b/build/config/linux/cached_results.scope
deleted file mode 100644
index 360984b0..0000000
--- a/build/config/linux/cached_results.scope
+++ /dev/null
@@ -1,104 +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.
-
-# Cached results for common pkg_config.py runs.
-data = [
-  {
-    sysroot = "../../build/linux/debian_bullseye_amd64-sysroot"
-    entries = [
-      {
-        args = ["atk", "atk-bridge-2.0"]
-        pkgresult = [["../../build/linux/debian_bullseye_amd64-sysroot/usr/include/atk-1.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/glib-2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/x86_64-linux-gnu/glib-2.0/include", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/at-spi2-atk/2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/dbus-1.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/x86_64-linux-gnu/dbus-1.0/include", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/at-spi-2.0"], [], ["atk-1.0", "gobject-2.0", "glib-2.0", "atk-bridge-2.0"], []]
-      },
-      {
-        args = ["atspi-2"]
-        pkgresult = [["../../build/linux/debian_bullseye_amd64-sysroot/usr/include/at-spi-2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/dbus-1.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/x86_64-linux-gnu/dbus-1.0/include", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/glib-2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/x86_64-linux-gnu/glib-2.0/include"], [], ["atspi", "dbus-1", "glib-2.0"], []]
-      },
-      {
-        args = ["dbus-1"]
-        pkgresult = [["../../build/linux/debian_bullseye_amd64-sysroot/usr/include/dbus-1.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/x86_64-linux-gnu/dbus-1.0/include" ], [], [ "dbus-1" ], []]
-      },
-      {
-        args = ["dri"]
-        pkgresult = [["../../build/linux/debian_bullseye_amd64-sysroot/usr/include/libdrm"], [], [], []]
-      },
-      {
-        args = ["egl"]
-        pkgresult = [[], [], [ "EGL" ], []]
-      },
-      {
-        args = ["gbm"]
-        pkgresult = [[], [], [ "gbm" ], []]
-      },
-      {
-        args = ["gio-2.0", "gio-unix-2.0"]
-        pkgresult = [["../../build/linux/debian_bullseye_amd64-sysroot/usr/include/glib-2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/x86_64-linux-gnu/glib-2.0/include", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/libmount", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/blkid", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/gio-unix-2.0" ], [], [ "gio-2.0", "gobject-2.0", "glib-2.0", ], []]
-      },
-      {
-        args = ["gl"]
-        pkgresult = [[], [], [ "GL" ], []]
-      },
-      {
-        args = ["gmodule-2.0", "gthread-2.0", "gtk+-3.0"]
-        pkgresult = [["../../build/linux/debian_bullseye_amd64-sysroot/usr/include/glib-2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/x86_64-linux-gnu/glib-2.0/include", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/gtk-3.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/pango-1.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/harfbuzz", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/freetype2", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/libpng16", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/libmount", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/blkid", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/fribidi", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/uuid", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/cairo", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/pixman-1", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/gdk-pixbuf-2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/gio-unix-2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/atk-1.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/at-spi2-atk/2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/dbus-1.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/x86_64-linux-gnu/dbus-1.0/include", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/at-spi-2.0"], [], ["gmodule-2.0", "glib-2.0", "gthread-2.0", "glib-2.0", "gtk-3", "gdk-3", "pangocairo-1.0", "pango-1.0", "harfbuzz", "atk-1.0", "cairo-gobject", "cairo", "gdk_pixbuf-2.0", "gio-2.0", "gobject-2.0", "glib-2.0"], []]
-      },
-      {
-        args = ["gmodule-2.0", "gthread-2.0", "gtk+-3.0", "gtk+-unix-print-3.0"]
-        pkgresult = [["../../build/linux/debian_bullseye_amd64-sysroot/usr/include/glib-2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/x86_64-linux-gnu/glib-2.0/include", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/gtk-3.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/pango-1.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/harfbuzz", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/freetype2", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/libpng16", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/libmount", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/blkid", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/fribidi", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/uuid", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/cairo", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/pixman-1", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/gdk-pixbuf-2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/gio-unix-2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/atk-1.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/at-spi2-atk/2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/dbus-1.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/x86_64-linux-gnu/dbus-1.0/include", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/at-spi-2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/gtk-3.0/unix-print"], [], ["gmodule-2.0", "glib-2.0", "gthread-2.0", "glib-2.0", "gtk-3", "gdk-3", "pangocairo-1.0", "pango-1.0", "harfbuzz", "atk-1.0", "cairo-gobject", "cairo", "gdk_pixbuf-2.0", "gio-2.0", "gobject-2.0", "glib-2.0"], []]
-      },
-      {
-        args = ["gmodule-2.0", "gthread-2.0", "gtk4"]
-        pkgresult = [["../../build/linux/debian_bullseye_amd64-sysroot/usr/include/glib-2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/x86_64-linux-gnu/glib-2.0/include", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/gtk-4.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/pango-1.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/harfbuzz", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/freetype2", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/libpng16", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/libmount", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/blkid", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/fribidi", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/uuid", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/cairo", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/pixman-1", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/gdk-pixbuf-2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/graphene-1.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/x86_64-linux-gnu/graphene-1.0/include"], ["-mfpmath=sse", "-msse", "-msse2"], ["gmodule-2.0", "glib-2.0", "gthread-2.0", "glib-2.0", "gtk-4", "pangocairo-1.0", "pango-1.0", "harfbuzz", "gdk_pixbuf-2.0", "cairo-gobject", "cairo", "graphene-1.0", "gio-2.0", "gobject-2.0", "glib-2.0"], []]
-      },
-      {
-        args = ["gmodule-2.0", "gthread-2.0", "gtk4", "gtk4-unix-print"]
-        pkgresult = [["../../build/linux/debian_bullseye_amd64-sysroot/usr/include/glib-2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/x86_64-linux-gnu/glib-2.0/include", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/gtk-4.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/pango-1.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/harfbuzz", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/freetype2", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/libpng16", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/libmount", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/blkid", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/fribidi", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/uuid", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/cairo", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/pixman-1", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/gdk-pixbuf-2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/graphene-1.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/x86_64-linux-gnu/graphene-1.0/include", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/gtk-4.0/unix-print"], ["-mfpmath=sse", "-msse", "-msse2"], ["gmodule-2.0", "glib-2.0", "gthread-2.0", "glib-2.0", "gtk-4", "pangocairo-1.0", "pango-1.0", "harfbuzz", "gdk_pixbuf-2.0", "cairo-gobject", "cairo", "graphene-1.0", "gio-2.0", "gobject-2.0", "glib-2.0"], []]
-      },
-      {
-        args = ["glib-2.0", "gmodule-2.0", "gobject-2.0", "gthread-2.0"]
-        pkgresult = [["../../build/linux/debian_bullseye_amd64-sysroot/usr/include/glib-2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/x86_64-linux-gnu/glib-2.0/include"], [], ["gmodule-2.0", "glib-2.0", "gobject-2.0", "gthread-2.0", "glib-2.0"], []]
-      },
-      {
-        args = ["libdrm"]
-        pkgresult = [["../../build/linux/debian_bullseye_amd64-sysroot/usr/include/libdrm" ], [], [ "drm" ], []]
-      },
-      {
-        args = ["libffi"]
-        pkgresult = [[], [], ["ffi"], []]
-      },
-      {
-        args = ["libpipewire-0.3"]
-        pkgresult = [["../../build/linux/debian_bullseye_amd64-sysroot/usr/include/pipewire-0.3", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/spa-0.2" ], [ "-D_REENTRANT" ], [ "pipewire-0.3" ], []]
-      },
-      {
-        args = ["libudev"]
-        pkgresult = [[], [], ["udev"], []]
-      },
-      {
-        args = ["libva"]
-        pkgresult = [[], [], ["va"], []]
-      },
-      {
-        args = ["nss", "-v", "-lssl3"]
-        pkgresult = [["../../build/linux/debian_bullseye_amd64-sysroot/usr/include/nss", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/nspr" ], [], [ "nss3", "nssutil3", "smime3", "plds4", "plc4", "nspr4" ], []]
-      },
-      {
-        args = ["pangocairo", "-v", "freetype"]
-        pkgresult = [["../../build/linux/debian_bullseye_amd64-sysroot/usr/include/pango-1.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/glib-2.0", "../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/x86_64-linux-gnu/glib-2.0/include", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/harfbuzz", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/libpng16", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/libmount", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/blkid", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/fribidi", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/uuid", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/cairo", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/pixman-1"], [], ["pangocairo-1.0", "pango-1.0", "gobject-2.0", "glib-2.0", "harfbuzz", "cairo"], []]
-      },
-      {
-        args = ["Qt5Core", "Qt5Widgets"]
-        pkgresult = [["../../build/linux/debian_bullseye_amd64-sysroot/usr/include/x86_64-linux-gnu/qt5/QtCore", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/x86_64-linux-gnu/qt5", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/x86_64-linux-gnu/qt5/QtWidgets", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/x86_64-linux-gnu/qt5/QtGui"], ["-DQT_WIDGETS_LIB", "-DQT_GUI_LIB", "-DQT_CORE_LIB"], ["Qt5Widgets", "Qt5Gui", "Qt5Core"], []]
-      },
-      {
-        args = ["Qt6Core", "Qt6Widgets"]
-        pkgresult = [["../../build/linux/debian_bullseye_amd64-sysroot/usr/include/x86_64-linux-gnu/qt6/QtCore", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/x86_64-linux-gnu/qt6", "../../build/linux/debian_bullseye_amd64-sysroot/usr/lib/x86_64-linux-gnu/qt6/mkspecs/linux-g++", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/x86_64-linux-gnu/qt6/QtWidgets", "../../build/linux/debian_bullseye_amd64-sysroot/usr/include/x86_64-linux-gnu/qt6/QtGui"], ["-DQT_WIDGETS_LIB", "-DQT_GUI_LIB", "-DQT_CORE_LIB"], ["Qt6Widgets", "Qt6Gui", "Qt6Core"], []]
-      },
-      {
-        args = ["xkbcommon"]
-        pkgresult = [[], [], ["xkbcommon"], []]
-      },
-    ]
-  },
-]
diff --git a/build/config/linux/pkg_config.gni b/build/config/linux/pkg_config.gni
index 67f39f5..47fccd12 100644
--- a/build/config/linux/pkg_config.gni
+++ b/build/config/linux/pkg_config.gni
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/config/compute_inputs_for_analyze.gni")
 import("//build/config/sysroot.gni")
 import("//build/toolchain/rbe.gni")
 
@@ -57,14 +56,10 @@
 
 common_pkg_config_args = []
 if (sysroot != "") {
-  _rebased_sysroot = rebase_path(sysroot, root_build_dir)
-  _cached_results = read_file("cached_results.scope", "scope")
-  _cached_results = _cached_results.data
-
   # Pass the sysroot if we're using one (it requires the CPU arch also).
   common_pkg_config_args += [
     "-s",
-    _rebased_sysroot,
+    rebase_path(sysroot),
     "-a",
     current_cpu,
   ]
@@ -99,69 +94,29 @@
          "Variable |packages| must be defined to be a list in pkg_config.")
   config(target_name) {
     if (host_toolchain == current_toolchain) {
-      _cache_args = host_pkg_config_args + invoker.packages
+      args = common_pkg_config_args + host_pkg_config_args + invoker.packages
     } else {
-      _cache_args = pkg_config_args + invoker.packages
+      args = common_pkg_config_args + pkg_config_args + invoker.packages
     }
     if (defined(invoker.extra_args)) {
-      _cache_args += invoker.extra_args
+      args += invoker.extra_args
     }
 
-    # exec_script() is slow, so cache results.
-    if (sysroot != "") {
-      foreach(_entry, _cached_results) {
-        if (_rebased_sysroot == _entry.sysroot) {
-          foreach(_subentry, _entry.entries) {
-            if (_subentry.args == _cache_args) {
-              pkgresult = _subentry.pkgresult
-            }
-          }
-
-          # Do not expect cache hits when:
-          #  * No entries exist for the sysroot.
-          #  * It's a package outside of the core ones in //build/config/linux
-          _expected_cache_hit =
-              filter_include([ get_path_info(".", "abspath") ],
-                             [ "//build/config/linux/*" ]) != []
-          not_needed([ "_expected_cache_hit" ])
-        }
-      }
-    }
-
-    if (!defined(pkgresult)) {
-      _script_args = common_pkg_config_args + _cache_args
-      pkgresult = exec_script(pkg_config_script, _script_args, "json")
-      if (defined(_expected_cache_hit) && _expected_cache_hit) {
-        print("sysroot=$_rebased_sysroot")
-        print("      {")
-        print("        args = $_cache_args")
-        print("        pkgresult = $pkgresult")
-        print("      },")
-        assert(
-            false,
-            "Non-cached pkg_config query. Please update //build/config/linux/cached_results.scope with the above.")
-      }
-    } else if (compute_inputs_for_analyze) {
-      # Generally, only bots add this arg. Use it to ensure cache is not stale.
-      _script_args = common_pkg_config_args + _cache_args
-      _expected_pkgresult = exec_script(pkg_config_script, _script_args, "json")
-      if (pkgresult != _expected_pkgresult) {
-        print("sysroot=$_rebased_sysroot")
-        print("      {")
-        print("        args = $_cache_args")
-        print("        pkgresult = $_expected_pkgresult")
-        print("      },")
-        assert(
-            false,
-            "Outdated pkg_config query result detected. Please update //build/config/linux/cached_results.scope with the above.")
-      }
-    }
+    pkgresult = exec_script(pkg_config_script, args, "json")
     cflags = pkgresult[1]
 
     foreach(include, pkgresult[0]) {
       # We want the system include paths to use -isystem instead of -I to
       # suppress warnings in those headers.
-      cflags += [ "-isystem$include" ]
+      # When building remotely, we make the path relative just as for use_sysroot.
+      # This ensures we are using the header files that match the platform we are
+      # building for.
+      if (use_sysroot || use_remoteexec) {
+        include_relativized = rebase_path(include, root_build_dir)
+        cflags += [ "-isystem$include_relativized" ]
+      } else {
+        cflags += [ "-isystem$include" ]
+      }
     }
 
     if (!defined(invoker.ignore_libs) || !invoker.ignore_libs) {
diff --git a/cc/test/fake_proxy.cc b/cc/test/fake_proxy.cc
index 5cf4ea3e..cc4d0e80 100644
--- a/cc/test/fake_proxy.cc
+++ b/cc/test/fake_proxy.cc
@@ -32,7 +32,9 @@
 
 bool FakeProxy::CommitRequested() const { return false; }
 
-void FakeProxy::QueueImageDecode(int request_id, const DrawImage& image) {}
+void FakeProxy::QueueImageDecode(int request_id,
+                                 const DrawImage& image,
+                                 bool speculative) {}
 
 void FakeProxy::SetMutator(std::unique_ptr<LayerTreeMutator> mutator) {}
 
diff --git a/cc/test/fake_proxy.h b/cc/test/fake_proxy.h
index 183c119..bcb139d 100644
--- a/cc/test/fake_proxy.h
+++ b/cc/test/fake_proxy.h
@@ -48,7 +48,9 @@
   void SetShouldThrottleFrameRate(bool flag) override {}
   void Start() override {}
   void Stop() override {}
-  void QueueImageDecode(int request_id, const DrawImage& image) override;
+  void QueueImageDecode(int request_id,
+                        const DrawImage& image,
+                        bool speculative) override;
   void SetMutator(std::unique_ptr<LayerTreeMutator> mutator) override;
   void SetPaintWorkletLayerPainter(
       std::unique_ptr<PaintWorkletLayerPainter> painter) override;
diff --git a/cc/test/stub_decode_cache.cc b/cc/test/stub_decode_cache.cc
index 674a092..bf9a9bc 100644
--- a/cc/test/stub_decode_cache.cc
+++ b/cc/test/stub_decode_cache.cc
@@ -15,9 +15,9 @@
 }
 
 ImageDecodeCache::TaskResult
-StubDecodeCache::GetOutOfRasterDecodeTaskForImageAndRef(
-    ClientId client_id,
-    const DrawImage& image) {
+StubDecodeCache::GetOutOfRasterDecodeTaskForImageAndRef(ClientId client_id,
+                                                        const DrawImage& image,
+                                                        bool speculative) {
   return TaskResult(/*need_unref=*/true, /*is_at_raster_decode=*/false,
                     /*can_do_hardware_accelerated_decode=*/false);
 }
diff --git a/cc/test/stub_decode_cache.h b/cc/test/stub_decode_cache.h
index 292763b..aa99f65 100644
--- a/cc/test/stub_decode_cache.h
+++ b/cc/test/stub_decode_cache.h
@@ -17,9 +17,9 @@
   TaskResult GetTaskForImageAndRef(ClientId client_id,
                                    const DrawImage& image,
                                    const TracingInfo& tracing_info) override;
-  TaskResult GetOutOfRasterDecodeTaskForImageAndRef(
-      ClientId client_id,
-      const DrawImage& image) override;
+  TaskResult GetOutOfRasterDecodeTaskForImageAndRef(ClientId client_id,
+                                                    const DrawImage& image,
+                                                    bool speculative) override;
   void UnrefImage(const DrawImage& image) override {}
   DecodedDrawImage GetDecodedImageForDraw(const DrawImage& image) override;
   void DrawWithImageFinished(const DrawImage& image,
diff --git a/cc/tiles/checker_image_tracker.cc b/cc/tiles/checker_image_tracker.cc
index bb61822..bc2b17db 100644
--- a/cc/tiles/checker_image_tracker.cc
+++ b/cc/tiles/checker_image_tracker.cc
@@ -435,8 +435,10 @@
       "cc", "CheckerImageTracker::DeferImageDecode", TRACE_ID_LOCAL(image_id));
   ImageController::ImageDecodeRequestId request_id =
       image_controller_->QueueImageDecode(
-          draw_image, base::BindOnce(&CheckerImageTracker::DidFinishImageDecode,
-                                     weak_factory_.GetWeakPtr(), image_id));
+          draw_image,
+          base::BindOnce(&CheckerImageTracker::DidFinishImageDecode,
+                         weak_factory_.GetWeakPtr(), image_id),
+          /*speculative*/ false);
 
   image_id_to_decode_.emplace(image_id, std::make_unique<ScopedDecodeHolder>(
                                             image_controller_, request_id));
diff --git a/cc/tiles/checker_image_tracker_unittest.cc b/cc/tiles/checker_image_tracker_unittest.cc
index d50772d..7f5a287 100644
--- a/cc/tiles/checker_image_tracker_unittest.cc
+++ b/cc/tiles/checker_image_tracker_unittest.cc
@@ -56,9 +56,9 @@
     locked_images_.erase(id);
   }
 
-  ImageDecodeRequestId QueueImageDecode(
-      const DrawImage& image,
-      ImageDecodedCallback callback) override {
+  ImageDecodeRequestId QueueImageDecode(const DrawImage& image,
+                                        ImageDecodedCallback callback,
+                                        bool speculative) override {
     ImageDecodeRequestId request_id = next_image_request_id_++;
 
     decoded_images_.push_back(image);
diff --git a/cc/tiles/decoded_image_tracker.cc b/cc/tiles/decoded_image_tracker.cc
index 27685e4..1c7d2be 100644
--- a/cc/tiles/decoded_image_tracker.cc
+++ b/cc/tiles/decoded_image_tracker.cc
@@ -39,7 +39,8 @@
 
 void DecodedImageTracker::QueueImageDecode(
     const DrawImage& image,
-    base::OnceCallback<void(bool)> callback) {
+    base::OnceCallback<void(bool)> callback,
+    bool speculative) {
   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
                "DecodedImageTracker::QueueImageDecode", "frame_key",
                image.frame_key().ToString());
@@ -47,9 +48,11 @@
   // Queue the decode in the image controller, but switch out the callback for
   // our own.
   image_controller_->QueueImageDecode(
-      image, base::BindOnce(&DecodedImageTracker::ImageDecodeFinished,
-                            base::Unretained(this), std::move(callback),
-                            image.paint_image().stable_id()));
+      image,
+      base::BindOnce(&DecodedImageTracker::ImageDecodeFinished,
+                     base::Unretained(this), std::move(callback),
+                     image.paint_image().stable_id()),
+      speculative);
 }
 
 void DecodedImageTracker::UnlockAllImages() {
diff --git a/cc/tiles/decoded_image_tracker.h b/cc/tiles/decoded_image_tracker.h
index 3ab0588..aa253d8 100644
--- a/cc/tiles/decoded_image_tracker.h
+++ b/cc/tiles/decoded_image_tracker.h
@@ -42,7 +42,8 @@
   // completion. The callback takes a bool indicating whether the decode was
   // successful or not.
   void QueueImageDecode(const DrawImage& image,
-                        base::OnceCallback<void(bool)> callback);
+                        base::OnceCallback<void(bool)> callback,
+                        bool speculative);
 
   // Unlock all locked images - used to respond to memory pressure or
   // application background.
diff --git a/cc/tiles/decoded_image_tracker_unittest.cc b/cc/tiles/decoded_image_tracker_unittest.cc
index f31a442f..dc9abaa3 100644
--- a/cc/tiles/decoded_image_tracker_unittest.cc
+++ b/cc/tiles/decoded_image_tracker_unittest.cc
@@ -30,9 +30,9 @@
     locked_ids_.erase(it);
   }
 
-  ImageDecodeRequestId QueueImageDecode(
-      const DrawImage& image,
-      ImageDecodedCallback callback) override {
+  ImageDecodeRequestId QueueImageDecode(const DrawImage& image,
+                                        ImageDecodedCallback callback,
+                                        bool speculative) override {
     auto id = next_id_++;
     locked_ids_.insert(
         std::make_pair(id, SoftwareImageDecodeCache::CacheKey::FromDrawImage(
@@ -93,7 +93,8 @@
       DrawImageForDecoding(CreateDiscardablePaintImage(gfx::Size(1, 1)),
                            TargetColorParams()),
       base::BindOnce([](bool* locked, bool success) { *locked = true; },
-                     base::Unretained(&locked)));
+                     base::Unretained(&locked)),
+      /*speculative*/ false);
   EXPECT_TRUE(locked);
   EXPECT_EQ(1u, image_controller()->num_locked_images());
 }
@@ -109,7 +110,8 @@
   decoded_image_tracker()->QueueImageDecode(
       DrawImageForDecoding(paint_image, target_color_params),
       base::BindOnce([](bool* locked, bool success) { *locked = true; },
-                     base::Unretained(&locked)));
+                     base::Unretained(&locked)),
+      /*speculative*/ false);
 
   // Check that the decoded color space images are locked, but if the color
   // space differs then that image is not locked. Note that we use the high
@@ -134,7 +136,8 @@
       DrawImageForDecoding(CreateDiscardablePaintImage(gfx::Size(1, 1)),
                            TargetColorParams()),
       base::BindOnce([](bool* locked, bool success) { *locked = true; },
-                     base::Unretained(&locked)));
+                     base::Unretained(&locked)),
+      /*speculative*/ false);
   EXPECT_TRUE(locked);
   EXPECT_EQ(1u, image_controller()->num_locked_images());
 
@@ -148,7 +151,8 @@
       DrawImageForDecoding(CreateDiscardablePaintImage(gfx::Size(1, 1)),
                            TargetColorParams()),
       base::BindOnce([](bool* locked, bool success) { *locked = true; },
-                     base::Unretained(&locked)));
+                     base::Unretained(&locked)),
+      /*speculative*/ false);
   EXPECT_TRUE(locked);
   EXPECT_EQ(2u, image_controller()->num_locked_images());
 
@@ -171,7 +175,8 @@
   decoded_image_tracker()->QueueImageDecode(
       DrawImageForDecoding(paint_image_1, target_color_params),
       base::BindOnce([](bool* locked, bool success) { *locked = true; },
-                     base::Unretained(&locked)));
+                     base::Unretained(&locked)),
+      /*speculative*/ false);
   EXPECT_TRUE(locked);
   EXPECT_EQ(1u, image_controller()->num_locked_images());
 
@@ -180,7 +185,8 @@
   decoded_image_tracker()->QueueImageDecode(
       DrawImageForDecoding(paint_image_2, target_color_params),
       base::BindOnce([](bool* locked, bool success) { *locked = true; },
-                     base::Unretained(&locked)));
+                     base::Unretained(&locked)),
+      /*speculative*/ false);
   EXPECT_TRUE(locked);
   EXPECT_EQ(2u, image_controller()->num_locked_images());
 
@@ -211,7 +217,8 @@
       DrawImageForDecoding(CreateDiscardablePaintImage(gfx::Size(1, 1)),
                            TargetColorParams()),
       base::BindOnce([](bool* locked, bool success) { *locked = true; },
-                     base::Unretained(&locked)));
+                     base::Unretained(&locked)),
+      /*speculative*/ false);
   EXPECT_TRUE(locked);
   EXPECT_EQ(1u, image_controller()->num_locked_images());
   locked = false;
@@ -219,7 +226,8 @@
       DrawImageForDecoding(CreateDiscardablePaintImage(gfx::Size(1, 1)),
                            TargetColorParams()),
       base::BindOnce([](bool* locked, bool success) { *locked = true; },
-                     base::Unretained(&locked)));
+                     base::Unretained(&locked)),
+      /*speculative*/ false);
   EXPECT_TRUE(locked);
   EXPECT_EQ(2u, image_controller()->num_locked_images());
 
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc
index 2ede643..c5ee6988 100644
--- a/cc/tiles/gpu_image_decode_cache.cc
+++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -560,7 +560,7 @@
       cache_key.target_color_space.GetHash(),
       base::HashInts(
           cache_key.frame_key.hash(),
-          base::HashInts(cache_key.upload_scale_mip_level,
+          base::HashInts(cache_key.mip_level(),
                          static_cast<int>(cache_key.filter_quality))));
 }
 
@@ -935,6 +935,24 @@
   OnUnlock();
 }
 
+void GpuImageDecodeCache::ImageData::RecordSpeculativeDecodeMatch(
+    int mip_level) {
+  if (speculative_decode_usage_stats_.has_value()) {
+    speculative_decode_usage_stats_->min_raster_mip_level = std::min(
+        speculative_decode_usage_stats_->min_raster_mip_level, mip_level);
+  }
+}
+
+void GpuImageDecodeCache::ImageData::
+    RecordSpeculativeDecodeRasterTaskTakeover() {
+  if (speculative_decode_usage_stats_.has_value()) {
+    speculative_decode_usage_stats_->raster_task_takeover = true;
+    TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("loading"),
+                         "SpeculativeImageDecodeRasterTaskTakeover",
+                         TRACE_EVENT_SCOPE_THREAD, "image_id", paint_image_id);
+  }
+}
+
 void GpuImageDecodeCache::DecodedImageData::ResetData() {
   if (aux_image_data_[kAuxImageIndexDefault].data) {
     ReportUsageStats();
@@ -1082,21 +1100,22 @@
 // GpuImageDecodeCache::ImageData
 
 GpuImageDecodeCache::ImageData::ImageData(
-    PaintImage::Id paint_image_id,
+    PaintImage::Id paint_image_id_param,
     DecodedDataMode mode,
     const gfx::ColorSpace& target_color_space,
     PaintFlags::FilterQuality quality,
-    int upload_scale_mip_level,
+    int upload_scale_mip_level_param,
     bool needs_mips,
     bool is_bitmap_backed,
     bool can_do_hardware_accelerated_decode,
     bool do_hardware_accelerated_decode,
+    bool speculative_decode,
     base::span<ImageInfo, kAuxImageCount> image_info)
-    : paint_image_id(paint_image_id),
+    : paint_image_id(paint_image_id_param),
       mode(mode),
       target_color_space(target_color_space),
       quality(quality),
-      upload_scale_mip_level(upload_scale_mip_level),
+      upload_scale_mip_level(upload_scale_mip_level_param),
       needs_mips(needs_mips),
       is_bitmap_backed(is_bitmap_backed),
       info(std::move(image_info[kAuxImageIndexDefault])),
@@ -1112,6 +1131,15 @@
   if (base::FeatureList::IsEnabled(features::kInitImageDecodeLastUseTime)) {
     last_use = base::TimeTicks::Now();
   }
+  if (speculative_decode) {
+    speculative_decode_usage_stats_.emplace();
+    speculative_decode_usage_stats_->speculative_decode_mip_level =
+        upload_scale_mip_level;
+    TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("loading"),
+                         "SpeculativeImageDecodeTaskCreated",
+                         TRACE_EVENT_SCOPE_THREAD, "image_id", paint_image_id,
+                         "speculative_mip_level", upload_scale_mip_level);
+  }
 }
 
 GpuImageDecodeCache::ImageData::~ImageData() {
@@ -1123,6 +1151,13 @@
   // This should always be cleaned up before deleting the image, as it needs to
   // be freed with the GL context lock held.
   DCHECK(!HasUploadedData());
+  if (IsSpeculativeDecode() &&
+      speculative_decode_usage_stats_->min_raster_mip_level == INT_MAX) {
+    TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("loading"),
+                         "SpeculativeImageDecodeUnused",
+                         TRACE_EVENT_SCOPE_THREAD, "image_id", paint_image_id);
+  }
+  speculative_decode_usage_stats_.reset();
 }
 
 bool GpuImageDecodeCache::ImageData::IsGpuOrTransferCache() const {
@@ -1276,23 +1311,26 @@
     const DrawImage& draw_image,
     const TracingInfo& tracing_info) {
   return GetTaskForImageAndRefInternal(client_id, draw_image, tracing_info,
-                                       TaskType::kInRaster);
+                                       TaskType::kInRaster,
+                                       /*speculative*/ false);
 }
 
 ImageDecodeCache::TaskResult
 GpuImageDecodeCache::GetOutOfRasterDecodeTaskForImageAndRef(
     ClientId client_id,
-    const DrawImage& draw_image) {
+    const DrawImage& draw_image,
+    bool speculative) {
   return GetTaskForImageAndRefInternal(client_id, draw_image,
                                        TracingInfo(0, TilePriority::NOW),
-                                       TaskType::kOutOfRaster);
+                                       TaskType::kOutOfRaster, speculative);
 }
 
 ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal(
     ClientId client_id,
     const DrawImage& draw_image,
     const TracingInfo& tracing_info,
-    TaskType task_type) {
+    TaskType task_type,
+    bool speculative) {
   DCHECK_GE(client_id, kDefaultClientId);
 
   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
@@ -1306,7 +1344,8 @@
 
   base::AutoLock locker(lock_);
   const InUseCacheKey cache_key = InUseCacheKeyFromDrawImage(draw_image);
-  ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
+  ImageData* image_data = GetImageDataForDrawImage(
+      draw_image, cache_key, task_type == TaskType::kInRaster);
   scoped_refptr<ImageData> new_data;
   if (!image_data) {
     // We need an ImageData, create one now. Note that hardware decode
@@ -1315,7 +1354,8 @@
     // through hardware decode acceleration.
     new_data = CreateImageData(
         draw_image,
-        task_type == TaskType::kInRaster /* allow_hardware_decode */);
+        task_type == TaskType::kInRaster /* allow_hardware_decode */,
+        speculative);
     image_data = new_data.get();
   } else if (image_data->decode.decode_failure) {
     // We have already tried and failed to decode this image, so just return.
@@ -1470,10 +1510,11 @@
 
   base::AutoLock lock(lock_);
   const InUseCacheKey cache_key = InUseCacheKeyFromDrawImage(draw_image);
-  ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
+  ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key, true);
   if (!image_data) {
     // We didn't find the image, create a new entry.
-    auto data = CreateImageData(draw_image, true /* allow_hardware_decode */);
+    auto data = CreateImageData(draw_image, true /* allow_hardware_decode */,
+                                false /* speculative_decode */);
     image_data = data.get();
     AddToPersistentCache(draw_image, std::move(data));
   }
@@ -2102,6 +2143,7 @@
         // raster task primary.
         if (stand_alone_task->state().IsNew()) {
           result->SetExternalDependent(stand_alone_task);
+          image_data->RecordSpeculativeDecodeRasterTaskTakeover();
         } else {
           stand_alone_task->SetExternalDependent(result);
         }
@@ -2219,6 +2261,7 @@
       image_data->mode != DecodedDataMode::kCpu &&
       image_data->HasUploadedData()) {
     image_data->decode.ResetData();
+    image_data->speculative_decode_usage_stats_.reset();
   }
 
   // If we have no refs on an uploaded image, it should be unlocked. Do this
@@ -2429,7 +2472,9 @@
     return;
   }
 
-  TRACE_EVENT0("cc,benchmark", "GpuImageDecodeCache::DecodeImage");
+  TRACE_EVENT2("cc,benchmark", "GpuImageDecodeCache::DecodeImage",
+               "speculative", image_data->IsSpeculativeDecode(),
+               "paint_image_id", image_data->paint_image_id);
 
   image_data->decode.ResetData();
 
@@ -2905,7 +2950,8 @@
 
 scoped_refptr<GpuImageDecodeCache::ImageData>
 GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image,
-                                     bool allow_hardware_decode) {
+                                     bool allow_hardware_decode,
+                                     bool speculative_decode) {
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
                "GpuImageDecodeCache::CreateImageData");
   std::array<ImageInfo, kAuxImageCount> image_info;
@@ -3033,7 +3079,7 @@
       draw_image.target_color_space(),
       CalculateDesiredFilterQuality(draw_image), upload_scale_mip_level,
       needs_mips, is_bitmap_backed, can_do_hardware_accelerated_decode,
-      do_hardware_accelerated_decode, image_info));
+      do_hardware_accelerated_decode, speculative_decode, image_info));
 }
 
 void GpuImageDecodeCache::WillAddCacheEntry(const DrawImage& draw_image) {
@@ -3335,22 +3381,58 @@
 // cannot be found, it looks for a compatible entry in our |persistent_cache_|.
 GpuImageDecodeCache::ImageData* GpuImageDecodeCache::GetImageDataForDrawImage(
     const DrawImage& draw_image,
-    const InUseCacheKey& key) {
+    const InUseCacheKey& key,
+    bool record_speculative_decode_stats) {
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
                "GpuImageDecodeCache::GetImageDataForDrawImage");
   DCHECK(UseCacheForDrawImage(draw_image));
 
   auto found_in_use = in_use_cache_.find(key);
-  if (found_in_use != in_use_cache_.end())
-    return found_in_use->second.image_data.get();
+  if (found_in_use != in_use_cache_.end()) {
+    scoped_refptr<ImageData>& image_data = found_in_use->second.image_data;
+    if (image_data->IsSpeculativeDecode() && record_speculative_decode_stats) {
+      if (!image_data->SpeculativeDecodeHasMatched()) {
+        TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("loading"),
+                             "SpeculativeImageDecodeInUseMatch",
+                             TRACE_EVENT_SCOPE_THREAD, "image_id",
+                             image_data->paint_image_id, "raster_mip_level",
+                             key.mip_level());
+      }
+      image_data->RecordSpeculativeDecodeMatch(
+          image_data->upload_scale_mip_level);
+    }
+    return image_data.get();
+  }
 
   auto found_persistent = persistent_cache_.Get(draw_image.frame_key());
   if (found_persistent != persistent_cache_.end()) {
-    ImageData* image_data = found_persistent->second.get();
-    if (IsCompatible(image_data, draw_image)) {
+    scoped_refptr<ImageData>& image_data = found_persistent->second;
+    bool first_match = !image_data->SpeculativeDecodeHasMatched();
+    if (image_data->IsSpeculativeDecode() && record_speculative_decode_stats) {
+      image_data->RecordSpeculativeDecodeMatch(key.mip_level());
+    }
+    if (IsCompatible(image_data.get(), draw_image)) {
       image_data->last_use = base::TimeTicks::Now();
-      return image_data;
+      if (image_data->IsSpeculativeDecode() &&
+          record_speculative_decode_stats) {
+        if (first_match) {
+          TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("loading"),
+                               "SpeculativeImageDecodeCompatibleMatch",
+                               TRACE_EVENT_SCOPE_THREAD, "image_id",
+                               image_data->paint_image_id, "raster_mip_level",
+                               key.mip_level());
+        }
+      }
+      return image_data.get();
     } else {
+      if (image_data->IsSpeculativeDecode() &&
+          record_speculative_decode_stats) {
+        TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("loading"),
+                             "SpeculativeImageDecodeIncompatibleMatch",
+                             TRACE_EVENT_SCOPE_THREAD, "image_id",
+                             image_data->paint_image_id, "raster_mip_level",
+                             key.mip_level());
+      }
       RemoveFromPersistentCache(found_persistent);
     }
   }
@@ -3395,8 +3477,8 @@
 
 size_t GpuImageDecodeCache::GetDrawImageSizeForTesting(const DrawImage& image) {
   base::AutoLock lock(lock_);
-  scoped_refptr<ImageData> data =
-      CreateImageData(image, false /* allow_hardware_decode */);
+  scoped_refptr<ImageData> data = CreateImageData(
+      image, false /* allow_hardware_decode */, false /* speculative_decode */);
   return data->GetTotalSize();
 }
 
diff --git a/cc/tiles/gpu_image_decode_cache.h b/cc/tiles/gpu_image_decode_cache.h
index aacdd45..94298e2 100644
--- a/cc/tiles/gpu_image_decode_cache.h
+++ b/cc/tiles/gpu_image_decode_cache.h
@@ -169,9 +169,9 @@
                                    const DrawImage& image,
                                    const TracingInfo& tracing_info) override;
   // See |GetTaskForImageAndRefInternal| to learn about the |client_id|.
-  TaskResult GetOutOfRasterDecodeTaskForImageAndRef(
-      ClientId client_id,
-      const DrawImage& image) override;
+  TaskResult GetOutOfRasterDecodeTaskForImageAndRef(ClientId client_id,
+                                                    const DrawImage& image,
+                                                    bool speculative) override;
   void UnrefImage(const DrawImage& image) override;
   DecodedDrawImage GetDecodedImageForDraw(const DrawImage& draw_image) override;
   void DrawWithImageFinished(const DrawImage& image,
@@ -602,6 +602,7 @@
               bool is_bitmap_backed,
               bool can_do_hardware_accelerated_decode,
               bool do_hardware_accelerated_decode,
+              bool speculative_decode,
               base::span<ImageInfo, kAuxImageCount> image_info);
 
     bool IsGpuOrTransferCache() const;
@@ -624,6 +625,16 @@
     // used by all auxiliary images.
     size_t GetTotalSize() const;
 
+    bool IsSpeculativeDecode() const {
+      return speculative_decode_usage_stats_.has_value();
+    }
+    bool SpeculativeDecodeHasMatched() const {
+      return IsSpeculativeDecode() &&
+             speculative_decode_usage_stats_->min_raster_mip_level < INT_MAX;
+    }
+    void RecordSpeculativeDecodeMatch(int mip_level);
+    void RecordSpeculativeDecodeRasterTaskTakeover();
+
     const PaintImage::Id paint_image_id;
     const DecodedDataMode mode;
     const gfx::ColorSpace target_color_space;
@@ -649,6 +660,13 @@
     DecodedImageData decode;
     UploadedImageData upload;
 
+    struct SpeculativeDecodeUsageStats {
+      int speculative_decode_mip_level = -1;
+      int min_raster_mip_level = INT_MAX;
+      bool raster_task_takeover = false;
+    };
+    std::optional<SpeculativeDecodeUsageStats> speculative_decode_usage_stats_;
+
    private:
     friend class base::RefCountedThreadSafe<ImageData>;
     ~ImageData();
@@ -671,7 +689,7 @@
   struct InUseCacheKeyHash;
   struct InUseCacheKey {
     InUseCacheKey(const DrawImage& draw_image, int mip_level);
-
+    int mip_level() const { return upload_scale_mip_level; }
     bool operator==(const InUseCacheKey& other) const;
 
    private:
@@ -714,7 +732,8 @@
   TaskResult GetTaskForImageAndRefInternal(ClientId client_id,
                                            const DrawImage& image,
                                            const TracingInfo& tracing_info,
-                                           TaskType task_type);
+                                           TaskType task_type,
+                                           bool speculative);
 
   void RefImageDecode(const DrawImage& draw_image,
                       const InUseCacheKey& cache_key)
@@ -771,7 +790,8 @@
 
   scoped_refptr<GpuImageDecodeCache::ImageData> CreateImageData(
       const DrawImage& image,
-      bool allow_hardware_decode);
+      bool allow_hardware_decode,
+      bool speculative_decode);
   void WillAddCacheEntry(const DrawImage& draw_image)
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
@@ -783,8 +803,10 @@
 
   // Finds the ImageData that should be used for the given DrawImage. Looks
   // first in the |in_use_cache_|, and then in the |persistent_cache_|.
-  ImageData* GetImageDataForDrawImage(const DrawImage& image,
-                                      const InUseCacheKey& key)
+  ImageData* GetImageDataForDrawImage(
+      const DrawImage& image,
+      const InUseCacheKey& key,
+      bool record_speculative_decode_stats = false)
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
   // Returns true if the given ImageData can be used to draw the specified
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc
index 186f267..b31a4cd3 100644
--- a/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -806,7 +806,8 @@
   TileTask* raster_decode_task = raster_result.task->dependencies()[0].get();
 
   ImageDecodeCache::TaskResult stand_alone_result =
-      cache->GetOutOfRasterDecodeTaskForImageAndRef(client_id, draw_image);
+      cache->GetOutOfRasterDecodeTaskForImageAndRef(client_id, draw_image,
+                                                    /*speculative*/ false);
   EXPECT_TRUE(stand_alone_result.need_unref);
   EXPECT_EQ(stand_alone_result.task->dependencies().size(), 1u);
   EXPECT_EQ(stand_alone_result.task->dependencies()[0].get(),
@@ -835,7 +836,8 @@
       CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
 
   ImageDecodeCache::TaskResult stand_alone_result =
-      cache->GetOutOfRasterDecodeTaskForImageAndRef(client_id, draw_image);
+      cache->GetOutOfRasterDecodeTaskForImageAndRef(client_id, draw_image,
+                                                    /*speculative*/ false);
   EXPECT_TRUE(stand_alone_result.need_unref);
   EXPECT_TRUE(stand_alone_result.task);
 
@@ -875,7 +877,8 @@
       CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
 
   ImageDecodeCache::TaskResult stand_alone_result =
-      cache->GetOutOfRasterDecodeTaskForImageAndRef(client_id, draw_image);
+      cache->GetOutOfRasterDecodeTaskForImageAndRef(client_id, draw_image,
+                                                    /*speculative*/ false);
   EXPECT_TRUE(stand_alone_result.need_unref);
   EXPECT_TRUE(stand_alone_result.task);
   TileTask* stand_alone_decode_task = stand_alone_result.task.get();
@@ -921,7 +924,8 @@
       CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
 
   ImageDecodeCache::TaskResult stand_alone_result =
-      cache->GetOutOfRasterDecodeTaskForImageAndRef(client_id, draw_image);
+      cache->GetOutOfRasterDecodeTaskForImageAndRef(client_id, draw_image,
+                                                    /*speculative*/ false);
   EXPECT_TRUE(stand_alone_result.need_unref);
   EXPECT_TRUE(stand_alone_result.task);
   TileTask* stand_alone_decode_task = stand_alone_result.task.get();
@@ -1171,8 +1175,8 @@
       CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
   EXPECT_EQ(another_draw_image.frame_index(), PaintImage::kDefaultFrameIndex);
   ImageDecodeCache::TaskResult result2 =
-      cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId1,
-                                                    another_draw_image);
+      cache->GetOutOfRasterDecodeTaskForImageAndRef(
+          kClientId1, another_draw_image, /*speculative*/ false);
   EXPECT_TRUE(result2.need_unref);
   // It must be a valid task.
   EXPECT_TRUE(result2.task);
@@ -1194,8 +1198,8 @@
             PaintImage::kDefaultFrameIndex);
   // Ask for the decode standalone task again.
   ImageDecodeCache::TaskResult result3 =
-      cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId1,
-                                                    yet_another_draw_image);
+      cache->GetOutOfRasterDecodeTaskForImageAndRef(
+          kClientId1, yet_another_draw_image, /*speculative*/ false);
   EXPECT_TRUE(result3.need_unref);
   // It mustn't be created now as we already have image decoded/uploaded.
   EXPECT_FALSE(result3.task);
@@ -2441,7 +2445,8 @@
                               PaintFlags::FilterQuality::kLow);
 
   ImageDecodeCache::TaskResult result =
-      cache->GetOutOfRasterDecodeTaskForImageAndRef(client_id, draw_image);
+      cache->GetOutOfRasterDecodeTaskForImageAndRef(client_id, draw_image,
+                                                    /*speculative*/ false);
   EXPECT_TRUE(result.need_unref);
   EXPECT_TRUE(result.task);
   EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
@@ -2477,7 +2482,8 @@
                                 PaintFlags::FilterQuality::kLow);
 
     ImageDecodeCache::TaskResult result1 =
-        cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId1, draw_image);
+        cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId1, draw_image,
+                                                      /*speculative*/ false);
     EXPECT_TRUE(result1.need_unref);
     EXPECT_TRUE(result1.task);
     EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
@@ -2486,7 +2492,8 @@
         CreateDrawImageInternal(image, matrix, nullptr /* color_space */,
                                 PaintFlags::FilterQuality::kLow);
     ImageDecodeCache::TaskResult result2 =
-        cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId2, draw_image);
+        cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId2, draw_image,
+                                                      /*speculative*/ false);
     EXPECT_TRUE(result2.need_unref);
     EXPECT_TRUE(result2.task);
     EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image2));
@@ -2536,7 +2543,8 @@
                               PaintFlags::FilterQuality::kLow);
 
   ImageDecodeCache::TaskResult result1 =
-      cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId1, draw_image);
+      cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId1, draw_image,
+                                                    /*speculative*/ false);
   EXPECT_TRUE(result1.need_unref);
   EXPECT_TRUE(result1.task);
   EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
@@ -2548,7 +2556,8 @@
       CreateDrawImageInternal(image, matrix, nullptr /* color_space */,
                               PaintFlags::FilterQuality::kLow);
   ImageDecodeCache::TaskResult result2 =
-      cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId2, draw_image);
+      cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId2, draw_image,
+                                                    /*speculative*/ false);
   EXPECT_TRUE(result2.need_unref);
   EXPECT_FALSE(result2.task);
   EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image2));
@@ -4192,7 +4201,8 @@
   PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
   DrawImage draw_image = CreateDrawImageInternal(image);
   ImageDecodeCache::TaskResult result =
-      cache->GetOutOfRasterDecodeTaskForImageAndRef(client_id, draw_image);
+      cache->GetOutOfRasterDecodeTaskForImageAndRef(client_id, draw_image,
+                                                    /*speculative*/ false);
   EXPECT_TRUE(result.need_unref);
   EXPECT_FALSE(result.task);
   EXPECT_FALSE(result.is_at_raster_decode);
@@ -4585,7 +4595,8 @@
                        CreateMatrix(SkSize::Make(1.0f, 1.0f)),
                        PaintImage::kDefaultFrameIndex, target_color_params);
   ImageDecodeCache::TaskResult result =
-      cache->GetOutOfRasterDecodeTaskForImageAndRef(client_id, draw_image);
+      cache->GetOutOfRasterDecodeTaskForImageAndRef(client_id, draw_image,
+                                                    /*speculative*/ false);
   EXPECT_TRUE(result.need_unref);
   ASSERT_TRUE(result.task);
   EXPECT_FALSE(result.can_do_hardware_accelerated_decode);
diff --git a/cc/tiles/image_controller.cc b/cc/tiles/image_controller.cc
index 1f7cd87f..7520646 100644
--- a/cc/tiles/image_controller.cc
+++ b/cc/tiles/image_controller.cc
@@ -333,7 +333,8 @@
 
 ImageController::ImageDecodeRequestId ImageController::QueueImageDecode(
     const DrawImage& draw_image,
-    ImageDecodedCallback callback) {
+    ImageDecodedCallback callback,
+    bool speculative) {
   // We must not receive any image requests if we have no worker.
   CHECK(worker_task_runner_);
 
@@ -356,7 +357,7 @@
       return id;
     }
     result = cache_->GetOutOfRasterDecodeTaskForImageAndRef(
-        image_cache_client_id_, draw_image);
+        image_cache_client_id_, draw_image, speculative);
   }
   // If we don't need to unref this, we don't actually have a task.
   DCHECK(result.need_unref || !result.task);
diff --git a/cc/tiles/image_controller.h b/cc/tiles/image_controller.h
index 4382099..59f381c 100644
--- a/cc/tiles/image_controller.h
+++ b/cc/tiles/image_controller.h
@@ -75,7 +75,8 @@
   // unlocked using UnlockImageDecode.
   // Virtual for testing.
   virtual ImageDecodeRequestId QueueImageDecode(const DrawImage& draw_image,
-                                                ImageDecodedCallback callback);
+                                                ImageDecodedCallback callback,
+                                                bool speculative);
 
   // Signals that an external dependency of `task` has completed.
   void ExternalDependencyCompletedForTask(scoped_refptr<TileTask> task);
diff --git a/cc/tiles/image_controller_unittest.cc b/cc/tiles/image_controller_unittest.cc
index c37e895..9ac59a7 100644
--- a/cc/tiles/image_controller_unittest.cc
+++ b/cc/tiles/image_controller_unittest.cc
@@ -55,9 +55,9 @@
     return TaskResult(/*need_unref=*/true, /*is_at_raster_decode=*/false,
                       /*can_do_hardware_accelerated_decode=*/false);
   }
-  TaskResult GetOutOfRasterDecodeTaskForImageAndRef(
-      uint32_t client_id,
-      const DrawImage& image) override {
+  TaskResult GetOutOfRasterDecodeTaskForImageAndRef(uint32_t client_id,
+                                                    const DrawImage& image,
+                                                    bool speculative) override {
     return GetTaskForImageAndRef(client_id, image, TracingInfo());
   }
 
@@ -285,9 +285,11 @@
   EXPECT_EQ(image().paint_image().width(), 1);
   ImageController::ImageDecodeRequestId expected_id =
       controller()->QueueImageDecode(
-          image(), base::BindOnce(&DecodeClient::Callback,
-                                  base::Unretained(&decode_client),
-                                  run_loop.QuitClosure()));
+          image(),
+          base::BindOnce(&DecodeClient::Callback,
+                         base::Unretained(&decode_client),
+                         run_loop.QuitClosure()),
+          /*speculative*/ false);
   RunOrTimeout(&run_loop);
   EXPECT_EQ(expected_id, decode_client.id());
   EXPECT_EQ(ImageController::ImageDecodeResult::SUCCESS,
@@ -302,9 +304,11 @@
 
   ImageController::ImageDecodeRequestId expected_id =
       controller()->QueueImageDecode(
-          image, base::BindOnce(&DecodeClient::Callback,
-                                base::Unretained(&decode_client),
-                                run_loop.QuitClosure()));
+          image,
+          base::BindOnce(&DecodeClient::Callback,
+                         base::Unretained(&decode_client),
+                         run_loop.QuitClosure()),
+          /*speculative*/ false);
   RunOrTimeout(&run_loop);
   EXPECT_EQ(expected_id, decode_client.id());
   EXPECT_EQ(ImageController::ImageDecodeResult::DECODE_NOT_REQUIRED,
@@ -318,9 +322,11 @@
   DrawImage image = CreateDiscardableDrawImage(gfx::Size(2000, 2000));
   ImageController::ImageDecodeRequestId expected_id =
       controller()->QueueImageDecode(
-          image, base::BindOnce(&DecodeClient::Callback,
-                                base::Unretained(&decode_client),
-                                run_loop.QuitClosure()));
+          image,
+          base::BindOnce(&DecodeClient::Callback,
+                         base::Unretained(&decode_client),
+                         run_loop.QuitClosure()),
+          /*speculative*/ false);
   RunOrTimeout(&run_loop);
   EXPECT_EQ(expected_id, decode_client.id());
   EXPECT_EQ(ImageController::ImageDecodeResult::FAILURE,
@@ -334,19 +340,23 @@
       controller()->QueueImageDecode(
           image(),
           base::BindOnce(&DecodeClient::Callback,
-                         base::Unretained(&decode_client1), base::DoNothing()));
+                         base::Unretained(&decode_client1), base::DoNothing()),
+          /*speculative*/ false);
   DecodeClient decode_client2;
   ImageController::ImageDecodeRequestId expected_id2 =
       controller()->QueueImageDecode(
           image(),
           base::BindOnce(&DecodeClient::Callback,
-                         base::Unretained(&decode_client2), base::DoNothing()));
+                         base::Unretained(&decode_client2), base::DoNothing()),
+          /*speculative*/ false);
   DecodeClient decode_client3;
   ImageController::ImageDecodeRequestId expected_id3 =
       controller()->QueueImageDecode(
-          image(), base::BindOnce(&DecodeClient::Callback,
-                                  base::Unretained(&decode_client3),
-                                  run_loop.QuitClosure()));
+          image(),
+          base::BindOnce(&DecodeClient::Callback,
+                         base::Unretained(&decode_client3),
+                         run_loop.QuitClosure()),
+          /*speculative*/ false);
   RunOrTimeout(&run_loop);
   EXPECT_EQ(expected_id1, decode_client1.id());
   EXPECT_EQ(ImageController::ImageDecodeResult::SUCCESS,
@@ -367,9 +377,11 @@
   DecodeClient decode_client;
   ImageController::ImageDecodeRequestId expected_id =
       controller()->QueueImageDecode(
-          image(), base::BindOnce(&DecodeClient::Callback,
-                                  base::Unretained(&decode_client),
-                                  run_loop.QuitClosure()));
+          image(),
+          base::BindOnce(&DecodeClient::Callback,
+                         base::Unretained(&decode_client),
+                         run_loop.QuitClosure()),
+          /*speculative*/ false);
   RunOrTimeout(&run_loop);
   EXPECT_EQ(expected_id, decode_client.id());
   EXPECT_TRUE(task->has_run());
@@ -386,19 +398,23 @@
       controller()->QueueImageDecode(
           image(),
           base::BindOnce(&DecodeClient::Callback,
-                         base::Unretained(&decode_client1), base::DoNothing()));
+                         base::Unretained(&decode_client1), base::DoNothing()),
+          /*speculative*/ false);
   DecodeClient decode_client2;
   ImageController::ImageDecodeRequestId expected_id2 =
       controller()->QueueImageDecode(
           image(),
           base::BindOnce(&DecodeClient::Callback,
-                         base::Unretained(&decode_client2), base::DoNothing()));
+                         base::Unretained(&decode_client2), base::DoNothing()),
+          /*speculative*/ false);
   DecodeClient decode_client3;
   ImageController::ImageDecodeRequestId expected_id3 =
       controller()->QueueImageDecode(
-          image(), base::BindOnce(&DecodeClient::Callback,
-                                  base::Unretained(&decode_client3),
-                                  run_loop.QuitClosure()));
+          image(),
+          base::BindOnce(&DecodeClient::Callback,
+                         base::Unretained(&decode_client3),
+                         run_loop.QuitClosure()),
+          /*speculative*/ false);
   RunOrTimeout(&run_loop);
   EXPECT_EQ(expected_id1, decode_client1.id());
   EXPECT_EQ(ImageController::ImageDecodeResult::SUCCESS,
@@ -422,7 +438,8 @@
       controller()->QueueImageDecode(
           image(),
           base::BindOnce(&DecodeClient::Callback,
-                         base::Unretained(&decode_client1), base::DoNothing()));
+                         base::Unretained(&decode_client1), base::DoNothing()),
+          /*speculative*/ false);
 
   scoped_refptr<BlockingTask> task_two(new BlockingTask);
   cache()->SetTaskToUse(task_two);
@@ -431,9 +448,11 @@
   DecodeClient decode_client2;
   ImageController::ImageDecodeRequestId expected_id2 =
       controller()->QueueImageDecode(
-          image(), base::BindOnce(&DecodeClient::Callback,
-                                  base::Unretained(&decode_client2),
-                                  run_loop.QuitClosure()));
+          image(),
+          base::BindOnce(&DecodeClient::Callback,
+                         base::Unretained(&decode_client2),
+                         run_loop.QuitClosure()),
+          /*speculative*/ false);
 
   task_one->AllowToRun();
   task_two->AllowToRun();
@@ -456,9 +475,11 @@
   DecodeClient decode_client1;
   ImageController::ImageDecodeRequestId expected_id1 =
       controller()->QueueImageDecode(
-          image(), base::BindOnce(&DecodeClient::Callback,
-                                  base::Unretained(&decode_client1),
-                                  run_loop1.QuitClosure()));
+          image(),
+          base::BindOnce(&DecodeClient::Callback,
+                         base::Unretained(&decode_client1),
+                         run_loop1.QuitClosure()),
+          /*speculative*/ false);
   RunOrTimeout(&run_loop1);
   EXPECT_EQ(expected_id1, decode_client1.id());
   EXPECT_TRUE(task->has_run());
@@ -468,9 +489,11 @@
   DecodeClient decode_client2;
   ImageController::ImageDecodeRequestId expected_id2 =
       controller()->QueueImageDecode(
-          image(), base::BindOnce(&DecodeClient::Callback,
-                                  base::Unretained(&decode_client2),
-                                  run_loop2.QuitClosure()));
+          image(),
+          base::BindOnce(&DecodeClient::Callback,
+                         base::Unretained(&decode_client2),
+                         run_loop2.QuitClosure()),
+          /*speculative*/ false);
   RunOrTimeout(&run_loop2);
   EXPECT_EQ(expected_id2, decode_client2.id());
   EXPECT_EQ(ImageController::ImageDecodeResult::SUCCESS,
@@ -485,9 +508,11 @@
   DecodeClient decode_client1;
   ImageController::ImageDecodeRequestId expected_id1 =
       controller()->QueueImageDecode(
-          image(), base::BindOnce(&DecodeClient::Callback,
-                                  base::Unretained(&decode_client1),
-                                  run_loop1.QuitClosure()));
+          image(),
+          base::BindOnce(&DecodeClient::Callback,
+                         base::Unretained(&decode_client1),
+                         run_loop1.QuitClosure()),
+          /*speculative*/ false);
   RunOrTimeout(&run_loop1);
   EXPECT_EQ(expected_id1, decode_client1.id());
   EXPECT_TRUE(task->has_run());
@@ -506,7 +531,8 @@
   controller()->QueueImageDecode(
       image(),
       base::BindOnce(&DecodeClient::Callback, base::Unretained(&decode_client),
-                     run_loop.QuitClosure()));
+                     run_loop.QuitClosure()),
+      /*speculative*/ false);
   controller()->SetImageDecodeCache(cache());
   RunOrTimeout(&run_loop);
   EXPECT_EQ(ImageController::ImageDecodeResult::SUCCESS,
@@ -525,11 +551,13 @@
   controller()->QueueImageDecode(
       image(),
       base::BindOnce(&DecodeClient::Callback, base::Unretained(&decode_client1),
-                     run_loop1.QuitClosure()));
+                     run_loop1.QuitClosure()),
+      /*speculative*/ false);
   controller()->QueueImageDecode(
       image(),
       base::BindOnce(&DecodeClient::Callback, base::Unretained(&decode_client2),
-                     run_loop2.QuitClosure()));
+                     run_loop2.QuitClosure()),
+      /*speculative*/ false);
 
   // Now reset the image cache before decode completed callbacks are posted to
   // the compositor thread. Ensure that the completion callbacks for the decode
@@ -558,11 +586,13 @@
   controller()->QueueImageDecode(
       image(),
       base::BindOnce(&DecodeClient::Callback, base::Unretained(&decode_client1),
-                     run_loop1.QuitClosure()));
+                     run_loop1.QuitClosure()),
+      /*speculative*/ false);
   controller()->QueueImageDecode(
       image(),
       base::BindOnce(&DecodeClient::Callback, base::Unretained(&decode_client2),
-                     run_loop2.QuitClosure()));
+                     run_loop2.QuitClosure()),
+      /*speculative*/ false);
 
   // Now reset the image cache before decode completed callbacks are posted to
   // the compositor thread. This should orphan the requests.
@@ -603,13 +633,15 @@
       controller()->QueueImageDecode(
           image(),
           base::BindOnce(&DecodeClient::Callback,
-                         base::Unretained(&decode_client1), base::DoNothing()));
+                         base::Unretained(&decode_client1), base::DoNothing()),
+          /*speculative*/ false);
 
   ImageController::ImageDecodeRequestId expected_id2 =
       controller()->QueueImageDecode(
           image(),
           base::BindOnce(&DecodeClient::Callback,
-                         base::Unretained(&decode_client2), base::DoNothing()));
+                         base::Unretained(&decode_client2), base::DoNothing()),
+          /*speculative*/ false);
 
   // This needs a ref because it is lazy.
   EXPECT_EQ(2, cache()->number_of_refs());
@@ -648,12 +680,14 @@
       controller()->QueueImageDecode(
           image1,
           base::BindOnce(&DecodeClient::Callback,
-                         base::Unretained(&decode_client1), base::DoNothing()));
+                         base::Unretained(&decode_client1), base::DoNothing()),
+          /*speculative*/ false);
   ImageController::ImageDecodeRequestId expected_id2 =
       controller()->QueueImageDecode(
           image2,
           base::BindOnce(&DecodeClient::Callback,
-                         base::Unretained(&decode_client2), base::DoNothing()));
+                         base::Unretained(&decode_client2), base::DoNothing()),
+          /*speculative*/ false);
 
   // No ref needed here, because it is non-lazy.
   EXPECT_EQ(0, cache()->number_of_refs());
@@ -696,9 +730,11 @@
   cache()->SetTaskToUse(task);
   ImageController::ImageDecodeRequestId expected_id =
       controller()->QueueImageDecode(
-          image(), base::BindOnce(&DecodeClient::Callback,
-                                  base::Unretained(&decode_client),
-                                  run_loop.QuitClosure()));
+          image(),
+          base::BindOnce(&DecodeClient::Callback,
+                         base::Unretained(&decode_client),
+                         run_loop.QuitClosure()),
+          /*speculative*/ false);
 
   EXPECT_FALSE(controller()->HasReadyToRunTaskForTesting());
   EXPECT_FALSE(task->has_run());
diff --git a/cc/tiles/image_decode_cache.h b/cc/tiles/image_decode_cache.h
index c8d805c..beca3a6 100644
--- a/cc/tiles/image_decode_cache.h
+++ b/cc/tiles/image_decode_cache.h
@@ -136,7 +136,8 @@
   // worker thread which may not have the right GPU context for upload.
   virtual TaskResult GetOutOfRasterDecodeTaskForImageAndRef(
       ClientId client_id,
-      const DrawImage& image) = 0;
+      const DrawImage& image,
+      bool speculative = false) = 0;
 
   // Unrefs an image. When the tile is finished, this should be called for every
   // GetTaskForImageAndRef call that returned true.
diff --git a/cc/tiles/software_image_decode_cache.cc b/cc/tiles/software_image_decode_cache.cc
index 0c2aa52..7f840b0 100644
--- a/cc/tiles/software_image_decode_cache.cc
+++ b/cc/tiles/software_image_decode_cache.cc
@@ -182,25 +182,27 @@
     const TracingInfo& tracing_info) {
   DCHECK_EQ(client_id, ImageDecodeCache::kDefaultClientId)
       << "SoftwareImageDecodeCache cannot be shared between multiple clients.";
-  return GetTaskForImageAndRefInternal(image, tracing_info,
-                                       TaskType::kInRaster);
+  return GetTaskForImageAndRefInternal(image, tracing_info, TaskType::kInRaster,
+                                       /*speculative*/ false);
 }
 
 ImageDecodeCache::TaskResult
 SoftwareImageDecodeCache::GetOutOfRasterDecodeTaskForImageAndRef(
     ClientId client_id,
-    const DrawImage& image) {
+    const DrawImage& image,
+    bool speculative) {
   DCHECK_EQ(client_id, ImageDecodeCache::kDefaultClientId)
       << "SoftwareImageDecodeCache cannot be shared between multiple clients.";
   return GetTaskForImageAndRefInternal(image, TracingInfo(0, TilePriority::NOW),
-                                       TaskType::kOutOfRaster);
+                                       TaskType::kOutOfRaster, speculative);
 }
 
 ImageDecodeCache::TaskResult
 SoftwareImageDecodeCache::GetTaskForImageAndRefInternal(
     const DrawImage& image,
     const TracingInfo& tracing_info,
-    TaskType task_type) {
+    TaskType task_type,
+    bool speculative) {
   CacheKey key = CacheKey::FromDrawImage(
       image, GetColorTypeForPaintImage(image.target_color_params(),
                                        image.paint_image()));
diff --git a/cc/tiles/software_image_decode_cache.h b/cc/tiles/software_image_decode_cache.h
index 69d5cf2..cfe861f6 100644
--- a/cc/tiles/software_image_decode_cache.h
+++ b/cc/tiles/software_image_decode_cache.h
@@ -46,7 +46,8 @@
                                    const TracingInfo& tracing_info) override;
   TaskResult GetOutOfRasterDecodeTaskForImageAndRef(
       ClientId client_id,
-      const DrawImage& image) override;
+      const DrawImage& image,
+      bool speculative = false) override;
   void UnrefImage(const DrawImage& image) override;
   DecodedDrawImage GetDecodedImageForDraw(const DrawImage& image) override;
   void DrawWithImageFinished(const DrawImage& image,
@@ -117,7 +118,9 @@
   // if it was public (ie, all of the locks need to be properly acquired).
   TaskResult GetTaskForImageAndRefInternal(const DrawImage& image,
                                            const TracingInfo& tracing_info,
-                                           TaskType type) LOCKS_EXCLUDED(lock_);
+                                           TaskType type,
+                                           bool speculative)
+      LOCKS_EXCLUDED(lock_);
 
   CacheEntry* AddCacheEntry(const CacheKey& key)
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
diff --git a/cc/tiles/software_image_decode_cache_unittest.cc b/cc/tiles/software_image_decode_cache_unittest.cc
index 0684f00..0ebfa0e 100644
--- a/cc/tiles/software_image_decode_cache_unittest.cc
+++ b/cc/tiles/software_image_decode_cache_unittest.cc
@@ -791,8 +791,8 @@
   TileTask* raster_decode_task = raster_result.task.get();
 
   ImageDecodeCache::TaskResult stand_alone_result =
-      cache_.GetOutOfRasterDecodeTaskForImageAndRef(cache_client_id_,
-                                                    draw_image);
+      cache_.GetOutOfRasterDecodeTaskForImageAndRef(
+          cache_client_id_, draw_image, /*speculative*/ false);
   EXPECT_TRUE(stand_alone_result.need_unref);
   EXPECT_EQ(stand_alone_result.task->dependencies().size(), 1u);
   EXPECT_EQ(stand_alone_result.task->dependencies()[0].get(),
@@ -821,8 +821,8 @@
       PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
 
   ImageDecodeCache::TaskResult stand_alone_result =
-      cache_.GetOutOfRasterDecodeTaskForImageAndRef(cache_client_id_,
-                                                    draw_image);
+      cache_.GetOutOfRasterDecodeTaskForImageAndRef(
+          cache_client_id_, draw_image, /*speculative*/ false);
   EXPECT_TRUE(stand_alone_result.need_unref);
   EXPECT_TRUE(stand_alone_result.task);
 
@@ -860,8 +860,8 @@
       PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
 
   ImageDecodeCache::TaskResult stand_alone_result =
-      cache_.GetOutOfRasterDecodeTaskForImageAndRef(cache_client_id_,
-                                                    draw_image);
+      cache_.GetOutOfRasterDecodeTaskForImageAndRef(
+          cache_client_id_, draw_image, /*speculative*/ false);
   EXPECT_TRUE(stand_alone_result.need_unref);
   EXPECT_TRUE(stand_alone_result.task);
   TileTask* stand_alone_decode_task = stand_alone_result.task.get();
@@ -906,8 +906,8 @@
       PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
 
   ImageDecodeCache::TaskResult stand_alone_result =
-      cache_.GetOutOfRasterDecodeTaskForImageAndRef(cache_client_id_,
-                                                    draw_image);
+      cache_.GetOutOfRasterDecodeTaskForImageAndRef(
+          cache_client_id_, draw_image, /*speculative*/ false);
   EXPECT_TRUE(stand_alone_result.need_unref);
   EXPECT_TRUE(stand_alone_result.task);
   TileTask* stand_alone_decode_task = stand_alone_result.task.get();
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc
index 922099d..0a61cbb 100644
--- a/cc/tiles/tile_manager_unittest.cc
+++ b/cc/tiles/tile_manager_unittest.cc
@@ -3895,9 +3895,11 @@
 
   // Add the images to our decoded_image_tracker.
   host_impl()->tile_manager()->decoded_image_tracker().QueueImageDecode(
-      DrawImageForDecoding(image1, TargetColorParams()), base::DoNothing());
+      DrawImageForDecoding(image1, TargetColorParams()), base::DoNothing(),
+      /*speculative*/ false);
   host_impl()->tile_manager()->decoded_image_tracker().QueueImageDecode(
-      DrawImageForDecoding(image2, TargetColorParams()), base::DoNothing());
+      DrawImageForDecoding(image2, TargetColorParams()), base::DoNothing(),
+      /*speculative*/ false);
   EXPECT_EQ(0u, host_impl()
                     ->tile_manager()
                     ->decoded_image_tracker()
@@ -3979,8 +3981,8 @@
     TargetColorParams target_color_params;
     target_color_params.color_space = output_cs;
     host_impl()->tile_manager()->decoded_image_tracker().QueueImageDecode(
-        DrawImageForDecoding(hdr_image, target_color_params),
-        base::DoNothing());
+        DrawImageForDecoding(hdr_image, target_color_params), base::DoNothing(),
+        /*speculative*/ false);
     FlushDecodeTasks();
 
     // Add images to a fake recording source.
diff --git a/cc/trees/commit_state.h b/cc/trees/commit_state.h
index a75a74f..080a893 100644
--- a/cc/trees/commit_state.h
+++ b/cc/trees/commit_state.h
@@ -7,6 +7,7 @@
 
 #include <array>
 #include <memory>
+#include <tuple>
 #include <unordered_map>
 #include <utility>
 #include <vector>
@@ -143,7 +144,8 @@
   std::unique_ptr<gfx::DelegatedInkMetadata> delegated_ink_metadata;
 
   std::unique_ptr<PendingPageScaleAnimation> pending_page_scale_animation;
-  std::vector<std::pair<int, std::unique_ptr<DrawImage>>> queued_image_decodes;
+  std::vector<std::tuple<int, std::unique_ptr<DrawImage>, bool>>
+      queued_image_decodes;
 
   // Presentation time callbacks requested for the next frame are initially
   // added here.
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index d133392a..9e597544 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -288,8 +288,9 @@
   property_tree_delegate_->SetLayerTreeHost(nullptr);
 
   // Fail any pending image decodes.
-  for (auto& pair : pending_image_decodes_)
-    std::move(pair.second).Run(false);
+  for (auto& entry : pending_image_decodes_) {
+    std::move(entry.second.first).Run(false);
+  }
 
   if (proxy_) {
     proxy_->Stop();
@@ -521,7 +522,7 @@
   auto it = pending_image_decodes_.find(request_id);
   CHECK(it != pending_image_decodes_.end(), base::NotFatalUntil::M130);
   // Issue stored callback and remove them from the pending list.
-  std::move(it->second).Run(decode_succeeded);
+  std::move(it->second.first).Run(decode_succeeded);
   pending_image_decodes_.erase(it);
 }
 
@@ -1898,17 +1899,19 @@
 }
 
 void LayerTreeHost::QueueImageDecode(const DrawImage& image,
-                                     base::OnceCallback<void(bool)> callback) {
+                                     base::OnceCallback<void(bool)> callback,
+                                     bool speculative) {
   TRACE_EVENT0("cc", "LayerTreeHost::QueueImageDecode");
   int next_id = s_image_decode_sequence_number.GetNext();
   if (base::FeatureList::IsEnabled(
           features::kSendExplicitDecodeRequestsImmediately)) {
-    proxy()->QueueImageDecode(next_id, image);
+    proxy()->QueueImageDecode(next_id, image, speculative);
   } else {
-    pending_commit_state()->queued_image_decodes.emplace_back(
-        next_id, std::make_unique<DrawImage>(image));
+    pending_commit_state()->queued_image_decodes.emplace_back(std::make_tuple(
+        next_id, std::make_unique<DrawImage>(image), speculative));
   }
-  pending_image_decodes_.emplace(next_id, std::move(callback));
+  pending_image_decodes_.emplace(
+      next_id, std::make_pair(std::move(callback), speculative));
   SetNeedsCommit();
 }
 
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index 7537a15..a10f549 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -900,7 +900,8 @@
                                          ElementListType tree_type) override {}
 
   void QueueImageDecode(const DrawImage& image,
-                        base::OnceCallback<void(bool)> callback);
+                        base::OnceCallback<void(bool)> callback,
+                        bool speculative);
   void ImageDecodesFinished(const std::vector<std::pair<int, bool>>& results);
 
   void RequestBeginMainFrameNotExpected(bool new_state);
@@ -1126,7 +1127,7 @@
 
   raw_ptr<RasterDarkModeFilter> dark_mode_filter_;
 
-  std::unordered_map<int, base::OnceCallback<void(bool)>>
+  std::unordered_map<int, std::pair<base::OnceCallback<void(bool)>, bool>>
       pending_image_decodes_;
 
   struct ScrollAnimationState {
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 120942b..22c76bac 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -710,8 +710,10 @@
   PullLayerTreeHostPropertiesFrom(state);
 
   // Transfer image decode requests to the impl thread.
-  for (auto& entry : state.queued_image_decodes)
-    QueueImageDecode(entry.first, *entry.second);
+  for (auto& entry : state.queued_image_decodes) {
+    QueueImageDecode(std::get<0>(entry), *std::get<1>(entry),
+                     std::get<2>(entry));
+  }
 
   for (auto& benchmark : state.benchmarks)
     ScheduleMicroBenchmark(std::move(benchmark));
@@ -4300,7 +4302,8 @@
 }
 
 void LayerTreeHostImpl::QueueImageDecode(int request_id,
-                                         const DrawImage& image) {
+                                         const DrawImage& image,
+                                         bool speculative) {
   DCHECK(!settings_.is_display_tree);
   const PaintImage& paint_image = image.paint_image();
   TRACE_EVENT1(
@@ -4314,8 +4317,10 @@
       /*frame_index=*/PaintImage::kDefaultFrameIndex,
       GetTargetColorParams(paint_image.GetContentColorUsage()));
   tile_manager_.decoded_image_tracker().QueueImageDecode(
-      image_copy, base::BindOnce(&LayerTreeHostImpl::ImageDecodeFinished,
-                                 weak_factory_.GetWeakPtr(), request_id));
+      image_copy,
+      base::BindOnce(&LayerTreeHostImpl::ImageDecodeFinished,
+                     weak_factory_.GetWeakPtr(), request_id),
+      speculative);
   tile_manager_.checker_image_tracker().DisallowCheckeringForImage(paint_image);
 }
 
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index a6391dd..8c11126 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -806,7 +806,9 @@
     return paint_worklet_painter_.get();
   }
 
-  void QueueImageDecode(int request_id, const DrawImage& image);
+  void QueueImageDecode(int request_id,
+                        const DrawImage& image,
+                        bool speculative);
   std::vector<std::pair<int, bool>> TakeCompletedImageDecodeRequests();
   // Returns mutator events to be handled by BeginMainFrame.
   std::unique_ptr<MutatorEvents> TakeMutatorEvents();
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 20f34ce..25cabd8 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -8289,8 +8289,10 @@
         &LayerTreeHostTestQueueImageDecode::ImageDecodeFinished,
         base::Unretained(this));
     // Schedule the decode twice for the same image.
-    layer_tree_host()->QueueImageDecode(image_, callback);
-    layer_tree_host()->QueueImageDecode(image_, callback);
+    layer_tree_host()->QueueImageDecode(image_, callback,
+                                        /*speculative*/ false);
+    layer_tree_host()->QueueImageDecode(image_, callback,
+                                        /*speculative*/ false);
   }
 
   void ReadyToCommitOnThread(LayerTreeHostImpl* impl) override {
@@ -8348,7 +8350,7 @@
                   /*use_dark_mode=*/false,
                   SkIRect::MakeWH(image.width(), image.height()),
                   PaintFlags::FilterQuality::kNone, SkM44()),
-        std::move(callback));
+        std::move(callback), /*speculative*/ false);
   }
 
   void ImageDecodeFinished(bool decode_succeeded) {
diff --git a/cc/trees/proxy.h b/cc/trees/proxy.h
index 8e0e90f71..4dda52d 100644
--- a/cc/trees/proxy.h
+++ b/cc/trees/proxy.h
@@ -96,7 +96,9 @@
   // Must be called before deleting the proxy.
   virtual void Stop() = 0;
 
-  virtual void QueueImageDecode(int request_id, const DrawImage& image) = 0;
+  virtual void QueueImageDecode(int request_id,
+                                const DrawImage& image,
+                                bool speculative) = 0;
   virtual void SetMutator(std::unique_ptr<LayerTreeMutator> mutator) = 0;
 
   virtual void SetPaintWorkletLayerPainter(
diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc
index 77d886b..77c2bf5 100644
--- a/cc/trees/proxy_impl.cc
+++ b/cc/trees/proxy_impl.cc
@@ -998,8 +998,9 @@
 }
 
 void ProxyImpl::QueueImageDecodeOnImpl(int request_id,
-                                       std::unique_ptr<DrawImage> image) {
-  host_impl_->QueueImageDecode(request_id, *image);
+                                       std::unique_ptr<DrawImage> image,
+                                       bool speculative) {
+  host_impl_->QueueImageDecode(request_id, *image, speculative);
 }
 
 void ProxyImpl::SetSourceURL(ukm::SourceId source_id, const GURL& url) {
diff --git a/cc/trees/proxy_impl.h b/cc/trees/proxy_impl.h
index 76882104..20f1cda5 100644
--- a/cc/trees/proxy_impl.h
+++ b/cc/trees/proxy_impl.h
@@ -100,7 +100,9 @@
                                  bool scroll_and_viewport_changes_synced,
                                  CommitTimestamps* commit_timestamps,
                                  bool commit_timeout = false);
-  void QueueImageDecodeOnImpl(int request_id, std::unique_ptr<DrawImage> image);
+  void QueueImageDecodeOnImpl(int request_id,
+                              std::unique_ptr<DrawImage> image,
+                              bool speculative);
   void SetSourceURL(ukm::SourceId source_id, const GURL& url);
   void SetUkmSmoothnessDestination(
       base::WritableSharedMemoryMapping ukm_smoothness_data);
diff --git a/cc/trees/proxy_main.cc b/cc/trees/proxy_main.cc
index 031528a..e09350b0 100644
--- a/cc/trees/proxy_main.cc
+++ b/cc/trees/proxy_main.cc
@@ -797,12 +797,15 @@
   started_ = false;
 }
 
-void ProxyMain::QueueImageDecode(int request_id, const DrawImage& image) {
+void ProxyMain::QueueImageDecode(int request_id,
+                                 const DrawImage& image,
+                                 bool speculative) {
   TRACE_EVENT1("cc", "ProxyMain::QueueImageDecode", "request_id", request_id);
   ImplThreadTaskRunner()->PostTask(
-      FROM_HERE, base::BindOnce(&ProxyImpl::QueueImageDecodeOnImpl,
-                                base::Unretained(proxy_impl_.get()), request_id,
-                                std::make_unique<DrawImage>(image)));
+      FROM_HERE,
+      base::BindOnce(&ProxyImpl::QueueImageDecodeOnImpl,
+                     base::Unretained(proxy_impl_.get()), request_id,
+                     std::make_unique<DrawImage>(image), speculative));
 }
 
 void ProxyMain::SetMutator(std::unique_ptr<LayerTreeMutator> mutator) {
diff --git a/cc/trees/proxy_main.h b/cc/trees/proxy_main.h
index 27a0044..b572b6d 100644
--- a/cc/trees/proxy_main.h
+++ b/cc/trees/proxy_main.h
@@ -114,7 +114,9 @@
   bool CommitRequested() const override;
   void Start() override;
   void Stop() override;
-  void QueueImageDecode(int request_id, const DrawImage& image) override;
+  void QueueImageDecode(int request_id,
+                        const DrawImage& image,
+                        bool speculative) override;
   void SetMutator(std::unique_ptr<LayerTreeMutator> mutator) override;
   void SetPaintWorkletLayerPainter(
       std::unique_ptr<PaintWorkletLayerPainter> painter) override;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 5215b873..3519ed5 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -461,10 +461,11 @@
 }
 
 void SingleThreadProxy::QueueImageDecode(int request_id,
-                                         const DrawImage& image) {
+                                         const DrawImage& image,
+                                         bool speculative) {
   DCHECK(task_runner_provider_->IsMainThread());
   DebugScopedSetImplThread impl(task_runner_provider_);
-  host_impl_->QueueImageDecode(request_id, image);
+  host_impl_->QueueImageDecode(request_id, image, speculative);
 }
 
 void SingleThreadProxy::SetMutator(std::unique_ptr<LayerTreeMutator> mutator) {
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index dc172d2..2b4895e 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -75,7 +75,9 @@
   bool CommitRequested() const override;
   void Start() override;
   void Stop() override;
-  void QueueImageDecode(int request_id, const DrawImage& image) override;
+  void QueueImageDecode(int request_id,
+                        const DrawImage& image,
+                        bool speculative) override;
   void SetMutator(std::unique_ptr<LayerTreeMutator> mutator) override;
   void SetPaintWorkletLayerPainter(
       std::unique_ptr<PaintWorkletLayerPainter> painter) override;
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 9f109798..66eae5a 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -453,6 +453,7 @@
       "//chrome/browser/prefetch/android:java",
       "//chrome/browser/preloading/android:java",
       "//chrome/browser/privacy:java",
+      "//chrome/browser/privacy:privacy_settings_java",
       "//chrome/browser/privacy_guide/android:java",
       "//chrome/browser/privacy_sandbox/android:java",
       "//chrome/browser/profiles/android:java",
diff --git a/chrome/android/features/tab_ui/java/res/values/colors.xml b/chrome/android/features/tab_ui/java/res/values/colors.xml
index 80baf0d7..3277daf 100644
--- a/chrome/android/features/tab_ui/java/res/values/colors.xml
+++ b/chrome/android/features/tab_ui/java/res/values/colors.xml
@@ -33,7 +33,6 @@
     <color name="incognito_tab_grid_dialog_ungroup_bar_text_color">@color/baseline_primary_80</color>
     <color name="incognito_tab_grid_dialog_ungroup_bar_text_hovered_color">@color/modern_white</color>
 
-    <color name="incognito_tab_list_editor_toolbar_bg_color">@color/gm3_baseline_surface_container_low_dark</color>
     <color name="incognito_tab_hover_card_bg_color">@color/gm3_baseline_surface_container_highest_dark</color>
 
     <color name="tab_group_color_picker_selection_bg_incognito">@color/dialog_bg_color_dark_baseline</color>
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinator.java
index 4228ba8..f1a37f3 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinator.java
@@ -32,6 +32,7 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.Supplier;
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
 import org.chromium.chrome.R;
@@ -39,6 +40,7 @@
 import org.chromium.chrome.browser.back_press.BackPressManager;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.hub.PaneManager;
 import org.chromium.chrome.browser.settings.SettingsNavigationFactory;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabArchiveSettings;
@@ -46,6 +48,7 @@
 import org.chromium.chrome.browser.tab_ui.TabContentManager;
 import org.chromium.chrome.browser.tabmodel.TabClosureParams;
 import org.chromium.chrome.browser.tabmodel.TabCreator;
+import org.chromium.chrome.browser.tabmodel.TabGroupModelFilter;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 import org.chromium.chrome.browser.tasks.tab_management.MessageService.MessageType;
@@ -74,6 +77,7 @@
 import org.chromium.components.browser_ui.widget.gesture.BackPressHandler;
 import org.chromium.components.tab_group_sync.SavedTabGroup;
 import org.chromium.components.tab_group_sync.TabGroupSyncService;
+import org.chromium.components.tab_group_sync.TabGroupUiActionHandler;
 import org.chromium.ui.interpolators.Interpolators;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modelutil.LayoutViewBuilder;
@@ -321,6 +325,10 @@
      * @param desktopWindowStateManager Manager to get desktop window and app header state.
      * @param edgeToEdgeSupplier Supplier for the {@link EdgeToEdgeController}.
      * @param tabGroupSyncService The {@link TabGroupSyncService} used for tab group sync.
+     * @param paneManagerSupplier Used to switch and communicate with other panes.
+     * @param tabGroupUiActionHandlerSupplier Used to open hidden tab groups.
+     * @param currentTabGroupModelFilterSupplier The supplier of the current {@link
+     *     TabGroupModelFilter}.
      */
     public ArchivedTabsDialogCoordinator(
             @NonNull Activity activity,
@@ -337,7 +345,10 @@
             @NonNull ModalDialogManager modalDialogManager,
             @Nullable DesktopWindowStateManager desktopWindowStateManager,
             @NonNull ObservableSupplier<EdgeToEdgeController> edgeToEdgeSupplier,
-            @Nullable TabGroupSyncService tabGroupSyncService) {
+            @Nullable TabGroupSyncService tabGroupSyncService,
+            @NonNull Supplier<PaneManager> paneManagerSupplier,
+            @NonNull Supplier<TabGroupUiActionHandler> tabGroupUiActionHandlerSupplier,
+            @NonNull ObservableSupplier<TabGroupModelFilter> currentTabGroupModelFilterSupplier) {
         mActivity = activity;
         mBrowserControlsStateProvider = browserControlsStateProvider;
         mTabContentManager = tabContentManager;
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsMessageService.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsMessageService.java
index 52cd4ec3..1e9ad786 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsMessageService.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsMessageService.java
@@ -24,17 +24,20 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.base.supplier.Supplier;
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.app.tabmodel.ArchivedTabModelOrchestrator;
 import org.chromium.chrome.browser.back_press.BackPressManager;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
+import org.chromium.chrome.browser.hub.PaneManager;
 import org.chromium.chrome.browser.tab.TabArchiveSettings;
 import org.chromium.chrome.browser.tab_ui.OnTabSelectingListener;
 import org.chromium.chrome.browser.tab_ui.RecyclerViewPosition;
 import org.chromium.chrome.browser.tab_ui.TabContentManager;
 import org.chromium.chrome.browser.tabmodel.TabCreator;
+import org.chromium.chrome.browser.tabmodel.TabGroupModelFilter;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tasks.tab_management.MessageCardViewProperties.MessageCardScope;
 import org.chromium.chrome.browser.tasks.tab_management.MessageService.MessageType;
@@ -50,6 +53,7 @@
 import org.chromium.components.browser_ui.widget.highlight.ViewHighlighter.HighlightShape;
 import org.chromium.components.feature_engagement.Tracker;
 import org.chromium.components.tab_group_sync.TabGroupSyncService;
+import org.chromium.components.tab_group_sync.TabGroupUiActionHandler;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
@@ -146,6 +150,10 @@
     private final @Nullable DesktopWindowStateManager mDesktopWindowStateManager;
     private final @NonNull ObservableSupplier<EdgeToEdgeController> mEdgeToEdgeSupplier;
     private final @Nullable TabGroupSyncService mTabGroupSyncService;
+    private final @NonNull Supplier<PaneManager> mPaneManagerSupplier;
+    private final @NonNull Supplier<TabGroupUiActionHandler> mTabGroupUiActionHandlerSupplier;
+    private final @NonNull ObservableSupplier<TabGroupModelFilter>
+            mCurrentTabGroupModelFilterSupplier;
 
     private TabArchiveSettings mTabArchiveSettings;
     private ArchivedTabsDialogCoordinator mArchivedTabsDialogCoordinator;
@@ -173,7 +181,10 @@
             @NonNull ObservableSupplier<TabListCoordinator> tabListCoordinatorSupplier,
             @Nullable DesktopWindowStateManager desktopWindowStateManager,
             @NonNull ObservableSupplier<EdgeToEdgeController> edgeToEdgeSupplier,
-            @Nullable TabGroupSyncService tabGroupSyncService) {
+            @Nullable TabGroupSyncService tabGroupSyncService,
+            @NonNull Supplier<PaneManager> paneManagerSupplier,
+            @NonNull Supplier<TabGroupUiActionHandler> tabGroupUiActionHandlerSupplier,
+            @NonNull ObservableSupplier<TabGroupModelFilter> currentTabGroupModelFilterSupplier) {
         super(MessageType.ARCHIVED_TABS_MESSAGE);
         mActivity = activity;
         mArchivedTabModelOrchestrator = archivedTabModelOrchestrator;
@@ -218,6 +229,9 @@
 
         mEdgeToEdgeSupplier = edgeToEdgeSupplier;
         mTabGroupSyncService = tabGroupSyncService;
+        mPaneManagerSupplier = paneManagerSupplier;
+        mTabGroupUiActionHandlerSupplier = tabGroupUiActionHandlerSupplier;
+        mCurrentTabGroupModelFilterSupplier = currentTabGroupModelFilterSupplier;
     }
 
     @Override
@@ -350,7 +364,10 @@
                         mModalDialogManager,
                         mDesktopWindowStateManager,
                         mEdgeToEdgeSupplier,
-                        mTabGroupSyncService);
+                        mTabGroupSyncService,
+                        mPaneManagerSupplier,
+                        mTabGroupUiActionHandlerSupplier,
+                        mCurrentTabGroupModelFilterSupplier);
     }
 
     private void updateModelProperties() {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java
index 230da1f..3e291eb3 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java
@@ -125,6 +125,9 @@
      * @param tabBookmarkerSupplier Supplier of {@link TabBookmarker} for bookmarking a given tab.
      * @param tabGroupCreationUiDelegate Orchestrates the tab group creation UI flow.
      * @param undoBarThrottle The controller to throttle the undo bar.
+     * @param hubManagerSupplier Supplier ultimately used to get the pane manager to switch panes.
+     * @param tabGroupUiActionHandlerSupplier Supplier for the controller used to open hidden
+     *     groups.
      */
     Pair<TabSwitcher, Pane> createTabSwitcherPane(
             @NonNull Activity activity,
@@ -152,7 +155,9 @@
             @NonNull ObservableSupplier<ShareDelegate> shareDelegateSupplier,
             @NonNull ObservableSupplier<TabBookmarker> tabBookmarkerSupplier,
             @NonNull TabGroupCreationUiDelegate tabGroupCreationUiDelegate,
-            UndoBarThrottle undoBarThrottle);
+            UndoBarThrottle undoBarThrottle,
+            @NonNull LazyOneshotSupplier<HubManager> hubManagerSupplier,
+            @NonNull Supplier<TabGroupUiActionHandler> tabGroupUiActionHandlerSupplier);
 
     /**
      * Create a {@link TabGroupsPane} for the Hub.
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java
index 50d3b623..a00ccab 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java
@@ -121,7 +121,9 @@
             @NonNull ObservableSupplier<ShareDelegate> shareDelegateSupplier,
             @NonNull ObservableSupplier<TabBookmarker> tabBookmarkerSupplier,
             @NonNull TabGroupCreationUiDelegate tabGroupCreationUiDelegate,
-            UndoBarThrottle undoBarThrottle) {
+            UndoBarThrottle undoBarThrottle,
+            @NonNull LazyOneshotSupplier<HubManager> hubManagerSupplier,
+            @NonNull Supplier<TabGroupUiActionHandler> tabGroupUiActionHandlerSupplier) {
         // TODO(crbug.com/40946413): Consider making this an activity scoped singleton and possibly
         // hosting it in CTA/HubProvider.
         TabSwitcherPaneCoordinatorFactory factory =
@@ -144,7 +146,9 @@
                         edgeToEdgeSupplier,
                         shareDelegateSupplier,
                         tabBookmarkerSupplier,
-                        undoBarThrottle);
+                        undoBarThrottle,
+                        () -> hubManagerSupplier.get().getPaneManager(),
+                        tabGroupUiActionHandlerSupplier);
         OneshotSupplierImpl<Profile> profileSupplier = new OneshotSupplierImpl<>();
         Handler handler = new Handler();
         profileProviderSupplier.onAvailable(
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManager.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManager.java
index e2e396a..05f5fa1 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManager.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManager.java
@@ -21,6 +21,7 @@
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.hub.PaneManager;
 import org.chromium.chrome.browser.incognito.reauth.IncognitoReauthManager;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher;
@@ -48,6 +49,7 @@
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.components.browser_ui.desktop_windowing.DesktopWindowStateManager;
+import org.chromium.components.tab_group_sync.TabGroupUiActionHandler;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modelutil.LayoutViewBuilder;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -149,6 +151,8 @@
     private final @NonNull BackPressManager mBackPressManager;
     private final @Nullable DesktopWindowStateManager mDesktopWindowStateManager;
     private final @NonNull ObservableSupplier<EdgeToEdgeController> mEdgeToEdgeSupplier;
+    private final @NonNull Supplier<PaneManager> mPaneManagerSupplier;
+    private final @NonNull Supplier<TabGroupUiActionHandler> mTabGroupUiActionHandlerSupplier;
 
     private @Nullable Profile mProfile;
     private @Nullable PriceMessageService mPriceMessageService;
@@ -172,6 +176,8 @@
      * @param backPressManager Manages the different back press handlers in the app.
      * @param desktopWindowStateManager Manager to get desktop window and app header state.
      * @param edgeToEdgeSupplier Supplier to the {@link EdgeToEdgeController} instance.
+     * @param paneManagerSupplier Used to switch and communicate with other panes.
+     * @param tabGroupUiActionHandlerSupplier Used to open hidden tab groups.
      */
     public TabSwitcherMessageManager(
             @NonNull Activity activity,
@@ -187,7 +193,9 @@
             @NonNull TabCreator regularTabCreator,
             @NonNull BackPressManager backPressManager,
             @Nullable DesktopWindowStateManager desktopWindowStateManager,
-            @NonNull ObservableSupplier<EdgeToEdgeController> edgeToEdgeSupplier) {
+            @NonNull ObservableSupplier<EdgeToEdgeController> edgeToEdgeSupplier,
+            @NonNull Supplier<PaneManager> paneManagerSupplier,
+            @NonNull Supplier<TabGroupUiActionHandler> tabGroupUiActionHandlerSupplier) {
         mActivity = activity;
         mLifecylceDispatcher = lifecycleDispatcher;
         mCurrentTabGroupModelFilterSupplier = currentTabGroupModelFilterSupplier;
@@ -215,6 +223,8 @@
         mOnTabGroupModelFilterChanged.onResult(
                 currentTabGroupModelFilterSupplier.addObserver(mOnTabGroupModelFilterChanged));
         mEdgeToEdgeSupplier = edgeToEdgeSupplier;
+        mPaneManagerSupplier = paneManagerSupplier;
+        mTabGroupUiActionHandlerSupplier = tabGroupUiActionHandlerSupplier;
     }
 
     /**
@@ -313,7 +323,10 @@
                             mTabListCoordinatorSupplier,
                             mDesktopWindowStateManager,
                             mEdgeToEdgeSupplier,
-                            TabGroupSyncServiceFactory.getForProfile(mProfile));
+                            TabGroupSyncServiceFactory.getForProfile(mProfile),
+                            mPaneManagerSupplier,
+                            mTabGroupUiActionHandlerSupplier,
+                            mCurrentTabGroupModelFilterSupplier);
             addObserver(mArchivedTabsMessageService);
             mMessageCardProviderCoordinator.subscribeMessageService(mArchivedTabsMessageService);
         }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManagerUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManagerUnitTest.java
index 29d8eb92..bc86005 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManagerUnitTest.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMessageManagerUnitTest.java
@@ -34,10 +34,12 @@
 import org.mockito.junit.MockitoRule;
 
 import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.supplier.Supplier;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.browser.back_press.BackPressManager;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
+import org.chromium.chrome.browser.hub.PaneManager;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher;
 import org.chromium.chrome.browser.price_tracking.PriceTrackingFeatures;
@@ -58,6 +60,7 @@
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.components.feature_engagement.Tracker;
 import org.chromium.components.tab_group_sync.TabGroupSyncService;
+import org.chromium.components.tab_group_sync.TabGroupUiActionHandler;
 import org.chromium.ui.base.TestActivity;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 
@@ -95,6 +98,8 @@
     @Mock private OnTabSelectingListener mOnTabSelectingListener;
     @Mock private EdgeToEdgeController mEdgeToEdgeController;
     @Mock private TabGroupSyncService mTabGroupSyncService;
+    @Mock private Supplier<PaneManager> mPaneManagerSupplier;
+    @Mock private Supplier<TabGroupUiActionHandler> mTabGroupUiActionHandlerSupplier;
     @Captor private ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor;
 
     @Captor
@@ -154,7 +159,9 @@
                         mRegularTabCreator,
                         mBackPressManager,
                         /* desktopWindowStateManager= */ null,
-                        mEdgeToEdgeSupplier);
+                        mEdgeToEdgeSupplier,
+                        mPaneManagerSupplier,
+                        mTabGroupUiActionHandlerSupplier);
         mMessageManager.registerMessages(mTabListCoordinator);
         mMessageManager.bind(
                 mTabListCoordinator,
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactory.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactory.java
index 617b0ec..741e40c 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactory.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactory.java
@@ -15,10 +15,12 @@
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.supplier.OneshotSupplier;
+import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.browser.back_press.BackPressManager;
 import org.chromium.chrome.browser.bookmarks.TabBookmarker;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.data_sharing.DataSharingTabManager;
+import org.chromium.chrome.browser.hub.PaneManager;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.lifecycle.NativeInitObserver;
 import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher;
@@ -38,6 +40,7 @@
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.desktop_windowing.DesktopWindowStateManager;
 import org.chromium.components.browser_ui.widget.scrim.ScrimManager;
+import org.chromium.components.tab_group_sync.TabGroupUiActionHandler;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.util.TokenHolder;
 
@@ -66,6 +69,8 @@
     private final @NonNull ObservableSupplier<ShareDelegate> mShareDelegateSupplier;
     private final @NonNull ObservableSupplier<TabBookmarker> mTabBookmarkerSupplier;
     private final UndoBarThrottle mUndoBarThrottle;
+    private final @NonNull Supplier<PaneManager> mPaneManagerSupplier;
+    private final @NonNull Supplier<TabGroupUiActionHandler> mTabGroupUiActionHandlerSupplier;
     private @Nullable TabSwitcherMessageManager mMessageManager;
 
     /**
@@ -91,6 +96,8 @@
      *     the tab's URL when the user selects the "Share" option.
      * @param tabBookmarkerSupplier Supplier of {@link TabBookmarker} for bookmarking a given tab.
      * @param undoBarThrottle Used to throttle the undo bar.
+     * @param paneManagerSupplier Used to switch and communicate with other panes.
+     * @param tabGroupUiActionHandlerSupplier Used to open hidden tab groups.
      */
     TabSwitcherPaneCoordinatorFactory(
             @NonNull Activity activity,
@@ -111,7 +118,9 @@
             @NonNull ObservableSupplier<EdgeToEdgeController> edgeToEdgeSupplier,
             @NonNull ObservableSupplier<ShareDelegate> shareDelegateSupplier,
             @NonNull ObservableSupplier<TabBookmarker> tabBookmarkerSupplier,
-            UndoBarThrottle undoBarThrottle) {
+            UndoBarThrottle undoBarThrottle,
+            @NonNull Supplier<PaneManager> paneManagerSupplier,
+            @NonNull Supplier<TabGroupUiActionHandler> tabGroupUiActionHandlerSupplier) {
         mActivity = activity;
         mLifecycleDispatcher = lifecycleDispatcher;
         mProfileProviderSupplier = profileProviderSupplier;
@@ -135,6 +144,8 @@
         mShareDelegateSupplier = shareDelegateSupplier;
         mTabBookmarkerSupplier = tabBookmarkerSupplier;
         mUndoBarThrottle = undoBarThrottle;
+        mPaneManagerSupplier = paneManagerSupplier;
+        mTabGroupUiActionHandlerSupplier = tabGroupUiActionHandlerSupplier;
     }
 
     /**
@@ -252,7 +263,9 @@
                             mTabCreatorManager.getTabCreator(/* incognito= */ false),
                             mBackPressManager,
                             mDesktopWindowStateManager,
-                            mEdgeToEdgeSupplier);
+                            mEdgeToEdgeSupplier,
+                            mPaneManagerSupplier,
+                            mTabGroupUiActionHandlerSupplier);
             if (mLifecycleDispatcher.isNativeInitializationFinished()) {
                 mMessageManager.initWithNative(
                         mProfileProviderSupplier.get().getOriginalProfile(), getTabListMode());
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactoryUnitTest.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactoryUnitTest.java
index 61513ca..ea5f49a 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactoryUnitTest.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherPaneCoordinatorFactoryUnitTest.java
@@ -33,6 +33,7 @@
 import org.chromium.base.Callback;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.supplier.OneshotSupplierImpl;
+import org.chromium.base.supplier.Supplier;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Features.DisableFeatures;
@@ -46,6 +47,7 @@
 import org.chromium.chrome.browser.data_sharing.DataSharingTabManager;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.hub.PaneManager;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.lifecycle.LifecycleObserver;
 import org.chromium.chrome.browser.lifecycle.NativeInitObserver;
@@ -78,6 +80,7 @@
 import org.chromium.components.data_sharing.TestDataSharingService;
 import org.chromium.components.feature_engagement.Tracker;
 import org.chromium.components.tab_group_sync.TabGroupSyncService;
+import org.chromium.components.tab_group_sync.TabGroupUiActionHandler;
 import org.chromium.ui.base.TestActivity;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 
@@ -134,6 +137,8 @@
     @Mock private TabBookmarker mTabBookmarker;
     @Mock private BookmarkModel mBookmarkModel;
     @Mock private UndoBarThrottle mUndoBarThrottle;
+    @Mock private Supplier<PaneManager> mPaneManagerSupplier;
+    @Mock private Supplier<TabGroupUiActionHandler> mTabGroupUiActionHandlerSupplier;
 
     @Captor private ArgumentCaptor<TabModelSelectorObserver> mTabModelSelectorObserverCaptor;
     @Captor private ArgumentCaptor<LifecycleObserver> mLifecycleObserverCaptor;
@@ -206,7 +211,9 @@
                         mEdgeToEdgeSupplier,
                         mShareDelegateSupplier,
                         mTabBookmarkerSupplier,
-                        mUndoBarThrottle);
+                        mUndoBarThrottle,
+                        mPaneManagerSupplier,
+                        mTabGroupUiActionHandlerSupplier);
     }
 
     @Test
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java
index aff755f..5027eac 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiThemeProvider.java
@@ -16,7 +16,7 @@
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.tasks.tab_management.TabListEditorCoordinator.CreationMode;
-import org.chromium.components.browser_ui.styles.ChromeColors;
+import org.chromium.chrome.browser.theme.SurfaceColorUpdateUtils;
 import org.chromium.components.browser_ui.styles.SemanticColorUtils;
 
 /** Utility class that provides theme related attributes for Tab UI. */
@@ -202,7 +202,7 @@
         if (creationMode == CreationMode.DIALOG) {
             return getTabGridDialogBackgroundColor(context, isIncognito);
         } else {
-            return ChromeColors.getPrimaryBackgroundColor(context, isIncognito);
+            return SurfaceColorUpdateUtils.getGridTabSwitcherBackgroundColor(context, isIncognito);
         }
     }
 
@@ -356,15 +356,10 @@
      */
     public static @ColorInt int getTabSelectionToolbarBackground(
             Context context, boolean isIncognito, @CreationMode int creationMode) {
-        if (isIncognito) {
-            return context.getColor(R.color.incognito_tab_list_editor_toolbar_bg_color);
-        } else {
-            if (creationMode == CreationMode.DIALOG) {
-                return ContextCompat.getColor(context, R.color.tab_grid_dialog_bg_color);
-            }
-
-            return MaterialColors.getColor(context, R.attr.colorSurface, TAG);
+        if (creationMode == CreationMode.DIALOG) {
+            return ContextCompat.getColor(context, R.color.tab_grid_dialog_bg_color);
         }
+        return SurfaceColorUpdateUtils.getGridTabSwitcherBackgroundColor(context, isIncognito);
     }
 
     /**
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinatorUnitTest.java
index adcea9c3..575b9498 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinatorUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsDialogCoordinatorUnitTest.java
@@ -41,7 +41,9 @@
 import org.robolectric.shadows.ShadowLooper;
 
 import org.chromium.base.Token;
+import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.supplier.Supplier;
 import org.chromium.base.task.TaskTraits;
 import org.chromium.base.task.test.ShadowPostTask;
 import org.chromium.base.task.test.ShadowPostTask.TestImpl;
@@ -53,10 +55,12 @@
 import org.chromium.chrome.browser.back_press.BackPressManager;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.hub.PaneManager;
 import org.chromium.chrome.browser.tab.TabArchiveSettings;
 import org.chromium.chrome.browser.tab_ui.OnTabSelectingListener;
 import org.chromium.chrome.browser.tab_ui.TabContentManager;
 import org.chromium.chrome.browser.tabmodel.TabCreator;
+import org.chromium.chrome.browser.tabmodel.TabGroupModelFilter;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorBase;
@@ -69,6 +73,7 @@
 import org.chromium.components.tab_group_sync.SavedTabGroup;
 import org.chromium.components.tab_group_sync.SavedTabGroupTab;
 import org.chromium.components.tab_group_sync.TabGroupSyncService;
+import org.chromium.components.tab_group_sync.TabGroupUiActionHandler;
 import org.chromium.ui.base.TestActivity;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 
@@ -109,6 +114,9 @@
     @Mock private RecyclerView mRecyclerView;
     @Mock private EdgeToEdgeController mEdgeToEdgeController;
     @Mock private TabGroupSyncService mTabGroupSyncService;
+    @Mock private Supplier<PaneManager> mPaneManagerSupplier;
+    @Mock private Supplier<TabGroupUiActionHandler> mTabGroupUiActionHandlerSupplier;
+    @Mock private ObservableSupplier<TabGroupModelFilter> mCurrentTabGroupModelFilterSupplier;
 
     private Activity mActivity;
     private ArchivedTabsDialogCoordinator mCoordinator;
@@ -154,7 +162,10 @@
                         mModalDialogManager,
                         /* desktopWindowStateManager= */ null,
                         mEdgeToEdgeSupplier,
-                        mTabGroupSyncService);
+                        mTabGroupSyncService,
+                        mPaneManagerSupplier,
+                        mTabGroupUiActionHandlerSupplier,
+                        mCurrentTabGroupModelFilterSupplier);
         mCoordinator.setTabListEditorCoordinatorForTesting(mTabListEditorCoordinator);
         recyclerView = new TabListRecyclerView(mActivity, null);
         recyclerView.setId(R.id.tab_list_recycler_view);
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsMessageServiceUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsMessageServiceUnitTest.java
index 0925090..32cc4826 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsMessageServiceUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsMessageServiceUnitTest.java
@@ -36,15 +36,19 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowLooper;
 
+import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.supplier.Supplier;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.browser.app.tabmodel.ArchivedTabModelOrchestrator;
 import org.chromium.chrome.browser.back_press.BackPressManager;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
+import org.chromium.chrome.browser.hub.PaneManager;
 import org.chromium.chrome.browser.tab.TabArchiveSettings;
 import org.chromium.chrome.browser.tab_ui.OnTabSelectingListener;
 import org.chromium.chrome.browser.tab_ui.TabContentManager;
 import org.chromium.chrome.browser.tabmodel.TabCreator;
+import org.chromium.chrome.browser.tabmodel.TabGroupModelFilter;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tasks.tab_management.MessageService.MessageType;
 import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator.TabListMode;
@@ -52,6 +56,7 @@
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.components.feature_engagement.Tracker;
 import org.chromium.components.tab_group_sync.TabGroupSyncService;
+import org.chromium.components.tab_group_sync.TabGroupUiActionHandler;
 import org.chromium.ui.base.TestActivity;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -85,6 +90,9 @@
     @Mock private TabListCoordinator mTabListCoordinator;
     @Mock private EdgeToEdgeController mEdgeToEdgeController;
     @Mock private TabGroupSyncService mTabGroupSyncService;
+    @Mock private Supplier<PaneManager> mPaneManagerSupplier;
+    @Mock private Supplier<TabGroupUiActionHandler> mTabGroupUiActionHandlerSupplier;
+    @Mock private ObservableSupplier<TabGroupModelFilter> mCurrentTabGroupModelFilterSupplier;
     @Captor private ArgumentCaptor<TabArchiveSettings.Observer> mTabArchiveSettingsObserver;
 
     private Activity mActivity;
@@ -124,7 +132,10 @@
                         mTabListCoordinatorSupplier,
                         /* desktopWindowStateManager= */ null,
                         mEdgeToEdgeSupplier,
-                        mTabGroupSyncService);
+                        mTabGroupSyncService,
+                        mPaneManagerSupplier,
+                        mTabGroupUiActionHandlerSupplier,
+                        mCurrentTabGroupModelFilterSupplier);
         mArchivedTabsMessageService.setArchivedTabsDialogCoordiantorForTesting(
                 mArchivedTabsDialogCoordinator);
         mArchivedTabsMessageService.addObserver(mMessageObserver);
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 77896fe..5375fa9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -1033,7 +1033,11 @@
                         getShareDelegateSupplier(),
                         mTabBookmarkerSupplier,
                         tabGroupCreationUiDelegate,
-                        mUndoBarPopupController);
+                        mUndoBarPopupController,
+                        mHubProvider.getHubManagerSupplier(),
+                        () ->
+                                ((TabbedRootUiCoordinator) mRootUiCoordinator)
+                                        .getTabGroupSyncController());
         if (didFinishNativeInitialization()) {
             result.first.initWithNative();
         }
@@ -2028,7 +2032,7 @@
     private void maybeRecordExternalAppClickInfo(
             @IntentHandler.ExternalAppId int externalId, Intent intent) {
         if (externalId != ExternalAppId.PIXEL_LAUNCHER
-                || externalId != ExternalAppId.THIRD_PARTY_LAUNCHER) {
+                || externalId != ExternalAppId.SAMSUNG_LAUNCHER) {
             return;
         }
 
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 fc296a1a..c38d99b0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
@@ -290,7 +290,7 @@
     private static final String PACKAGE_YAHOO_MAIL = "com.yahoo.mobile.client.android.mail";
     private static final String PACKAGE_VIBER = "com.viber.voip";
     private static final String PACKAGE_PIXEL_LAUNCHER = "com.google.android.apps.nexuslauncher";
-    private static final String THIRD_PARTY_LAUNCHER_SUFFIX = "launcher";
+    private static final String PACKAGE_SAMSUNG_LAUNCHER = "com.sec.android.app.launcher";
     private static final String FACEBOOK_REFERRER_URL = "android-app://m.facebook.com";
     private static final String FACEBOOK_INTERNAL_BROWSER_REFERRER = "http://m.facebook.com";
     private static final String TWITTER_LINK_PREFIX = "http://t.co/";
@@ -327,7 +327,8 @@
         ExternalAppId.YOUTUBE,
         ExternalAppId.CAMERA,
         ExternalAppId.PIXEL_LAUNCHER,
-        ExternalAppId.THIRD_PARTY_LAUNCHER,
+        ExternalAppId.DEPRECATED_THIRD_PARTY_LAUNCHER,
+        ExternalAppId.SAMSUNG_LAUNCHER,
         ExternalAppId.NUM_ENTRIES
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -350,9 +351,10 @@
         int YOUTUBE = 15;
         int CAMERA = 16;
         int PIXEL_LAUNCHER = 17;
-        int THIRD_PARTY_LAUNCHER = 18;
+        int DEPRECATED_THIRD_PARTY_LAUNCHER = 18;
+        int SAMSUNG_LAUNCHER = 19;
         // Update ClientAppId in enums.xml when adding new items.
-        int NUM_ENTRIES = 19;
+        int NUM_ENTRIES = 20;
     }
 
     /**
@@ -520,8 +522,8 @@
                     return ExternalAppId.CAMERA;
                 } else if (referrer.endsWith(PACKAGE_PIXEL_LAUNCHER)) {
                     return ExternalAppId.PIXEL_LAUNCHER;
-                } else if (referrer.endsWith(THIRD_PARTY_LAUNCHER_SUFFIX)) {
-                    return ExternalAppId.THIRD_PARTY_LAUNCHER;
+                } else if (referrer.endsWith(PACKAGE_SAMSUNG_LAUNCHER)) {
+                    return ExternalAppId.SAMSUNG_LAUNCHER;
                 }
             }
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java b/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java
index 4444853..fa8eb995 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/KeyboardShortcuts.java
@@ -995,7 +995,7 @@
                         currentTabModel
                                 .getTabRemover()
                                 .closeTabs(
-                                        TabClosureParams.closeTab(tab).allowUndo(true).build(),
+                                        TabClosureParams.closeTab(tab).allowUndo(false).build(),
                                         /* allowDialog= */ true);
                     }
                     return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
index 3e0b1f94..625406e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
@@ -157,7 +157,8 @@
                     && ChromeFeatureList.sAndroidNativePagesInNewTabDownloadsEnabled.getValue())
                     || tab == null || !tab.isInitialized()) {
                 // Open a new tab, which pops Chrome into the foreground.
-                ChromeAsyncTabLauncher delegate = new ChromeAsyncTabLauncher(false);
+                ChromeAsyncTabLauncher delegate = new ChromeAsyncTabLauncher(
+                        /* incognito= */ OtrProfileId.isOffTheRecord(otrProfileId));
                 delegate.launchNewTab(params, TabLaunchType.FROM_CHROME_UI, null);
             } else {
                 // Download Home shows up inside an existing tab, but only if the last Activity was
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java
index cb351cc..a2718ae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java
@@ -291,6 +291,16 @@
                         SingleCategorySettings.EXTRA_TITLE,
                         javascriptOptimizerPref.getTitle().toString());
 
+        Bundle arguments = getArguments();
+        if (arguments != null
+                && arguments
+                        .keySet()
+                        .contains(
+                                PrivacySettingsNavigation
+                                        .EXTRA_FOCUS_ADVANCED_PROTECTION_SECTION)) {
+            scrollToPreference(PREF_ADVANCED_PROTECTION_INFO);
+        }
+
         updatePreferences();
     }
 
@@ -510,12 +520,11 @@
                             androidAdvancedProtectionLinkAction),
                     createLink(context, "link_javascript_optimizer", javascriptOptimizerLinkAction)
                 };
+        String advancedProtectionSectionMessageTemplate =
+                getString(
+                        R.string.settings_privacy_and_security_advanced_protection_section_message);
         SpannableString span =
-                SpanApplier.applySpans(
-                        getString(
-                                R.string
-                                        .settings_privacy_and_security_advanced_protection_section_message),
-                        spans);
+                SpanApplier.applySpans(advancedProtectionSectionMessageTemplate, spans);
 
         PropertyModel advancedProtectionInfoModel =
                 new PropertyModel.Builder(SafetyHubModuleProperties.ALL_KEYS)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/safe_browsing/SafeBrowsingReferringAppBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/safe_browsing/SafeBrowsingReferringAppBridge.java
index 820a800..cdf20668 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/safe_browsing/SafeBrowsingReferringAppBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/safe_browsing/SafeBrowsingReferringAppBridge.java
@@ -203,8 +203,11 @@
                 return "camera";
             case ExternalAppId.PIXEL_LAUNCHER:
                 return "pixel.launcher";
-            case ExternalAppId.THIRD_PARTY_LAUNCHER:
+            case ExternalAppId.DEPRECATED_THIRD_PARTY_LAUNCHER:
                 return "third-party.launcher";
+            case ExternalAppId.SAMSUNG_LAUNCHER:
+                return "samsung.launcher";
+
             default:
                 assert false : "not reached";
                 return "";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
index 779dc398..6c062cd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedRootUiCoordinator.java
@@ -124,6 +124,7 @@
 import org.chromium.chrome.browser.pdf.PdfPageIphController;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
+import org.chromium.chrome.browser.privacy.settings.PrivacySettings;
 import org.chromium.chrome.browser.privacy_sandbox.ActivityTypeMapper;
 import org.chromium.chrome.browser.privacy_sandbox.PrivacySandboxBridge;
 import org.chromium.chrome.browser.privacy_sandbox.PrivacySandboxDialogController;
@@ -793,7 +794,8 @@
         super.onFinishNativeInitialization();
         assert mLayoutManager != null;
 
-        mAdvancedProtectionCoordinator = new AdvancedProtectionCoordinator(mWindowAndroid);
+        mAdvancedProtectionCoordinator =
+                new AdvancedProtectionCoordinator(mWindowAndroid, PrivacySettings.class);
 
         UmaSessionStats.registerSyntheticFieldTrial(
                 "AndroidNavigationMode",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/KeyboardShortcutsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/KeyboardShortcutsTest.java
index 2e44903..0a6e704e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/KeyboardShortcutsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/KeyboardShortcutsTest.java
@@ -6,9 +6,11 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
@@ -34,11 +36,16 @@
 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.tab.Tab;
 import org.chromium.chrome.browser.tab.TabSelectionType;
+import org.chromium.chrome.browser.tabmodel.TabClosureParams;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.tabmodel.TabRemover;
 import org.chromium.chrome.browser.toolbar.ToolbarManager;
 import org.chromium.components.browser_ui.widget.MenuOrKeyboardActionController;
+import org.chromium.content_public.browser.WebContents;
+import org.chromium.ui.KeyboardUtils;
 
 import java.util.Set;
 
@@ -55,17 +62,67 @@
     @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
 
     @Mock private MenuOrKeyboardActionController mMenuOrKeyboardActionController;
+    @Mock private Tab mTab;
     @Mock private TabModel mTabModel;
     @Mock private TabModelSelector mTabModelSelector;
+    @Mock private TabRemover mTabRemover;
     @Mock private ToolbarManager mToolbarManager;
+    @Mock private WebContents mWebContents;
 
     @Before
     public void setUp() {
-        when(mTabModelSelector.getCurrentModel()).thenAnswer(invocation -> mTabModel);
+        setUpTabModelSelector();
         when(mMenuOrKeyboardActionController.onMenuOrKeyboardAction(anyInt(), anyBoolean()))
                 .thenReturn(true);
     }
 
+    /**
+     * Sets up the mock {@link #mTabModelSelector}, which should be passed to {@code
+     * KeyboardShortcuts.onKeyDown()} for testing.
+     */
+    private void setUpTabModelSelector() {
+        when(mTabModelSelector.getCurrentModel()).thenReturn(mTabModel);
+        when(mTabModelSelector.getCurrentTab()).thenReturn(mTab);
+
+        when(mTabModel.getCount()).thenReturn(1);
+        when(mTabModel.index()).thenReturn(0);
+        when(mTabModel.getTabAt(0)).thenReturn(mTab);
+        when(mTabModel.getTabRemover()).thenReturn(mTabRemover);
+
+        when(mTab.getWebContents()).thenReturn(mWebContents);
+        doNothing().when(mTabRemover).closeTabs(any(TabClosureParams.class), anyBoolean());
+    }
+
+    // Close Tab shortcuts
+
+    @Test
+    @SmallTest
+    public void testCloseTab_ctrlW() {
+        testCloseTab(KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON);
+    }
+
+    @Test
+    @SmallTest
+    public void testCloseTab_ctrlF4() {
+        testCloseTab(KeyEvent.KEYCODE_F4, KeyEvent.META_CTRL_ON);
+    }
+
+    @Test
+    @SmallTest
+    public void testCloseTab_buttonB() {
+        testCloseTab(KeyEvent.KEYCODE_BUTTON_B, KeyboardUtils.NO_MODIFIER);
+    }
+
+    private void testCloseTab(int keyCode, int metaState) {
+        boolean isKeyEventHandled = keyDown(keyCode, metaState, /* isCurrentTabVisible= */ true);
+
+        assertTrue(isKeyEventHandled);
+        verify(mTabRemover)
+                .closeTabs(
+                        eq(TabClosureParams.closeTab(mTab).allowUndo(false).build()),
+                        /* allowDialog= */ eq(true));
+    }
+
     // Bookmarks shortcuts
 
     @Test
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/IntentHandlerRobolectricTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/IntentHandlerRobolectricTest.java
index 1fd10ab..257b5113 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/IntentHandlerRobolectricTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/IntentHandlerRobolectricTest.java
@@ -735,9 +735,11 @@
                 ExternalAppId.PIXEL_LAUNCHER,
                 IntentHandler.determineExternalIntentSource(intent, activity));
 
-        intent.putExtra(IntentHandler.EXTRA_ACTIVITY_REFERRER, "android.app.launcher");
+        intent.putExtra(
+                IntentHandler.EXTRA_ACTIVITY_REFERRER,
+                "android-app://com.sec.android.app.launcher");
         assertEquals(
-                ExternalAppId.THIRD_PARTY_LAUNCHER,
+                ExternalAppId.SAMSUNG_LAUNCHER,
                 IntentHandler.determineExternalIntentSource(intent, activity));
     }
 }
diff --git a/chrome/browser/accessibility/pdf_ocr_controller.cc b/chrome/browser/accessibility/pdf_ocr_controller.cc
index 54a9846..76be195 100644
--- a/chrome/browser/accessibility/pdf_ocr_controller.cc
+++ b/chrome/browser/accessibility/pdf_ocr_controller.cc
@@ -138,8 +138,8 @@
        base::SplitString(accept_languages, ",", base::TRIM_WHITESPACE,
                          base::SPLIT_WANT_NONEMPTY)) {
     // Convert to a Chrome language code synonym. This language synonym is then
-    // converted into a `LocaleCodeISO639` enum value for a UMA histogram. See
-    // tools/metrics/histograms/enums.xml enum LocaleCodeISO639. The enum there
+    // converted into a `LocaleCodeBCP47` enum value for a UMA histogram. See
+    // tools/metrics/histograms/enums.xml enum LocaleCodeBCP47. The enum there
     // doesn't always have locales where the base lang and the locale are the
     // same (e.g. they don't have id-id, but do have id). So if the base lang
     // and the locale are the same, just use the base lang.
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager_unittest.cc b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager_unittest.cc
index 7f0afdd..d5f32bd 100644
--- a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager_unittest.cc
+++ b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager_unittest.cc
@@ -788,7 +788,6 @@
                                  _, ::ash::kReportDeviceBootMode, true,
                                  metrics::kInitialCollectionDelay))
       .WillByDefault([&]() {
-        LOG(ERROR) << " lbaraz: CALLED ";
         return std::make_unique<FakeCollector>(&collector_count);
       });
 
diff --git a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillImageFetcher.java b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillImageFetcher.java
index 6006a67..76f2ace 100644
--- a/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillImageFetcher.java
+++ b/chrome/browser/autofill/android/java/src/org/chromium/chrome/browser/autofill/AutofillImageFetcher.java
@@ -223,7 +223,7 @@
 
         ImageFetcher.Params params =
                 ImageFetcher.Params.create(
-                        resolvedUrl, ImageFetcher.AUTOFILL_CARD_ART_UMA_CLIENT_NAME);
+                        resolvedUrl, ImageFetcher.AUTOFILL_IMAGE_FETCHER_UMA_CLIENT_NAME);
         mImageFetcher.fetchImage(params, onImageFetched);
     }
 
diff --git a/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationIntegrationTest.java b/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationIntegrationTest.java
index 1bdaa90..986f7f8 100644
--- a/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationIntegrationTest.java
+++ b/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationIntegrationTest.java
@@ -12,6 +12,13 @@
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
+import static org.hamcrest.Matchers.allOf;
+
+import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.addBlankTabs;
+import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.clickFirstCardFromTabSwitcher;
+import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.enterTabSwitcher;
+import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.mergeAllNormalTabsToAGroup;
+import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.verifyTabSwitcherCardCount;
 import static org.chromium.ui.test.util.ViewUtils.onViewWaiting;
 
 import androidx.test.filters.MediumTest;
@@ -28,6 +35,7 @@
 import org.chromium.base.test.util.DoNotBatch;
 import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.base.test.util.Restriction;
+import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.data_sharing.DataSharingServiceFactory;
 import org.chromium.chrome.browser.data_sharing.DataSharingUiDelegateAndroid;
 import org.chromium.chrome.browser.data_sharing.FakeDataSharingUIDelegateImpl;
@@ -198,4 +206,60 @@
                 WAIT_TIMEOUT_MS,
                 CriteriaHelper.DEFAULT_POLLING_INTERVAL);
     }
+
+    @Test
+    @MediumTest
+    public void testCollaborationCreateFlow() {
+        final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
+        final AtomicBoolean createCalled = new AtomicBoolean();
+        mDataSharingUIDelegate.setShowCreateFlowRunnable(() -> createCalled.set(true));
+
+        // Create a tab group and enter TabGridDialog.
+        addBlankTabs(cta, false, 3);
+        enterTabSwitcher(cta);
+        mergeAllNormalTabsToAGroup(cta);
+        verifyTabSwitcherCardCount(cta, 1);
+        clickFirstCardFromTabSwitcher(cta);
+        onViewWaiting(withId(R.id.share_button)).check(matches(isDisplayed())).perform(click());
+
+        // Verify that bottom sheet sign-in is shown and accept.
+        onViewWaiting(
+                allOf(
+                        withText(R.string.collaboration_signin_bottom_sheet_description),
+                        isDisplayed()));
+        final String continueAsText =
+                mActivityTestRule
+                        .getActivity()
+                        .getString(
+                                R.string.sync_promo_continue_as,
+                                TestAccounts.ACCOUNT1.getGivenName());
+        onView(withText(continueAsText)).perform(click());
+
+        // Verify that the history opt-in dialog is shown and accept.
+        onViewWaiting(
+                        withText(R.string.collaboration_sync_description),
+                        // checkRootDialog=true ensures dialog is in focus, avoid flakiness.
+                        true)
+                .check(matches(isDisplayed()));
+        onViewWaiting(withId(R.id.button_primary)).perform(click());
+
+        CriteriaHelper.pollInstrumentationThread(
+                () -> {
+                    return createCalled.get();
+                },
+                WAIT_TIMEOUT_MS,
+                CriteriaHelper.DEFAULT_POLLING_INTERVAL);
+    }
+
+    @Test
+    @MediumTest
+    public void testHistoryAndSyncDisabled() {
+        mActivityTestRule.getSigninTestRule().addAccountThenSignin(TestAccounts.ACCOUNT1);
+
+        mActivityTestRule.loadUrlInNewTab(
+                mUrl, /* incognito= */ false, TabLaunchType.FROM_EXTERNAL_APP);
+        // Verify that the history opt-in dialog is shown and refuse.
+        onViewWaiting(withText(R.string.collaboration_sync_description))
+                .check(matches(isDisplayed()));
+    }
 }
diff --git a/chrome/browser/commerce/coupons/android/java/src/org/chromium/chrome/browser/commerce/coupons/DiscountsButtonController.java b/chrome/browser/commerce/coupons/android/java/src/org/chromium/chrome/browser/commerce/coupons/DiscountsButtonController.java
index 313c33ab..15d6329 100644
--- a/chrome/browser/commerce/coupons/android/java/src/org/chromium/chrome/browser/commerce/coupons/DiscountsButtonController.java
+++ b/chrome/browser/commerce/coupons/android/java/src/org/chromium/chrome/browser/commerce/coupons/DiscountsButtonController.java
@@ -40,13 +40,13 @@
                 activeTabSupplier,
                 modalDialogManager,
                 AppCompatResources.getDrawable(context, R.drawable.ic_shoppingmode_24dp),
-                context.getString(R.string.discount_container_title),
-                R.string.discount_container_title,
-                true,
-                null,
+                /* contentDescription= */ context.getString(R.string.discount_container_title),
+                /* actionChipLabelResId= */ R.string.discount_container_title,
+                /* supportsTinting= */ true,
+                /* iphCommandBuilder= */ null,
                 AdaptiveToolbarButtonVariant.DISCOUNTS,
-                Resources.ID_NULL,
-                false);
+                /* tooltipTextResId= */ Resources.ID_NULL,
+                /* showBackgroundHighlight= */ true);
 
         mBottomSheetController = bottomSheetController;
         mBottomSheetObserver =
diff --git a/chrome/browser/commerce/price_insights/android/java/src/org/chromium/chrome/browser/price_insights/PriceInsightsButtonController.java b/chrome/browser/commerce/price_insights/android/java/src/org/chromium/chrome/browser/price_insights/PriceInsightsButtonController.java
index d7bebe8..775957a 100644
--- a/chrome/browser/commerce/price_insights/android/java/src/org/chromium/chrome/browser/price_insights/PriceInsightsButtonController.java
+++ b/chrome/browser/commerce/price_insights/android/java/src/org/chromium/chrome/browser/price_insights/PriceInsightsButtonController.java
@@ -74,7 +74,7 @@
                 /* iphCommandBuilder= */ null,
                 AdaptiveToolbarButtonVariant.PRICE_INSIGHTS,
                 /* tooltipTextResId= */ Resources.ID_NULL,
-                /* showBackgroundHighlight= */ false);
+                /* showBackgroundHighlight= */ true);
 
         mContext = context;
         mBottomSheetController = bottomSheetController;
diff --git a/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingButtonController.java b/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingButtonController.java
index f05d821..b75fb3e 100644
--- a/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingButtonController.java
+++ b/chrome/browser/commerce/price_tracking/android/java/src/org/chromium/chrome/browser/price_tracking/PriceTrackingButtonController.java
@@ -96,7 +96,7 @@
                         /* buttonVariant= */ AdaptiveToolbarButtonVariant.PRICE_TRACKING,
                         /* actionChipLabelResId= */ Resources.ID_NULL,
                         /* tooltipTextResId= */ Resources.ID_NULL,
-                        /* showBackgroundHighlight= */ false,
+                        /* showBackgroundHighlight= */ true,
                         /* hasErrorBadge= */ false);
 
         mBottomSheetObserver =
diff --git a/chrome/browser/data_sharing/android/java/res/layout/recent_activity_bottom_sheet.xml b/chrome/browser/data_sharing/android/java/res/layout/recent_activity_bottom_sheet.xml
index bab9c42f..acc66273 100644
--- a/chrome/browser/data_sharing/android/java/res/layout/recent_activity_bottom_sheet.xml
+++ b/chrome/browser/data_sharing/android/java/res/layout/recent_activity_bottom_sheet.xml
@@ -20,8 +20,7 @@
     android:orientation="horizontal"
     android:gravity="center_vertical"
     android:layout_marginTop="@dimen/recent_activity_title_top_margin"
-    android:paddingStart="@dimen/list_item_default_margin"
-    android:paddingEnd="@dimen/list_item_default_margin">
+    android:paddingStart="@dimen/list_item_default_margin">
 
         <TextView
             android:id="@+id/title"
@@ -35,6 +34,7 @@
             android:id="@+id/recent_activity_menu_button"
             android:layout_width="@dimen/min_touch_target_size"
             android:layout_height="@dimen/min_touch_target_size"
+            android:paddingEnd="@dimen/list_item_default_margin"
             android:background="@null"
             android:src="@drawable/ic_more_vert_24dp"
             android:contentDescription="@string/collaboration_recent_activity_menu_option"
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/FakeDataSharingUIDelegateImpl.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/FakeDataSharingUIDelegateImpl.java
index c7266e3..e1cd88110 100644
--- a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/FakeDataSharingUIDelegateImpl.java
+++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/FakeDataSharingUIDelegateImpl.java
@@ -20,6 +20,8 @@
 public class FakeDataSharingUIDelegateImpl implements DataSharingUIDelegate {
 
     private @Nullable Runnable mShowJoinFlowRunnable;
+    private @Nullable Runnable mShowCreateFlowRunnable;
+    private @Nullable Runnable mShowManageFlowRunnable;
 
     public FakeDataSharingUIDelegateImpl() {}
 
@@ -31,6 +33,7 @@
 
     @Override
     public String showCreateFlow(DataSharingCreateUiConfig createUiConfig) {
+        if (mShowCreateFlowRunnable != null) mShowCreateFlowRunnable.run();
         return "";
     }
 
@@ -42,6 +45,7 @@
 
     @Override
     public String showManageFlow(DataSharingManageUiConfig manageUiConfig) {
+        if (mShowManageFlowRunnable != null) mShowManageFlowRunnable.run();
         return "";
     }
 
@@ -56,4 +60,14 @@
     public void setShowJoinFlowRunnable(Runnable runnable) {
         mShowJoinFlowRunnable = runnable;
     }
+
+    /* Set a runnable to be called when showCreateFlow() is called. */
+    public void setShowCreateFlowRunnable(Runnable runnable) {
+        mShowCreateFlowRunnable = runnable;
+    }
+
+    /* Set a runnable to be called when showManageFlow() is called. */
+    public void setShowManageFlowRunnable(Runnable runnable) {
+        mShowManageFlowRunnable = runnable;
+    }
 }
diff --git a/chrome/browser/enterprise/connectors/reporting/reporting_event_router_unittest.cc b/chrome/browser/enterprise/connectors/reporting/reporting_event_router_unittest.cc
index cbc4347c..43e8fc7 100644
--- a/chrome/browser/enterprise/connectors/reporting/reporting_event_router_unittest.cc
+++ b/chrome/browser/enterprise/connectors/reporting/reporting_event_router_unittest.cc
@@ -403,9 +403,9 @@
       /*enabled_opt_in_events=*/{});
 
   test::EventReportValidatorBase validator(client_.get());
-  validator.ExpectSecurityInterstitialShown(
+  validator.ExpectSecurityInterstitialEvent(
       "https://phishing.com/", "PHISHING", profile_->GetProfileUserName(),
-      GetProfileIdentifier(), "EVENT_RESULT_WARNED", 0);
+      GetProfileIdentifier(), "EVENT_RESULT_WARNED", false, 0);
   reporting_event_router_->OnSecurityInterstitialShown(
       GURL("https://phishing.com/"), "PHISHING", 0, false);
 }
@@ -417,11 +417,25 @@
       /*enabled_opt_in_events=*/{});
 
   test::EventReportValidatorBase validator(client_.get());
-  validator.ExpectSecurityInterstitialShown(
+  validator.ExpectSecurityInterstitialEvent(
       "https://phishing.com/", "PHISHING", profile_->GetProfileUserName(),
-      GetProfileIdentifier(), "EVENT_RESULT_BLOCKED", 0);
+      GetProfileIdentifier(), "EVENT_RESULT_BLOCKED", false, 0);
   reporting_event_router_->OnSecurityInterstitialShown(
       GURL("https://phishing.com/"), "PHISHING", 0, true);
 }
 
+TEST_F(ReportingEventRouterTest, TestInterstitialProceeded) {
+  test::SetOnSecurityEventReporting(
+      profile_->GetPrefs(), /*enabled=*/true,
+      /*enabled_event_names=*/{kKeyInterstitialEvent},
+      /*enabled_opt_in_events=*/{});
+
+  test::EventReportValidatorBase validator(client_.get());
+  validator.ExpectSecurityInterstitialEvent(
+      "https://phishing.com/", "PHISHING", profile_->GetProfileUserName(),
+      GetProfileIdentifier(), "EVENT_RESULT_BYPASSED", true, 0);
+  reporting_event_router_->OnSecurityInterstitialProceeded(
+      GURL("https://phishing.com/"), "PHISHING", 0);
+}
+
 }  // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/profile_management/oidc_auth_response_capture_navigation_throttle_unittest.cc b/chrome/browser/enterprise/profile_management/oidc_auth_response_capture_navigation_throttle_unittest.cc
index c98894ce..0cda658 100644
--- a/chrome/browser/enterprise/profile_management/oidc_auth_response_capture_navigation_throttle_unittest.cc
+++ b/chrome/browser/enterprise/profile_management/oidc_auth_response_capture_navigation_throttle_unittest.cc
@@ -6,7 +6,6 @@
 
 #include "base/base64.h"
 #include "base/base64url.h"
-#include "base/features.h"
 #include "base/json/json_writer.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
@@ -724,23 +723,6 @@
       OidcInterceptionResult::kInvalidUrlOrTokens);
 }
 
-TEST_P(OidcAuthResponseCaptureNavigationThrottleTest, DataDecoderFailure) {
-  // Disable the Rust JSON parser, as it is in-process and cannot crash.
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatureState(base::features::kUseRustJsonParser, false);
-  in_process_data_decoder_.SimulateJsonParserCrash(/*drop=*/true);
-
-  std::string redirection_url =
-      BuildStandardResponseUrl(/*oidc_state=*/std::string());
-
-  auto* oidc_interceptor = GetMockOidcInterceptor();
-  RunThrottleAndExpectNoOidcInterception(oidc_interceptor, redirection_url,
-                                         NavigationThrottle::DEFER);
-  CheckFunnelAndResultHistogram(
-      OidcInterceptionFunnelStep::kValidRedirectionCaptured,
-      OidcInterceptionResult::kInvalidUrlOrTokens);
-}
-
 TEST_P(OidcAuthResponseCaptureNavigationThrottleTest, NoServiceForGuestMode) {
   TestNoServiceForInvalidProfile(profile_manager()->CreateGuestProfile());
 }
diff --git a/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc b/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc
index 96b5d27..3f26116 100644
--- a/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc
+++ b/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc
@@ -144,7 +144,7 @@
   EXPECT_TRUE(RunSettingsSubtest("getPref_CrOSSetting")) << message_;
 }
 
-IN_PROC_BROWSER_TEST_P(SettingsPrivateApiTest, SetPref_CrOSSetting) {
+IN_PROC_BROWSER_TEST_P(SettingsPrivateApiTest, DISABLED_SetPref_CrOSSetting) {
   EXPECT_TRUE(RunSettingsSubtest("setPref_CrOSSetting")) << message_;
 }
 
diff --git a/chrome/browser/extensions/content_verifier_browsertest.cc b/chrome/browser/extensions/content_verifier_browsertest.cc
index 90fd91d..c71db01 100644
--- a/chrome/browser/extensions/content_verifier_browsertest.cc
+++ b/chrome/browser/extensions/content_verifier_browsertest.cc
@@ -1177,16 +1177,8 @@
 // disable the extension, both in case-sensitive and case-insensitive systems.
 //
 // Regression test for https://crbug.com/1033294.
-// Consistently fails on Mac11, Mac12, and Mac13 bots (crbug.com/414579613).
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_RemainsEnabledOnNavigateToPathWithIncorrectCase \
-  DISABLED_RemainsEnabledOnNavigateToPathWithIncorrectCase
-#else
-#define MAYBE_RemainsEnabledOnNavigateToPathWithIncorrectCase \
-  RemainsEnabledOnNavigateToPathWithIncorrectCase
-#endif
 IN_PROC_BROWSER_TEST_F(ContentVerifierTest,
-                       MAYBE_RemainsEnabledOnNavigateToPathWithIncorrectCase) {
+                       RemainsEnabledOnNavigateToPathWithIncorrectCase) {
   const Extension* extension = InstallExtensionFromWebstore(
       test_data_dir_.AppendASCII("content_verifier/content_script.crx"), 1);
   ASSERT_TRUE(extension);
@@ -1199,8 +1191,8 @@
       extension_id, base::FilePath().AppendASCII(kIncorrectCasePath));
 
   GURL page_url = extension->GetResourceURL(kIncorrectCasePath);
-#if BUILDFLAG(IS_WIN)
-  // Windows is case insensitive, load should succeed.
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
+  // Some platforms are case insensitive, load should succeed.
   ASSERT_TRUE(NavigateToURL(page_url));
   ASSERT_TRUE(content::WaitForLoadStop(GetActiveWebContents()));
 #else
diff --git a/chrome/browser/extensions/extension_security_exploit_browsertest.cc b/chrome/browser/extensions/extension_security_exploit_browsertest.cc
index 6c33c06c..18babd9 100644
--- a/chrome/browser/extensions/extension_security_exploit_browsertest.cc
+++ b/chrome/browser/extensions/extension_security_exploit_browsertest.cc
@@ -482,12 +482,6 @@
 
 IN_PROC_BROWSER_TEST_F(OpenChannelToExtensionExploitTest,
                        FromContentScript_BadSourceUrl_FromFrame) {
-  if (!base::FeatureList::IsEnabled(
-          extensions_features::kExtensionSourceUrlEnforcement)) {
-    GTEST_SKIP() << "...BadSourceUrl... tests require "
-                 << "the kExtensionSourceUrlEnforcement feature";
-  }
-
   // Trigger sending of a valid ExtensionHostMsg_OpenChannelToExtension IPC
   // from a content script of an `active_extension_id`.
   ASSERT_TRUE(ExecuteProgrammaticContentScript(
@@ -519,12 +513,6 @@
 
 IN_PROC_BROWSER_TEST_F(OpenChannelToExtensionExploitTest,
                        FromServiceWorker_BadSourceUrl) {
-  if (!base::FeatureList::IsEnabled(
-          extensions_features::kExtensionSourceUrlEnforcement)) {
-    GTEST_SKIP() << "...BadSourceUrl... tests require "
-                 << "the kExtensionSourceUrlEnforcement feature";
-  }
-
   // Navigate the test tab to an extension page.
   // TODO(crbug.com/40874764): Remove this test step - it is only here as
   // a workaround for the bug that impacts how renderer kills are detected when
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index cabe4bc..e17f127 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -5188,7 +5188,7 @@
       "birnie@google.com",
       "//chrome/browser/glic/OWNERS"
     ],
-    "expiry_milestone": 137
+    "expiry_milestone": 140
   },
   {
     "name": "glic-user-resize",
@@ -5196,7 +5196,7 @@
       "iwells@chromium.org",
       "//chrome/browser/glic/OWNERS"
     ],
-    "expiry_milestone": 137
+    "expiry_milestone": 139
   },
   {
     "name": "glic-z-order-changes",
@@ -5204,7 +5204,7 @@
       "andreaxg@google.com",
       "//chrome/browser/glic/OWNERS"
     ],
-    "expiry_milestone": 137
+    "expiry_milestone": 139
   },
   {
     "name": "glic-zero-state-suggestions",
diff --git a/chrome/browser/glic/glic_keyed_service.cc b/chrome/browser/glic/glic_keyed_service.cc
index 295da19..0a4604d 100644
--- a/chrome/browser/glic/glic_keyed_service.cc
+++ b/chrome/browser/glic/glic_keyed_service.cc
@@ -193,7 +193,7 @@
         callback) {
   auto* active_web_contents = GetFocusedTabData().focus();
 
-  if (contextual_cueing_service_ && active_web_contents) {
+  if (contextual_cueing_service_ && active_web_contents && IsWindowShowing()) {
     auto suggestions = mojom::ZeroStateSuggestions::New();
     suggestions->tab_id = GetTabId(active_web_contents);
     suggestions->tab_url = active_web_contents->GetLastCommittedURL();
diff --git a/chrome/browser/glic/host/glic_api_uitest.cc b/chrome/browser/glic/host/glic_api_uitest.cc
index 6f5740b1..9d71954 100644
--- a/chrome/browser/glic/host/glic_api_uitest.cc
+++ b/chrome/browser/glic/host/glic_api_uitest.cc
@@ -16,6 +16,7 @@
 #include "base/run_loop.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/test/bind.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/run_until.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_future.h"
@@ -433,6 +434,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(GlicApiTest, testInitializeFailsWindowClosed) {
+  base::HistogramTester histogram_tester;
   // Immediately close the window to check behavior while window is closed.
   // Fail client initialization, should see error page.
   RunTestSequence(
@@ -440,6 +442,8 @@
   window_controller().Close();
   ExecuteJsTest();
   WaitForWebUiState(mojom::WebUiState::kError);
+  histogram_tester.ExpectUniqueSample("Glic.Host.WebClientState.OnDestroy",
+                                      /*WEB_CLIENT_INITIALIZE_FAILED=*/2, 1);
 }
 
 IN_PROC_BROWSER_TEST_F(GlicApiTest, testInitializeFailsWindowOpen) {
@@ -547,10 +551,45 @@
   listener.WaitForWebUiState(mojom::WebUiState::kError);
 }
 
+IN_PROC_BROWSER_TEST_F(GlicApiTestWithFastTimeout, testNoClientCreated) {
+#if defined(SLOW_BINARY)
+  GTEST_SKIP() << "skip timeout test for slow binary";
+#else
+  base::HistogramTester histogram_tester;
+  RunTestSequence(
+      OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
+  WebUIStateListener listener(&window_controller());
+  ExecuteJsTest();
+  listener.WaitForWebUiState(mojom::WebUiState::kError);
+  // Note that the client does receive the bootstrap message, but never calls
+  // back, so from the host's perspective bootstrapping is still pending.
+  histogram_tester.ExpectUniqueSample("Glic.Host.WebClientState.OnDestroy",
+                                      0 /*BOOTSTRAP_PENDING*/, 1);
+#endif
+}
+
+// In this test, the client page does not initiate the bootstrap process, so no
+// client connects.
+IN_PROC_BROWSER_TEST_F(GlicApiTestWithFastTimeout, testNoBootstrap) {
+#if defined(SLOW_BINARY)
+  GTEST_SKIP() << "skip timeout test for slow binary";
+#else
+  base::HistogramTester histogram_tester;
+  RunTestSequence(
+      OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
+  WebUIStateListener listener(&window_controller());
+  ExecuteJsTest();
+  listener.WaitForWebUiState(mojom::WebUiState::kError);
+  histogram_tester.ExpectUniqueSample("Glic.Host.WebClientState.OnDestroy",
+                                      0 /*BOOTSTRAP_PENDING*/, 1);
+#endif
+}
+
 IN_PROC_BROWSER_TEST_F(GlicApiTestWithFastTimeout, testInitializeTimesOut) {
 #if defined(SLOW_BINARY)
   GTEST_SKIP() << "skip timeout test for slow binary";
 #else
+  base::HistogramTester histogram_tester;
   RunTestSequence(
       OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
   WebUIStateListener listener(&window_controller());
@@ -558,6 +597,8 @@
       .params = base::Value(base::Value::Dict().Set("failWith", "timeout")),
   });
   listener.WaitForWebUiState(mojom::WebUiState::kError);
+  histogram_tester.ExpectUniqueSample("Glic.Host.WebClientState.OnDestroy",
+                                      3 /*WEB_CLIENT_NOT_INITIALIZED*/, 1);
 #endif
 }
 
@@ -907,6 +948,16 @@
   }));
 }
 
+// TODO(harringtond): This is flaky.
+IN_PROC_BROWSER_TEST_F(GlicApiTest, DISABLED_testCloseAndOpenWhileOpening) {
+  RunTestSequence(
+      OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
+  ExecuteJsTest();
+  RunTestSequence(
+      OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
+  ContinueJsTest();
+}
+
 IN_PROC_BROWSER_TEST_F(GlicApiTestWithOneTab,
                        testNotifyPanelWillOpenIsCalledOnce) {
   ExecuteJsTest();
@@ -1107,6 +1158,8 @@
 }
 
 IN_PROC_BROWSER_TEST_F(GlicApiTest, testNavigateToDifferentClientPage) {
+  base::HistogramTester histogram_tester;
+
   WebUIStateListener listener(&window_controller());
   RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
                                  GlicInstrumentMode::kHostAndContents));
@@ -1115,6 +1168,10 @@
   listener.WaitForWebUiState(mojom::WebUiState::kBeginLoad);
   listener.WaitForWebUiState(mojom::WebUiState::kReady);
   ExecuteJsTest({.params = base::Value(1)});  // test run count: 1.
+  histogram_tester.ExpectUniqueSample("Glic.Host.WebClientState.OnCommit",
+                                      6 /*RESPONSIVE*/, 1);
+  histogram_tester.ExpectUniqueSample("Glic.Host.WebClientState.OnDestroy",
+                                      0 /*BOOTSTRAP_PENDING*/, 1);
 }
 
 // TODO(crbug.com/410881522): Re-enable this test
diff --git a/chrome/browser/glic/widget/glic_widget.cc b/chrome/browser/glic/widget/glic_widget.cc
index 9c6ce5b2..623f306 100644
--- a/chrome/browser/glic/widget/glic_widget.cc
+++ b/chrome/browser/glic/widget/glic_widget.cc
@@ -208,6 +208,7 @@
 
 void GlicWidget::OnThemeChanged() {
   NotifyColorProviderChanged();
+  ThemeChanged();
 }
 
 }  // namespace glic
diff --git a/chrome/browser/global_keyboard_shortcuts_mac.mm b/chrome/browser/global_keyboard_shortcuts_mac.mm
index cbc0d472..795cc37 100644
--- a/chrome/browser/global_keyboard_shortcuts_mac.mm
+++ b/chrome/browser/global_keyboard_shortcuts_mac.mm
@@ -157,7 +157,7 @@
       keys.push_back(
           {true, false, true, false, kVK_ANSI_C, IDC_ADD_NEW_TAB_TO_GROUP});
       keys.push_back(
-          {true, false, true, false, kVK_ANSI_D, IDC_CREATE_NEW_TAB_GROUP});
+          {true, false, true, false, kVK_ANSI_P, IDC_CREATE_NEW_TAB_GROUP});
       keys.push_back(
           {true, false, true, false, kVK_ANSI_W, IDC_CLOSE_TAB_GROUP});
       keys.push_back(
diff --git a/chrome/browser/lens/core/mojom/lens_side_panel.mojom b/chrome/browser/lens/core/mojom/lens_side_panel.mojom
index 5dedab1..3561101 100644
--- a/chrome/browser/lens/core/mojom/lens_side_panel.mojom
+++ b/chrome/browser/lens/core/mojom/lens_side_panel.mojom
@@ -26,6 +26,24 @@
   GetIsContextualSearchbox() => (bool is_contextual_searchbox);
 };
 
+// Enumerates the semantic events that can be logged by the Lens Overlay.
+// LINT.IfChange(SidePanelResultStatus)
+enum SidePanelResultStatus {
+  // The result status is unknown or uninitialized. Should not be logged.
+  kUnknown = 0,
+  // The result frame was shown in the side panel.
+  kResultShown = 1,
+  // The error page was shown due to the user being offline when the side panel
+  // attempted to load.
+  kErrorPageShownOffline = 2,
+  // The error page was shown due to the initial full image query failing due to
+  // error.
+  kErrorPageShownStartQueryError = 3,
+  // The error page was shown because page was protected.
+  kErrorPageShownProtected = 4,
+};
+// LINT.ThenChange(//tools/metrics/histograms/metadata/lens/enums.xml:LensOverlaySidePanelResultStatus)
+
 // Side Panel WebUI page handler for request from Browser side.
 // (C++ -> TypeScript)
 interface LensSidePanelPage {
@@ -48,8 +66,8 @@
 
   // Sets whether to show a full error page in the side panel WebUI. This is
   // used when the user opens the side panel in an offline state or the full
-  // image request times out.
-  SetShowErrorPage(bool should_show_error_page);
+  // image request times out. The error type is denoted by `status`.
+  SetShowErrorPage(bool should_show_error_page, SidePanelResultStatus status);
 
   // Suppress the ghost loader when no bytes are returned for the page.
   SuppressGhostLoader();
diff --git a/chrome/browser/privacy/BUILD.gn b/chrome/browser/privacy/BUILD.gn
index 60f9ce12..747febf8 100644
--- a/chrome/browser/privacy/BUILD.gn
+++ b/chrome/browser/privacy/BUILD.gn
@@ -72,6 +72,10 @@
     ]
   }
 
+  android_library("privacy_settings_java") {
+    sources = [ "settings/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettingsNavigation.java" ]
+  }
+
   android_resources("java_resources") {
     sources = [
       "java/res/layout/secure_dns_provider_preference.xml",
diff --git a/chrome/browser/privacy/settings/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettingsNavigation.java b/chrome/browser/privacy/settings/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettingsNavigation.java
new file mode 100644
index 0000000..1c6e5dd
--- /dev/null
+++ b/chrome/browser/privacy/settings/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettingsNavigation.java
@@ -0,0 +1,16 @@
+// 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.privacy.settings;
+
+import org.chromium.build.annotations.NullMarked;
+
+/** Arguments for {@link PrivacySettings} {@link SettingsNavigation}. */
+@NullMarked
+public class PrivacySettingsNavigation {
+    // Extra for intent to launch PrivacySettings fragment. Extra indicates that PrivacySettings
+    // should scroll to "advanced-protection" section after launching PrivacySettings.
+    public static final String EXTRA_FOCUS_ADVANCED_PROTECTION_SECTION =
+            "focus_advanced_protection_section";
+}
diff --git a/chrome/browser/privacy_sandbox/notice/notice_service.cc b/chrome/browser/privacy_sandbox/notice/notice_service.cc
index 5342642..09cf427 100644
--- a/chrome/browser/privacy_sandbox/notice/notice_service.cc
+++ b/chrome/browser/privacy_sandbox/notice/notice_service.cc
@@ -44,7 +44,7 @@
 void PrivacySandboxNoticeService::EventOccurred(
     NoticeId notice_id,
     PrivacySandboxNoticeEvent event) {
-  GetNoticeStorage()->RecordEvent(notice_id, event);
+  notice_storage()->RecordEvent(notice_id, event);
 
   auto notice_ptr = catalog_->GetNoticeMap().find(notice_id);
   CHECK(notice_ptr != catalog_->GetNoticeMap().end());
@@ -60,20 +60,8 @@
   return required_notices;
 }
 
-NoticeStorage* PrivacySandboxNoticeService::GetNoticeStorage() {
-  return notice_storage_.get();
-}
-
-PrefService* PrivacySandboxNoticeService::GetPrefService() {
-  return profile_->GetPrefs();
-}
-
-NoticeCatalog* PrivacySandboxNoticeService::GetCatalog() {
-  return catalog_.get();
-}
-
 void PrivacySandboxNoticeService::EmitStartupHistograms() {
-  GetNoticeStorage()->RecordStartupHistograms();
+  notice_storage()->RecordStartupHistograms();
 }
 
 #if !BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/privacy_sandbox/notice/notice_service.h b/chrome/browser/privacy_sandbox/notice/notice_service.h
index 08cb5627..744e7b4 100644
--- a/chrome/browser/privacy_sandbox/notice/notice_service.h
+++ b/chrome/browser/privacy_sandbox/notice/notice_service.h
@@ -16,7 +16,6 @@
 #endif  // !BUILDFLAG(IS_ANDROID)
 
 class Profile;
-class PrefService;
 
 namespace privacy_sandbox {
 
@@ -44,11 +43,6 @@
   void EventOccurred(NoticeId notice_id,
                      notice::mojom::PrivacySandboxNoticeEvent event) override;
 
-  // Service Accessors.
-  NoticeStorage* GetNoticeStorage();
-  PrefService* GetPrefService();
-  NoticeCatalog* GetCatalog();
-
 #if !BUILDFLAG(IS_ANDROID)
   DesktopViewManagerInterface* GetDesktopViewManager() override;
 #endif  // !BUILDFLAG(IS_ANDROID)
@@ -58,10 +52,14 @@
 
  private:
   void EmitStartupHistograms();
+
+  NoticeStorage* notice_storage() { return notice_storage_.get(); }
+
   // TODO(crbug.com/392612108): Create eligibility and notice result callbacks.
   raw_ptr<Profile> profile_;
   std::unique_ptr<NoticeCatalog> catalog_;
   std::unique_ptr<NoticeStorage> notice_storage_;
+
 #if !BUILDFLAG(IS_ANDROID)
   std::unique_ptr<DesktopViewManagerInterface> desktop_view_manager_;
 #endif  // !BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/resources/bookmarks/bookmarks.ts b/chrome/browser/resources/bookmarks/bookmarks.ts
index fce1bcd7..87e30696 100644
--- a/chrome/browser/resources/bookmarks/bookmarks.ts
+++ b/chrome/browser/resources/bookmarks/bookmarks.ts
@@ -19,7 +19,7 @@
 export {BookmarksFolderNodeElement} from './folder_node.js';
 export {BookmarksItemElement} from './item.js';
 export {BookmarksListElement} from './list.js';
-export {reduceAction, updateFolderOpenState, updateNodes, updateSelectedFolder, updateSelection} from './reducers.js';
+export {reduceAction, updateFolderOpenState, updateNodes, updateSelection} from './reducers.js';
 export {BookmarksRouter} from './router.js';
 export {Store} from './store.js';
 export {StoreClientMixinLit} from './store_client_mixin_lit.js';
diff --git a/chrome/browser/resources/bookmarks/reducers.ts b/chrome/browser/resources/bookmarks/reducers.ts
index 16c93436..0f931ef 100644
--- a/chrome/browser/resources/bookmarks/reducers.ts
+++ b/chrome/browser/resources/bookmarks/reducers.ts
@@ -268,8 +268,7 @@
   return false;
 }
 
-// Exported for tests.
-export function updateSelectedFolder(
+function updateSelectedFolder(
     selectedFolder: string, action: Action, nodes: NodeMap): string {
   switch (action.name) {
     case 'select-folder':
@@ -362,13 +361,12 @@
 
 export function reduceAction(
     state: BookmarksPageState, action: Action): BookmarksPageState {
-  const updatedNodes = updateNodes(state.nodes, action);
   return {
-    nodes: updatedNodes,
+    nodes: updateNodes(state.nodes, action),
     selectedFolder:
-        updateSelectedFolder(state.selectedFolder, action, updatedNodes),
+        updateSelectedFolder(state.selectedFolder, action, state.nodes),
     folderOpenState:
-        updateFolderOpenState(state.folderOpenState, action, updatedNodes),
+        updateFolderOpenState(state.folderOpenState, action, state.nodes),
     prefs: updatePrefs(state.prefs, action),
     search: updateSearch(state.search, action),
     selection: updateSelection(state.selection, action),
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common_manifest.json.jinja2 b/chrome/browser/resources/chromeos/accessibility/accessibility_common_manifest.json.jinja2
index 2702e018..44a86f5 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common_manifest.json.jinja2
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common_manifest.json.jinja2
@@ -9,11 +9,15 @@
     "service_worker": "accessibility_common/mv3/accessibility_common_loader.ts",
     "type": "module"
   },
+  "content_security_policy": {
+    "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'"
+  },
 {% else %}
   "manifest_version": 2,
   "background": {
     "page": "accessibility_common/mv2/background.html"
   },
+  "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
 {% endif %}
   "name": "Accessibility Common",
   "version": "{{set_version}}",
@@ -21,7 +25,6 @@
 {% if is_guest_manifest == '1' %}
   "incognito": "split",
 {% endif %}
-  "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
   "permissions": [
     "accessibilityPrivate",
     "accessibilityFeatures.read",
diff --git a/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts b/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts
index d50864b..aa2e2f1 100644
--- a/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts
+++ b/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts
@@ -37,6 +37,22 @@
   ERROR,  // Final state
 }
 
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+//
+// LINT.IfChange(DetailedWebClientState)
+export enum DetailedWebClientState {
+  BOOTSTRAP_PENDING = 0,
+  WEB_CLIENT_NOT_CREATED = 1,
+  WEB_CLIENT_INITIALIZE_FAILED = 2,
+  WEB_CLIENT_NOT_INITIALIZED = 3,
+  TEMPORARY_UNRESPONSIVE = 4,
+  PERMANENT_UNRESPONSIVE = 5,
+  RESPONSIVE = 6,
+  MAX_VALUE = RESPONSIVE,
+}
+// LINT.ThenChange(//tools/metrics/histograms/metadata/glic/enums.xml:GlicDetailedWebClientState)
+
 // Implemented by the embedder of GlicApiHost.
 export interface ApiHostEmbedder {
   // Called when the guest requests resize.
@@ -199,6 +215,8 @@
     if (this.receiver) {
       throw new Error('web client already created');
     }
+    this.host.detailedWebClientState =
+        DetailedWebClientState.WEB_CLIENT_NOT_INITIALIZED;
     this.receiver = new WebClientReceiver(
         new WebClientImpl(this.sender, this.host, this.embedder));
     const {initialState} = await this.handler.webClientCreated(
@@ -569,6 +587,7 @@
   private webClientState =
       ObservableValue.withValue<WebClientState>(WebClientState.UNINITIALIZED);
   private waitingOnPanelWillOpenValue = false;
+  detailedWebClientState = DetailedWebClientState.BOOTSTRAP_PENDING;
 
   constructor(
       private browserProxy: BrowserProxy, private windowProxy: WindowProxy,
@@ -621,11 +640,14 @@
 
   // Called when the web client is initialized.
   webClientInitialized() {
+    this.detailedWebClientState = DetailedWebClientState.RESPONSIVE;
     this.setWebClientState(WebClientState.RESPONSIVE);
     this.responsiveCheckLoop();
   }
 
   webClientInitializeFailed() {
+    this.detailedWebClientState =
+        DetailedWebClientState.WEB_CLIENT_INITIALIZE_FAILED;
     this.setWebClientState(WebClientState.ERROR);
   }
 
@@ -637,6 +659,10 @@
     return this.webClientState;
   }
 
+  getDetailedWebClientState(): DetailedWebClientState {
+    return this.detailedWebClientState;
+  }
+
   // Sends a message to the webview which is required to initialize the client.
   // Because we don't know when the client will be ready to receive this
   // message, we start sending this every 50ms as soon as navigation commits on
@@ -692,6 +718,7 @@
       if (gotResponse) {  // Success
         this.webClientErrorTimer.reset();
         this.setWebClientState(WebClientState.RESPONSIVE);
+        this.detailedWebClientState = DetailedWebClientState.RESPONSIVE;
 
         await sleep(checkIntervalMs);
         continue;
@@ -699,6 +726,8 @@
 
       // Failed, not responsive.
       if (this.webClientState.getCurrentValue() === WebClientState.RESPONSIVE) {
+        this.detailedWebClientState =
+            DetailedWebClientState.TEMPORARY_UNRESPONSIVE;
         this.setWebClientState(WebClientState.UNRESPONSIVE);
         this.startWebClientErrorTimer();
       }
@@ -711,6 +740,8 @@
 
   startWebClientErrorTimer() {
     this.webClientErrorTimer.start(() => {
+      this.detailedWebClientState =
+          DetailedWebClientState.PERMANENT_UNRESPONSIVE;
       this.setWebClientState(WebClientState.ERROR);
     });
   }
@@ -737,6 +768,11 @@
       return;
     }
 
+    if (this.detailedWebClientState ===
+        DetailedWebClientState.BOOTSTRAP_PENDING) {
+      this.detailedWebClientState =
+          DetailedWebClientState.WEB_CLIENT_NOT_CREATED;
+    }
     this.stopBootstrapPing();
 
     const response =
diff --git a/chrome/browser/resources/glic/webview.ts b/chrome/browser/resources/glic/webview.ts
index edbc385..48b9a53c 100644
--- a/chrome/browser/resources/glic/webview.ts
+++ b/chrome/browser/resources/glic/webview.ts
@@ -8,10 +8,11 @@
 
 import type {BrowserProxyImpl} from './browser_proxy.js';
 import type {Subscriber} from './glic_api/glic_api.js';
-import {GlicApiHost, WebClientState} from './glic_api_impl/glic_api_host.js';
+import {DetailedWebClientState, GlicApiHost, WebClientState} from './glic_api_impl/glic_api_host.js';
 import type {ApiHostEmbedder} from './glic_api_impl/glic_api_host.js';
 import {ObservableValue} from './observable.js';
 import type {ObservableValueReadOnly} from './observable.js';
+import {OneShotTimer} from './timer.js';
 
 export type PageType =
     // A login page.
@@ -82,6 +83,7 @@
   private eventTracker = new EventTracker();
   private webClientState =
       ObservableValue.withValue(WebClientState.UNINITIALIZED);
+  private oneMinuteTimer = new OneShotTimer(1000 * 60);
 
   constructor(
       private readonly container: HTMLElement,
@@ -135,6 +137,15 @@
     this.eventTracker.add(this.webview, 'exit', this.onExit.bind(this));
 
     this.webview.src = this.persistentState.useLoadUrl();
+
+    this.oneMinuteTimer.start(() => {
+      if (this.host) {
+        chrome.metricsPrivate.recordEnumerationValue(
+            'Glic.Host.WebClientState.AtOneMinute',
+            this.host.getDetailedWebClientState(),
+            DetailedWebClientState.MAX_VALUE + 1);
+      }
+    });
   }
 
   getWebClientState(): ObservableValueReadOnly<WebClientState> {
@@ -142,6 +153,13 @@
   }
 
   destroy() {
+    this.oneMinuteTimer.reset();
+    if (this.host) {
+      chrome.metricsPrivate.recordEnumerationValue(
+          'Glic.Host.WebClientState.OnDestroy',
+          this.host.getDetailedWebClientState(),
+          DetailedWebClientState.MAX_VALUE + 1);
+    }
     this.destroyHost(
         this.webClientState.getCurrentValue() === WebClientState.ERROR ?
             WebClientState.ERROR :
@@ -223,6 +241,12 @@
     if (!isTopLevel) {
       return;
     }
+    if (this.host) {
+      chrome.metricsPrivate.recordEnumerationValue(
+          'Glic.Host.WebClientState.OnCommit',
+          this.host.getDetailedWebClientState(),
+          DetailedWebClientState.MAX_VALUE + 1);
+    }
     const wasResponsive = this.getWebClientState().getCurrentValue() ===
         WebClientState.RESPONSIVE;
 
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 77fc8e1..38a6be4 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
@@ -23,6 +23,7 @@
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import type {SearchboxGhostLoaderElement} from '/lens/shared/searchbox_ghost_loader.js';
 
+import {SidePanelResultStatus} from '../lens_side_panel.mojom-webui.js';
 import type {LensSidePanelPageHandlerInterface} from '../lens_side_panel.mojom-webui.js';
 import {PageContentType} from '../page_content_type.mojom-webui.js';
 import {handleEscapeSearchbox} from '../searchbox_utils.js';
@@ -372,8 +373,10 @@
     }
   }
 
-  private setShowErrorPage(shouldShowErrorPage: boolean) {
-    this.$.errorPage.setIsProtectedError(false);
+  private setShowErrorPage(
+      shouldShowErrorPage: boolean, status: SidePanelResultStatus) {
+    this.$.errorPage.setIsProtectedError(
+        status === SidePanelResultStatus.kErrorPageShownProtected);
     this.isErrorPageVisible =
         shouldShowErrorPage && loadTimeData.getBoolean('enableErrorPage');
   }
diff --git a/chrome/browser/resources/print_preview/BUILD.gn b/chrome/browser/resources/print_preview/BUILD.gn
index 8ea61af..e49ebec6 100644
--- a/chrome/browser/resources/print_preview/BUILD.gn
+++ b/chrome/browser/resources/print_preview/BUILD.gn
@@ -98,6 +98,8 @@
     "ui/duplex_settings.css",
     "ui/header.css",
     "ui/link_container.css",
+    "ui/margin_control.css",
+    "ui/margin_control_container.css",
     "ui/media_size_settings.css",
     "ui/more_settings.css",
     "ui/number_settings_section.css",
diff --git a/chrome/browser/resources/print_preview/ui/margin_control.css b/chrome/browser/resources/print_preview/ui/margin_control.css
new file mode 100644
index 0000000..17d1cd2
--- /dev/null
+++ b/chrome/browser/resources/print_preview/ui/margin_control.css
@@ -0,0 +1,138 @@
+/* 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. */
+
+/* #css_wrapper_metadata_start
+ * #type=style-lit
+ * #import=chrome://resources/cr_elements/cr_input/cr_input_style_lit.css.js
+ * #import=chrome://resources/cr_elements/cr_shared_vars.css.js
+ * #include=cr-input-style-lit
+ * #css_wrapper_metadata_end */
+
+:host {
+  display: block;
+  position: absolute;
+  transition: opacity 150ms linear;
+}
+
+:host([invisible]) {
+  opacity: 0;
+}
+
+:host([disabled]),
+:host([invisible]) {
+  pointer-events: none;
+}
+
+:host([side=top]) #lineContainer,
+:host([side=bottom]) #lineContainer {
+  cursor: ns-resize;
+  padding: 8px 0;
+  width: 100%;
+}
+
+:host([side=left]) #lineContainer,
+:host([side=right]) #lineContainer {
+  cursor: ew-resize;
+  height: 100%;
+  padding: 0 8px;
+}
+
+#line {
+  border: 1px dashed var(--google-blue-500);
+}
+
+@media (prefers-color-scheme: dark) {
+  #line {
+    border-color: var(--google-blue-300);
+  }
+}
+
+:host([side=top]) #line,
+:host([side=bottom]) #line {
+  width: 100%;
+}
+
+:host([side=left]) #line,
+:host([side=right]) #line {
+  height: 100%;
+}
+
+#row-container {
+  border-radius: 4px;
+  font-size: 0.8rem;
+  min-height: 25px;
+  overflow: hidden;
+  padding: 1px;
+  position: absolute;
+}
+
+@media (prefers-color-scheme: light) {
+  #row-container {
+    --cr-input-background-color: var(--cr-primary-text-color);
+    --cr-input-color: white;
+    background-color: var(--cr-primary-text-color);
+    color: white;
+  }
+}
+
+@media (prefers-color-scheme: dark) {
+  #row-container {
+    --cr-input-background-color: rgb(27, 28, 30);  /* GG900 + 30% black */
+    --cr-input-color: var(--cr-primary-text-color);
+    background-color: rgb(27, 28, 30);  /* GG900 + 30% black */
+    color: var(--cr-primary-text-color);
+  }
+}
+
+:host([side=top]) #row-container {
+  left: 50%;
+  top: 9px;
+}
+
+:host([side=right]) #row-container {
+  right: 9px;
+  top: 50%;
+}
+
+:host([side=bottom]) #row-container {
+  bottom: 9px;
+  right: 50%;
+}
+
+:host([side=left]) #row-container {
+  bottom: 50%;
+  left: 9px;
+}
+
+:host([disabled]) #row-container {
+  opacity: var(--cr-disabled-opacity);
+}
+
+:host([invalid]) #input {
+  caret-color: var(--cr-input-error-color);
+}
+
+:host([invalid]) #underline {
+  border-color: var(--cr-input-error-color);
+}
+
+#row-container,
+#input-container {
+  align-items: center;
+  display: flex;
+}
+
+#input-container {
+  position: relative;
+}
+
+#input {
+  padding-inline-end: 0;
+  text-align: end;
+  width: 44px;
+}
+
+#unit {
+  padding-inline-end: 8px;
+}
diff --git a/chrome/browser/resources/print_preview/ui/margin_control.html b/chrome/browser/resources/print_preview/ui/margin_control.html
index 780498e..83743336 100644
--- a/chrome/browser/resources/print_preview/ui/margin_control.html
+++ b/chrome/browser/resources/print_preview/ui/margin_control.html
@@ -1,142 +1,14 @@
-<style include="cr-input-style">
-  :host {
-    display: block;
-    position: absolute;
-    transition: opacity 150ms linear;
-  }
-
-  :host([invisible]) {
-    opacity: 0;
-  }
-
-  :host([disabled]),
-  :host([invisible]) {
-    pointer-events: none;
-  }
-
-  :host([side=top]) #lineContainer,
-  :host([side=bottom]) #lineContainer {
-    cursor: ns-resize;
-    padding: 8px 0;
-    width: 100%;
-  }
-
-  :host([side=left]) #lineContainer,
-  :host([side=right]) #lineContainer {
-    cursor: ew-resize;
-    height: 100%;
-    padding: 0 8px;
-  }
-
-  #line {
-    border: 1px dashed var(--google-blue-500);
-  }
-
-  @media (prefers-color-scheme: dark) {
-    #line {
-      border-color: var(--google-blue-300);
-    }
-  }
-
-  :host([side=top]) #line,
-  :host([side=bottom]) #line {
-    width: 100%;
-  }
-
-  :host([side=left]) #line,
-  :host([side=right]) #line {
-    height: 100%;
-  }
-
-  #row-container {
-    border-radius: 4px;
-    font-size: 0.8rem;
-    min-height: 25px;
-    overflow: hidden;
-    padding: 1px;
-    position: absolute;
-  }
-
-  @media (prefers-color-scheme: light) {
-    #row-container {
-      --cr-input-background-color: var(--cr-primary-text-color);
-      --cr-input-color: white;
-      background-color: var(--cr-primary-text-color);
-      color: white;
-    }
-  }
-
-  @media (prefers-color-scheme: dark) {
-    #row-container {
-      --cr-input-background-color: rgb(27, 28, 30);  /* GG900 + 30% black */
-      --cr-input-color: var(--cr-primary-text-color);
-      background-color: rgb(27, 28, 30);  /* GG900 + 30% black */
-      color: var(--cr-primary-text-color);
-    }
-  }
-
-  :host([side=top]) #row-container {
-    left: 50%;
-    top: 9px;
-  }
-
-  :host([side=right]) #row-container {
-    right: 9px;
-    top: 50%;
-  }
-
-  :host([side=bottom]) #row-container {
-    bottom: 9px;
-    right: 50%;
-  }
-
-  :host([side=left]) #row-container {
-    bottom: 50%;
-    left: 9px;
-  }
-
-  :host([disabled]) #row-container {
-    opacity: var(--cr-disabled-opacity);
-  }
-
-  :host([invalid]) #input {
-    caret-color: var(--cr-input-error-color);
-  }
-
-  :host([invalid]) #underline {
-    border-color: var(--cr-input-error-color);
-  }
-
-  #row-container,
-  #input-container {
-    align-items: center;
-    display: flex;
-  }
-
-  #input-container {
-    position: relative;
-  }
-
-  #input {
-    padding-inline-end: 0;
-    text-align: end;
-    width: 44px;
-  }
-
-  #unit {
-    padding-inline-end: 8px;
-  }
-</style>
-  <div id="lineContainer">
-    <div id="line"></div>
+<div id="lineContainer">
+  <div id="line"></div>
+</div>
+<div id="row-container">
+  <div id="input-container">
+    <input id="input" ?disabled="${this.disabled}"
+        aria-label="${this.i18n(this.side)}"
+        aria-hidden="${this.getAriaHidden_()}"
+        @focus="${this.onFocus_}" @blur="${this.onBlur_}"
+        data-timeout-delay="1000">
+    <span id="unit">${this.measurementSystem?.unitSymbol || ''}</span>
   </div>
-  <div id="row-container">
-    <div id="input-container">
-      <input id="input" disabled="[[disabled]]" aria-label$="[[i18n(side)]]"
-          aria-hidden$="[[getAriaHidden_(invisible)]]"
-          on-focus="onFocus_" on-blur="onBlur_" data-timeout-delay="1000">
-      <span id="unit">[[measurementSystem.unitSymbol]]</span>
-    </div>
-    <div id="underline"></div>
-  </div>
+  <div id="underline"></div>
 </div>
diff --git a/chrome/browser/resources/print_preview/ui/margin_control.ts b/chrome/browser/resources/print_preview/ui/margin_control.ts
index cdf645ec..92f15cc 100644
--- a/chrome/browser/resources/print_preview/ui/margin_control.ts
+++ b/chrome/browser/resources/print_preview/ui/margin_control.ts
@@ -2,23 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'chrome://resources/cr_elements/cr_shared_vars.css.js';
-import 'chrome://resources/cr_elements/cr_input/cr_input_style.css.js';
 import '/strings.m.js';
 
-import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
-import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
+import {I18nMixinLit} from 'chrome://resources/cr_elements/i18n_mixin_lit.js';
+import {WebUiListenerMixinLit} from 'chrome://resources/cr_elements/web_ui_listener_mixin_lit.js';
 import {assert} from 'chrome://resources/js/assert.js';
-import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
+import type {PropertyValues} from 'chrome://resources/lit/v3_0/lit.rollup.js';
 
 import type {Coordinate2d} from '../data/coordinate2d.js';
 import {CustomMarginsOrientation} from '../data/margins.js';
 import type {MeasurementSystem} from '../data/measurement_system.js';
 import type {Size} from '../data/size.js';
-import {observerDepsDefined} from '../print_preview_utils.js';
 
-import {InputMixin} from './input_mixin.js';
-import {getTemplate} from './margin_control.html.js';
+import {InputMixinLit} from './input_mixin_lit.js';
+import {getCss} from './margin_control.css.js';
+import {getHtml} from './margin_control.html.js';
 
 /**
  * Radius of the margin control in pixels. Padding of control + 1 for border.
@@ -34,7 +33,7 @@
 }
 
 const PrintPreviewMarginControlElementBase =
-    I18nMixin(WebUiListenerMixin(InputMixin(PolymerElement)));
+    I18nMixinLit(WebUiListenerMixinLit(InputMixinLit(CrLitElement)));
 
 export class PrintPreviewMarginControlElement extends
     PrintPreviewMarginControlElementBase {
@@ -42,94 +41,94 @@
     return 'print-preview-margin-control';
   }
 
-  static get template() {
-    return getTemplate();
+  static override get styles() {
+    return getCss();
   }
 
-  static get properties() {
+  override render() {
+    return getHtml.bind(this)();
+  }
+
+  static override get properties() {
     return {
       disabled: {
         type: Boolean,
-        reflectToAttribute: true,
-        observer: 'onDisabledChange_',
+        reflect: true,
       },
 
       side: {
         type: String,
-        reflectToAttribute: true,
+        reflect: true,
       },
 
       invalid: {
         type: Boolean,
-        reflectToAttribute: true,
+        reflect: true,
       },
 
       invisible: {
         type: Boolean,
-        reflectToAttribute: true,
-        observer: 'onClipSizeChange_',
+        reflect: true,
       },
 
-      measurementSystem: Object,
+      measurementSystem: {type: Object},
 
       focused_: {
         type: Boolean,
-        reflectToAttribute: true,
-        value: false,
+        reflect: true,
       },
 
-      positionInPts_: {
-        type: Number,
-        notify: true,
-        value: 0,
-      },
-
-      scaleTransform: {
-        type: Number,
-        notify: true,
-      },
-
-      translateTransform: {
-        type: Object,
-        notify: true,
-      },
-
-      pageSize: {
-        type: Object,
-        notify: true,
-      },
-
-      clipSize: {
-        type: Object,
-        notify: true,
-        observer: 'onClipSizeChange_',
-      },
+      positionInPts_: {type: Number},
+      scaleTransform: {type: Number},
+      translateTransform: {type: Object},
+      pageSize: {type: Object},
+      clipSize: {type: Object},
     };
   }
 
-  declare disabled: boolean;
-  declare side: CustomMarginsOrientation;
-  declare invalid: boolean;
-  declare invisible: boolean;
-  declare measurementSystem: MeasurementSystem|null;
-  declare scaleTransform: number;
-  declare translateTransform: Coordinate2d;
-  declare pageSize: Size;
-  declare clipSize: Size|null;
+  accessor disabled: boolean;
+  accessor side: CustomMarginsOrientation;
+  accessor invalid: boolean;
+  accessor invisible: boolean;
+  accessor measurementSystem: MeasurementSystem|null;
+  accessor scaleTransform: number;
+  accessor translateTransform: Coordinate2d;
+  accessor pageSize: Size;
+  accessor clipSize: Size|null;
 
-  declare private focused_: boolean;
-  declare private positionInPts_: number;
+  private accessor focused_: boolean = false;
+  private accessor positionInPts_: number = 0;
 
-  static get observers() {
-    return [
-      'updatePosition_(positionInPts_, scaleTransform, translateTransform, ' +
-          'pageSize, side)',
-    ];
+  override willUpdate(changedProperties: PropertyValues<this>) {
+    super.willUpdate(changedProperties);
+
+    if (changedProperties.has('disabled')) {
+      if (this.disabled) {
+        this.focused_ = false;
+      }
+    }
   }
 
-  override ready() {
-    super.ready();
+  override updated(changedProperties: PropertyValues<this>) {
+    super.updated(changedProperties);
 
+    const changedPrivateProperties =
+        changedProperties as Map<PropertyKey, unknown>;
+
+    if (changedProperties.has('clipSize') ||
+        changedProperties.has('invisible')) {
+      this.onClipSizeChange_();
+    }
+
+    if (changedPrivateProperties.has('positionInPts_') ||
+        changedProperties.has('scaleTransform') ||
+        changedProperties.has('translateTransform') ||
+        changedProperties.has('pageSize') || changedProperties.has('side')) {
+      this.updatePosition_();
+    }
+  }
+
+  override firstUpdated() {
     this.addEventListener('input-change', e => this.onInputChange_(e));
   }
 
@@ -169,7 +168,7 @@
    * @return 'true' or 'false', indicating whether the input should be
    *     aria-hidden.
    */
-  private getAriaHidden_(): string {
+  protected getAriaHidden_(): string {
     return this.invisible.toString();
   }
 
@@ -210,12 +209,6 @@
          event.composedPath()[0] === this.$.line);
   }
 
-  private onDisabledChange_() {
-    if (this.disabled) {
-      this.focused_ = false;
-    }
-  }
-
   /**
    * @param value Value to parse to points. E.g. '3.40' or '200'.
    * @return Value in points represented by the input value.
@@ -278,19 +271,20 @@
     this.fire_('text-change', value);
   }
 
-  private onBlur_() {
+  protected onBlur_() {
     this.focused_ = false;
     this.resetAndUpdate();
     this.fire_('text-blur', this.invalid || !this.$.input.value);
   }
 
-  private onFocus_() {
+  protected onFocus_() {
     this.focused_ = true;
     this.fire_('text-focus');
   }
 
   private updatePosition_() {
-    if (!observerDepsDefined(Array.from(arguments))) {
+    if (!this.translateTransform || !this.scaleTransform ||
+        !this.measurementSystem) {
       return;
     }
 
@@ -343,6 +337,8 @@
   }
 }
 
+export type MarginControlElement = PrintPreviewMarginControlElement;
+
 declare global {
   interface HTMLElementTagNameMap {
     'print-preview-margin-control': PrintPreviewMarginControlElement;
diff --git a/chrome/browser/resources/print_preview/ui/margin_control_container.css b/chrome/browser/resources/print_preview/ui/margin_control_container.css
new file mode 100644
index 0000000..f79b734
--- /dev/null
+++ b/chrome/browser/resources/print_preview/ui/margin_control_container.css
@@ -0,0 +1,22 @@
+/* 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. */
+
+/* #css_wrapper_metadata_start
+ * #type=style-lit
+ * #css_wrapper_metadata_end */
+
+:host {
+  display: block;
+  left: 0;
+  position: absolute;
+  top: 0;
+}
+
+:host([dragging_=dragging-vertical]) {
+  cursor: ns-resize;
+}
+
+:host([dragging_=dragging-horizontal]) {
+  cursor: ew-resize;
+}
diff --git a/chrome/browser/resources/print_preview/ui/margin_control_container.html b/chrome/browser/resources/print_preview/ui/margin_control_container.html
index 09f1d496..950be26 100644
--- a/chrome/browser/resources/print_preview/ui/margin_control_container.html
+++ b/chrome/browser/resources/print_preview/ui/margin_control_container.html
@@ -1,29 +1,14 @@
-<style>
-  :host {
-    display: block;
-    left: 0;
-    position: absolute;
-    top: 0;
-  }
-
-  :host([dragging_=dragging-vertical]) {
-    cursor: ns-resize;
-  }
-
-  :host([dragging_=dragging-horizontal]) {
-    cursor: ew-resize;
-  }
-</style>
-<template is="dom-repeat" items="[[marginSides_]]">
-  <print-preview-margin-control side="[[item]]" invisible="[[invisible_]]"
-      disabled="[[controlsDisabled_(state, invisible_)]]"
-      translate-transform="[[translateTransform_]]"
-      clip-size="[[clipSize_]]"
-      measurement-system="[[measurementSystem]]"
-      scale-transform="[[scaleTransform_]]"
-      page-size="[[pageSize]]"
-      on-pointerdown="onPointerDown_"
-      on-text-change="onTextChange_" on-text-blur="onTextBlur_"
-      on-text-focus="onTextFocus_" on-transition-end="onTransitionEnd_">
+${this.marginSides_.map(item => html`
+  <print-preview-margin-control side="${item}" ?invisible="${this.invisible_}"
+      ?disabled="${this.controlsDisabled_()}"
+      .translateTransform="${this.translateTransform_}"
+      .clipSize="${this.clipSize_}"
+      .measurementSystem="${this.measurementSystem}"
+      .scaleTransform="${this.scaleTransform_}"
+      .pageSize="${this.pageSize}"
+      @pointerdown="${this.onPointerDown_}"
+      @text-change="${this.onTextChange_}" @text-blur="${this.onTextBlur_}"
+      @text-focus="${this.onTextFocus_}"
+      @transition-end="${this.onTransitionEnd_}">
   </print-preview-margin-control>
-</template>
+`)}
diff --git a/chrome/browser/resources/print_preview/ui/margin_control_container.ts b/chrome/browser/resources/print_preview/ui/margin_control_container.ts
index 27f287a..52dff04 100644
--- a/chrome/browser/resources/print_preview/ui/margin_control_container.ts
+++ b/chrome/browser/resources/print_preview/ui/margin_control_container.ts
@@ -6,18 +6,20 @@
 
 import {assert} from 'chrome://resources/js/assert.js';
 import {EventTracker} from 'chrome://resources/js/event_tracker.js';
-import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
+import type {PropertyValues} from 'chrome://resources/lit/v3_0/lit.rollup.js';
 
 import {Coordinate2d} from '../data/coordinate2d.js';
 import type {Margins, MarginsSetting} from '../data/margins.js';
 import {CustomMarginsOrientation, MarginsType} from '../data/margins.js';
 import type {MeasurementSystem} from '../data/measurement_system.js';
-import type {Size} from '../data/size.js';
+import {Size} from '../data/size.js';
 import {State} from '../data/state.js';
 
 import type {PrintPreviewMarginControlElement} from './margin_control.js';
-import {getTemplate} from './margin_control_container.html.js';
-import {SettingsMixin} from './settings_mixin.js';
+import {getCss} from './margin_control_container.css.js';
+import {getHtml} from './margin_control_container.html.js';
+import {SettingsMixinLit} from './settings_mixin_lit.js';
 
 export const MARGIN_KEY_MAP:
     Map<CustomMarginsOrientation, keyof MarginsSetting> = new Map([
@@ -31,7 +33,7 @@
 
 
 const PrintPreviewMarginControlContainerElementBase =
-    SettingsMixin(PolymerElement);
+    SettingsMixinLit(CrLitElement);
 
 export class PrintPreviewMarginControlContainerElement extends
     PrintPreviewMarginControlContainerElementBase {
@@ -39,72 +41,27 @@
     return 'print-preview-margin-control-container';
   }
 
-  static get template() {
-    return getTemplate();
+  static override get styles() {
+    return getCss();
   }
 
-  static get properties() {
+  override render() {
+    return getHtml.bind(this)();
+  }
+
+  static override get properties() {
     return {
-      pageSize: {
-        type: Object,
-        notify: true,
-      },
-
-      documentMargins: {
-        type: Object,
-        notify: true,
-      },
-
-      previewLoaded: Boolean,
-
-      measurementSystem: Object,
-
-      state: {
-        type: Number,
-        observer: 'onStateChanged_',
-      },
-
-      scaleTransform_: {
-        type: Number,
-        notify: true,
-        value: 0,
-      },
-
-      translateTransform_: {
-        type: Object,
-        notify: true,
-        value: new Coordinate2d(0, 0),
-      },
-
-      clipSize_: {
-        type: Object,
-        notify: true,
-        value: null,
-      },
-
-      available_: {
-        type: Boolean,
-        notify: true,
-        computed: 'computeAvailable_(previewLoaded, settings.margins.value)',
-        observer: 'onAvailableChange_',
-      },
-
-      invisible_: {
-        type: Boolean,
-        reflectToAttribute: true,
-        value: true,
-      },
-
-      marginSides_: {
-        type: Array,
-        notify: true,
-        value: [
-          CustomMarginsOrientation.TOP,
-          CustomMarginsOrientation.RIGHT,
-          CustomMarginsOrientation.BOTTOM,
-          CustomMarginsOrientation.LEFT,
-        ],
-      },
+      pageSize: {type: Object},
+      documentMargins: {type: Object},
+      previewLoaded: {type: Boolean},
+      measurementSystem: {type: Object},
+      state: {type: Number},
+      scaleTransform_: {type: Number},
+      translateTransform_: {type: Object},
+      clipSize_: {type: Object},
+      available_: {type: Boolean},
+      invisible_: {type: Boolean},
+      marginSides_: {type: Array},
 
       /**
        * String attribute used to set cursor appearance. Possible values:
@@ -114,42 +71,72 @@
        */
       dragging_: {
         type: String,
-        reflectToAttribute: true,
-        value: '',
+        reflect: true,
       },
     };
   }
 
-  static get observers() {
-    return [
-      'onMarginSettingsChange_(settings.customMargins.value)',
-      'onMediaSizeOrLayoutChange_(' +
-          'settings.mediaSize.value, settings.layout.value)',
-
-    ];
-  }
-
-  declare pageSize: Size;
-  declare documentMargins: Margins;
-  declare previewLoaded: boolean;
-  declare measurementSystem: MeasurementSystem|null;
-  declare state: State;
-  declare private available_: boolean;
-  declare private invisible_: boolean;
-  declare private clipSize_: Size;
-  declare private scaleTransform_: number;
-  declare private translateTransform_: Coordinate2d;
-  declare private dragging_: string;
-  declare private marginSides_: CustomMarginsOrientation[];
-
+  accessor pageSize: Size;
+  accessor documentMargins: Margins;
+  accessor previewLoaded: boolean;
+  accessor measurementSystem: MeasurementSystem|null;
+  accessor state: State;
+  private accessor available_: boolean;
+  protected accessor invisible_: boolean = true;
+  protected accessor clipSize_: Size = new Size(0, 0);
+  protected accessor scaleTransform_: number = 0;
+  protected accessor translateTransform_: Coordinate2d = new Coordinate2d(0, 0);
+  private accessor dragging_: ''|'dragging-horizontal'|'dragging-vertical' = '';
+  protected accessor marginSides_: CustomMarginsOrientation[] = [
+    CustomMarginsOrientation.TOP,
+    CustomMarginsOrientation.RIGHT,
+    CustomMarginsOrientation.BOTTOM,
+    CustomMarginsOrientation.LEFT,
+  ];
   private pointerStartPositionInPixels_: Coordinate2d = new Coordinate2d(0, 0);
   private marginStartPositionInPixels_: Coordinate2d|null = null;
   private resetMargins_: boolean|null = null;
   private eventTracker_: EventTracker = new EventTracker();
   private textboxFocused_: boolean = false;
 
+  override connectedCallback() {
+    super.connectedCallback();
+
+    this.addSettingObserver(
+        'customMargins.value', this.onMarginSettingsChange_.bind(this));
+    this.onMarginSettingsChange_();
+
+    this.addSettingObserver(
+        'mediaSize.value', this.onMediaSizeOrLayoutChange_.bind(this));
+    this.addSettingObserver(
+        'layout.value', this.onMediaSizeOrLayoutChange_.bind(this));
+
+    this.addSettingObserver('margins.value', () => {
+      this.available_ = this.computeAvailable_();
+    });
+  }
+
+  override willUpdate(changedProperties: PropertyValues<this>) {
+    super.willUpdate(changedProperties);
+
+    const changedPrivateProperties =
+        changedProperties as Map<PropertyKey, unknown>;
+
+    if (changedProperties.has('state')) {
+      this.onStateChanged_();
+    }
+
+    if (changedProperties.has('previewLoaded')) {
+      this.available_ = this.computeAvailable_();
+    }
+
+    if (changedPrivateProperties.has('available_')) {
+      this.onAvailableChange_();
+    }
+  }
+
   private computeAvailable_(): boolean {
-    return this.previewLoaded && !!this.clipSize_ &&
+    return this.previewLoaded &&
         ((this.getSettingValue('margins') as MarginsType) ===
          MarginsType.CUSTOM) &&
         !!this.pageSize;
@@ -177,7 +164,7 @@
       // settings. It sets custom margins empty by default.
       return;
     }
-    this.shadowRoot!.querySelectorAll('print-preview-margin-control')
+    this.shadowRoot.querySelectorAll('print-preview-margin-control')
         .forEach(control => {
           const key = MARGIN_KEY_MAP.get(control.side)!;
           const newValue = margins[key] || 0;
@@ -211,7 +198,7 @@
   /**
    * @return Whether the controls should be disabled.
    */
-  private controlsDisabled_(): boolean {
+  protected controlsDisabled_(): boolean {
     return this.state !== State.READY || this.invisible_;
   }
 
@@ -297,7 +284,6 @@
     const posInPts = this.posInPixelsToPts_(control, posInPixels);
     this.moveControlWithConstraints_(control, posInPts);
     this.setMargin_(control.side, posInPts);
-    this.updateClippingMask(this.clipSize_);
     this.eventTracker_.remove(control, 'pointercancel');
     this.eventTracker_.remove(control, 'pointerup');
     this.eventTracker_.remove(control, 'pointermove');
@@ -326,7 +312,7 @@
   /**
    * @param e Contains information about what control fired the event.
    */
-  private onTextFocus_(e: Event) {
+  protected onTextFocus_(e: Event) {
     this.textboxFocused_ = true;
     const control = e.target as PrintPreviewMarginControlElement;
 
@@ -417,7 +403,7 @@
   /**
    * @param e Event containing the new textbox value.
    */
-  private onTextChange_(e: CustomEvent<number>) {
+  protected onTextChange_(e: CustomEvent<number>) {
     const control = e.target as PrintPreviewMarginControlElement;
     control.invalid = false;
     const clippedValue = this.clipAndRoundValue_(control.side, e.detail);
@@ -429,7 +415,7 @@
    * @param e Event fired when a control's text field is blurred. Contains
    *     information about whether the control is in an invalid state.
    */
-  private onTextBlur_(e: CustomEvent<boolean>) {
+  protected onTextBlur_(e: CustomEvent<boolean>) {
     const control = e.target as PrintPreviewMarginControlElement;
     control.setTextboxValue(control.getPositionInPts());
     if (e.detail /* detail is true if the control is in an invalid state */) {
@@ -441,7 +427,7 @@
   /**
    * @param e Fired when pointerdown occurs on a margin control.
    */
-  private onPointerDown_(e: PointerEvent) {
+  protected onPointerDown_(e: PointerEvent) {
     const control = e.target as PrintPreviewMarginControlElement;
     if (!control.shouldDrag(e)) {
       return;
@@ -475,7 +461,7 @@
   /**
    * Set display:none after the opacity transition for the controls is done.
    */
-  private onTransitionEnd_() {
+  protected onTransitionEnd_() {
     if (this.invisible_) {
       this.style.display = 'none';
     }
@@ -507,14 +493,13 @@
    * @param clipSize Size to clip the margin controls to.
    */
   updateClippingMask(clipSize: Size) {
-    if (!clipSize) {
-      return;
-    }
     this.clipSize_ = clipSize;
-    this.notifyPath('clipSize_');
   }
 }
 
+export type MarginControlContainerElement =
+    PrintPreviewMarginControlContainerElement;
+
 declare global {
   interface HTMLElementTagNameMap {
     'print-preview-margin-control-container':
diff --git a/chrome/browser/resources/side_panel/read_anything/read_anything_logger.ts b/chrome/browser/resources/side_panel/read_anything/read_anything_logger.ts
index 77a094f..ea433357 100644
--- a/chrome/browser/resources/side_panel/read_anything/read_anything_logger.ts
+++ b/chrome/browser/resources/side_panel/read_anything/read_anything_logger.ts
@@ -112,7 +112,7 @@
       return;
     }
 
-    // See tools/metrics/histograms/enums.xml enum LocaleCodeISO639. The enum
+    // See tools/metrics/histograms/enums.xml enum LocaleCodeBCP47. The enum
     // there doesn't always have locales where the base lang and the locale
     // are the same (e.g. they don't have id-id, but do have id). So if the
     // base lang and the locale are the same, just use the base lang.
diff --git a/chrome/browser/safe_browsing/android/BUILD.gn b/chrome/browser/safe_browsing/android/BUILD.gn
index 1893aadb..58fd64ba 100644
--- a/chrome/browser/safe_browsing/android/BUILD.gn
+++ b/chrome/browser/safe_browsing/android/BUILD.gn
@@ -95,6 +95,7 @@
     "//chrome/browser/feedback/android:java",
     "//chrome/browser/flags:java",
     "//chrome/browser/preferences:java",
+    "//chrome/browser/privacy:privacy_settings_java",
     "//chrome/browser/profiles/android:java",
     "//chrome/browser/settings:java",
     "//components/browser_ui/modaldialog/android:java",
@@ -188,6 +189,7 @@
     "//components/permissions/android:core_java",
     "//components/permissions/android:java",
     "//third_party/androidx:androidx_annotation_annotation_java",
+    "//third_party/androidx:androidx_fragment_fragment_java",
     "//third_party/junit",
     "//third_party/mockito:mockito_java",
     "//ui/android:ui_java",
diff --git a/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionCoordinator.java b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionCoordinator.java
index d4136706..68ed8e56 100644
--- a/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionCoordinator.java
+++ b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionCoordinator.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.safe_browsing;
 
+import androidx.fragment.app.Fragment;
+
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.ui.base.WindowAndroid;
 
@@ -12,8 +14,9 @@
 public class AdvancedProtectionCoordinator {
     private AdvancedProtectionMediator mMediator;
 
-    public AdvancedProtectionCoordinator(WindowAndroid windowAndroid) {
-        mMediator = new AdvancedProtectionMediator(windowAndroid);
+    public AdvancedProtectionCoordinator(
+            WindowAndroid windowAndroid, Class<? extends Fragment> privacySettingsFragmentClass) {
+        mMediator = new AdvancedProtectionMediator(windowAndroid, privacySettingsFragmentClass);
     }
 
     public void destroy() {
diff --git a/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediator.java b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediator.java
index 4872fdc..f06b569 100644
--- a/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediator.java
+++ b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediator.java
@@ -6,10 +6,16 @@
 
 import static org.chromium.build.NullUtil.assumeNonNull;
 
+import android.os.Bundle;
+
+import androidx.fragment.app.Fragment;
+
 import org.chromium.base.shared_preferences.SharedPreferencesManager;
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
+import org.chromium.chrome.browser.privacy.settings.PrivacySettingsNavigation;
+import org.chromium.chrome.browser.settings.SettingsNavigationFactory;
 import org.chromium.components.messages.MessageDispatcher;
 import org.chromium.components.messages.MessageDispatcherProvider;
 import org.chromium.components.permissions.OsAdditionalSecurityPermissionProvider;
@@ -20,10 +26,13 @@
 @NullMarked
 public class AdvancedProtectionMediator implements OsAdditionalSecurityPermissionProvider.Observer {
     private WindowAndroid mWindowAndroid;
+    private Class<? extends Fragment> mPrivacySettingsFragmentClass;
     private boolean mShouldShowMessageOnStartup;
 
-    public AdvancedProtectionMediator(WindowAndroid windowAndroid) {
+    public AdvancedProtectionMediator(
+            WindowAndroid windowAndroid, Class<? extends Fragment> privacySettingsFragmentClass) {
         mWindowAndroid = windowAndroid;
+        mPrivacySettingsFragmentClass = privacySettingsFragmentClass;
 
         var provider = OsAdditionalSecurityPermissionUtil.getProviderInstance();
         if (provider != null) {
@@ -72,9 +81,18 @@
 
     private void enqueueMessage(OsAdditionalSecurityPermissionProvider provider) {
         var context = assumeNonNull(mWindowAndroid.getContext().get());
+        Runnable buttonHandler =
+                () -> {
+                    Bundle args = new Bundle();
+                    args.putBoolean(
+                            PrivacySettingsNavigation.EXTRA_FOCUS_ADVANCED_PROTECTION_SECTION,
+                            true);
+                    SettingsNavigationFactory.createSettingsNavigation()
+                            .startSettings(context, mPrivacySettingsFragmentClass, args);
+                };
         var propertyModel =
                 provider.buildAdvancedProtectionMessagePropertyModel(
-                        context, /* primaryButtonAction= */ null);
+                        context, /* primaryButtonAction= */ buttonHandler);
         if (propertyModel == null) {
             return;
         }
diff --git a/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediatorTest.java b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediatorTest.java
index d0ae2c24..916c5f1 100644
--- a/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediatorTest.java
+++ b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/AdvancedProtectionMediatorTest.java
@@ -15,6 +15,8 @@
 
 import android.content.Context;
 
+import androidx.fragment.app.Fragment;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -55,6 +57,8 @@
 
     @Mock private ManagedMessageDispatcher mMessageDispatcher;
 
+    private static class TestFragment extends Fragment {}
+
     private static class TestPermissionProvider extends OsAdditionalSecurityPermissionProvider {
         private boolean mIsAdvancedProtectionRequestedByOs;
         private Observer mObserver;
@@ -126,7 +130,7 @@
     public void testDontShowMessageNoPrefAdvancedProtectionOff() {
         setPermissionProvider(/* isAdvancedProtectionRequestedByOs= */ false);
 
-        var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid);
+        var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid, TestFragment.class);
         coordinator.showMessageOnStartupIfNeeded();
         verifyDidNotEnqueueMessage();
 
@@ -141,7 +145,7 @@
     public void testShowMessageNoPrefAdvancedProtectionOn() {
         setPermissionProvider(/* isAdvancedProtectionRequestedByOs= */ true);
 
-        var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid);
+        var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid, TestFragment.class);
         coordinator.showMessageOnStartupIfNeeded();
         verifyEnqueuedMessage();
 
@@ -159,7 +163,7 @@
                 .writeBoolean(ChromePreferenceKeys.OS_ADVANCED_PROTECTION_SETTING, true);
         setPermissionProvider(/* isAdvancedProtectionRequestedByOs= */ true);
 
-        var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid);
+        var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid, TestFragment.class);
         coordinator.showMessageOnStartupIfNeeded();
         verifyDidNotEnqueueMessage();
 
@@ -176,7 +180,7 @@
         sharedPreferences.writeBoolean(ChromePreferenceKeys.OS_ADVANCED_PROTECTION_SETTING, true);
         setPermissionProvider(/* isAdvancedProtectionRequestedByOs= */ false);
 
-        var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid);
+        var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid, TestFragment.class);
         coordinator.showMessageOnStartupIfNeeded();
         verifyDidNotEnqueueMessage();
 
@@ -198,7 +202,7 @@
         sharedPreferences.writeBoolean(ChromePreferenceKeys.OS_ADVANCED_PROTECTION_SETTING, false);
         setPermissionProvider(/* isAdvancedProtectionRequestedByOs= */ true);
 
-        var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid);
+        var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid, TestFragment.class);
         coordinator.showMessageOnStartupIfNeeded();
         verifyEnqueuedMessage();
 
@@ -219,7 +223,7 @@
         sharedPreferences.writeBoolean(ChromePreferenceKeys.OS_ADVANCED_PROTECTION_SETTING, true);
         var provider = setPermissionProvider(/* isAdvancedProtectionRequestedByOs= */ false);
 
-        var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid);
+        var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid, TestFragment.class);
         coordinator.showMessageOnStartupIfNeeded();
         verifyDidNotEnqueueMessage();
         provider.setAdvancedProtectionRequestedByOs(/* isAdvancedProtectionRequestedByOs= */ true);
@@ -236,7 +240,7 @@
         sharedPreferences.writeBoolean(ChromePreferenceKeys.OS_ADVANCED_PROTECTION_SETTING, true);
         var provider = setPermissionProvider(/* isAdvancedProtectionRequestedByOs= */ false);
 
-        var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid);
+        var coordinator = new AdvancedProtectionCoordinator(mWindowAndroid, TestFragment.class);
         coordinator.showMessageOnStartupIfNeeded();
         verifyDidNotEnqueueMessage();
         provider.setAdvancedProtectionRequestedByOs(/* isAdvancedProtectionRequestedByOs= */ true);
@@ -260,7 +264,7 @@
                 yesterdayTimestamp);
         setPermissionProvider(/* isAdvancedProtectionRequestedByOs= */ false);
 
-        new AdvancedProtectionCoordinator(mWindowAndroid);
+        new AdvancedProtectionCoordinator(mWindowAndroid, TestFragment.class);
         assertTrue(
                 yesterdayTimestamp
                         < sharedPreferences.readLong(
@@ -283,7 +287,7 @@
                 yesterdayTimestamp);
         setPermissionProvider(/* isAdvancedProtectionRequestedByOs= */ true);
 
-        new AdvancedProtectionCoordinator(mWindowAndroid);
+        new AdvancedProtectionCoordinator(mWindowAndroid, TestFragment.class);
         assertEquals(
                 yesterdayTimestamp,
                 sharedPreferences.readLong(
@@ -303,7 +307,7 @@
                 ChromePreferenceKeys.OS_ADVANCED_PROTECTION_SETTING_UPDATED_TIME);
         setPermissionProvider(/* isAdvancedProtectionRequestedByOs= */ true);
 
-        new AdvancedProtectionCoordinator(mWindowAndroid);
+        new AdvancedProtectionCoordinator(mWindowAndroid, TestFragment.class);
         assertTrue(
                 sharedPreferences.readBoolean(
                         ChromePreferenceKeys.OS_ADVANCED_PROTECTION_SETTING, false));
diff --git a/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtils.java b/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtils.java
index 0507a386..6f882ca 100644
--- a/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtils.java
+++ b/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/SurfaceColorUpdateUtils.java
@@ -94,6 +94,7 @@
      */
     public static @ColorInt int getGridTabSwitcherBackgroundColor(
             Context context, boolean isIncognito) {
+        // TODO(crbug.com/414404094): Add semantic color for incognito.
         if (ChromeFeatureList.sGridTabSwitcherSurfaceColorUpdate.isEnabled()) {
             return isIncognito
                     ? ContextCompat.getColor(
diff --git a/chrome/browser/ui/android/toolbar/BUILD.gn b/chrome/browser/ui/android/toolbar/BUILD.gn
index beb996c..2bfb4248 100644
--- a/chrome/browser/ui/android/toolbar/BUILD.gn
+++ b/chrome/browser/ui/android/toolbar/BUILD.gn
@@ -301,6 +301,10 @@
     "java/res/drawable/menu_bg_bottom_tinted.xml",
     "java/res/drawable/modern_toolbar_text_box_background_with_primary_color.xml",
     "java/res/drawable/new_tab_icon.xml",
+    "java/res/drawable/optional_button_background.xml",
+    "java/res/drawable/optional_button_background_baseline.xml",
+    "java/res/drawable/optional_button_background_selector.xml",
+    "java/res/drawable/optional_button_background_selector_baseline.xml",
     "java/res/drawable/toolbar_menu_button_ripple.xml",
     "java/res/drawable/toolbar_on_bottom.xml",
     "java/res/drawable/toolbar_on_top.xml",
diff --git a/chrome/browser/ui/android/toolbar/java/res/drawable/optional_button_background.xml b/chrome/browser/ui/android/toolbar/java/res/drawable/optional_button_background.xml
new file mode 100644
index 0000000..34871d1
--- /dev/null
+++ b/chrome/browser/ui/android/toolbar/java/res/drawable/optional_button_background.xml
@@ -0,0 +1,17 @@
+<?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.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="?android:attr/colorControlHighlight">
+    <item
+        android:id="@android:id/content"
+        android:height="@dimen/modern_toolbar_background_size"
+        android:left="@dimen/toolbar_phone_optional_button_background_padding"
+        android:right="@dimen/toolbar_phone_optional_button_background_padding"
+        android:gravity="center"
+        android:drawable="@drawable/optional_button_background_selector" />
+</ripple>
diff --git a/chrome/browser/ui/android/toolbar/java/res/drawable/optional_button_background_baseline.xml b/chrome/browser/ui/android/toolbar/java/res/drawable/optional_button_background_baseline.xml
new file mode 100644
index 0000000..688cc58
--- /dev/null
+++ b/chrome/browser/ui/android/toolbar/java/res/drawable/optional_button_background_baseline.xml
@@ -0,0 +1,17 @@
+<?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.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="?android:attr/colorControlHighlight">
+    <item
+        android:id="@android:id/content"
+        android:height="@dimen/modern_toolbar_background_size"
+        android:left="@dimen/toolbar_phone_optional_button_background_padding"
+        android:right="@dimen/toolbar_phone_optional_button_background_padding"
+        android:gravity="center"
+        android:drawable="@drawable/optional_button_background_selector_baseline" />
+</ripple>
diff --git a/chrome/browser/ui/android/toolbar/java/res/drawable/optional_button_background_selector.xml b/chrome/browser/ui/android/toolbar/java/res/drawable/optional_button_background_selector.xml
new file mode 100644
index 0000000..77de80f
--- /dev/null
+++ b/chrome/browser/ui/android/toolbar/java/res/drawable/optional_button_background_selector.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_hovered="true">
+        <shape android:shape="rectangle">
+            <solid android:color="@color/color_on_surface_with_alpha_8" />
+            <corners android:radius="@dimen/modern_toolbar_background_corner_radius"/>
+        </shape>
+    </item>
+    <item android:state_focused="true">
+        <shape android:shape="rectangle">
+            <solid android:color="@android:color/transparent" />
+            <stroke
+                android:color="@macro/default_control_color_active"
+                android:width="@dimen/focused_icon_background_stroke_width" />
+            <corners android:radius="@dimen/modern_toolbar_background_corner_radius"/>
+        </shape>
+    </item>
+    <item android:state_pressed="true">
+        <shape android:shape="rectangle">
+            <solid android:color="@color/color_on_surface_with_alpha_12" />
+            <corners android:radius="@dimen/modern_toolbar_background_corner_radius"/>
+        </shape>
+    </item>
+    <item>
+        <shape android:shape="rectangle">
+            <solid android:color="@android:color/transparent" />
+            <corners android:radius="@dimen/modern_toolbar_background_corner_radius"/>
+        </shape>
+    </item>
+</selector>
diff --git a/chrome/browser/ui/android/toolbar/java/res/drawable/optional_button_background_selector_baseline.xml b/chrome/browser/ui/android/toolbar/java/res/drawable/optional_button_background_selector_baseline.xml
new file mode 100644
index 0000000..5990cd04
--- /dev/null
+++ b/chrome/browser/ui/android/toolbar/java/res/drawable/optional_button_background_selector_baseline.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_hovered="true">
+        <shape android:shape="rectangle">
+            <solid android:color="@color/baseline_neutral_90_alpha_8" />
+            <corners android:radius="@dimen/modern_toolbar_background_corner_radius"/>
+        </shape>
+    </item>
+    <item android:state_focused="true">
+        <shape android:shape="rectangle">
+            <solid android:color="@android:color/transparent" />
+            <stroke
+                android:color="@color/baseline_neutral_90"
+                android:width="@dimen/focused_icon_background_stroke_width" />
+            <corners android:radius="@dimen/modern_toolbar_background_corner_radius"/>
+        </shape>
+    </item>
+    <item android:state_pressed="true">
+        <shape android:shape="rectangle">
+            <solid android:color="@color/baseline_neutral_90_alpha_12" />
+            <corners android:radius="@dimen/modern_toolbar_background_corner_radius"/>
+        </shape>
+    </item>
+    <item>
+        <shape android:shape="rectangle">
+            <solid android:color="@android:color/transparent" />
+            <corners android:radius="@dimen/modern_toolbar_background_corner_radius"/>
+        </shape>
+    </item>
+</selector>
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/BaseButtonDataProvider.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/BaseButtonDataProvider.java
index 9826537a9..44ec4d5 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/BaseButtonDataProvider.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/BaseButtonDataProvider.java
@@ -45,11 +45,16 @@
      *     visible. Can be null to disable this behavior.
      * @param buttonDrawable Drawable for the button icon.
      * @param contentDescription String for the button's content description.
+     * @param actionChipLabelResId String for the button's action chip label, can be
+     *     Resources.ID_NULL is the button doesn't support action chip.
      * @param supportsTinting Whether the button's icon should be tinted.
      * @param iphCommandBuilder An IPH command builder instance to show when the button is
      *     displayed, can be null.
      * @param adaptiveButtonVariant Enum value of {@link AdaptiveToolbarButtonVariant}, used for
      *     metrics.
+     * @param tooltipTextResId String to show as a tooltip when the button is hovered over.
+     * @param showBackgroundHighlight Whether to use a custom background drawable to handle
+     *     highlight and focus UI states.
      */
     public BaseButtonDataProvider(
             Supplier<Tab> activeTabSupplier,
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonCoordinator.java
index 2b7be11..dafdac0f 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonCoordinator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/optional_button/OptionalButtonCoordinator.java
@@ -178,8 +178,8 @@
         if (buttonData != null) {
             buttonData.setBackgroundResource(
                     isIncognito
-                            ? R.drawable.default_icon_background_baseline
-                            : R.drawable.default_icon_background);
+                            ? R.drawable.optional_button_background_baseline
+                            : R.drawable.optional_button_background);
         }
         mMediator.updateButton(buttonData);
     }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
index 9782afc..0d6913a 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
@@ -742,7 +742,7 @@
                 RecordUserAction.record(reportingTagPrefix + "InNewBackgroundTab");
                 return mToolbarTabController.forwardInNewTab(/* foregroundNewTab= */ false);
             } else if (hasShift) {
-                RecordUserAction.record(reportingTagPrefix + "InNewWindow");
+                RecordUserAction.record(reportingTagPrefix + "InNewForegroundWindow");
                 return mToolbarTabController.forwardInNewWindow();
             } else {
                 RecordUserAction.record(reportingTagPrefix);
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
index a218033..ecc084b 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
@@ -485,7 +485,7 @@
 
         ButtonSpec buttonSpec = buttonData.getButtonSpec();
 
-        // Set hover highlight for profile, voice search, share and new tab button on tablets. Set
+        // Set hover highlight for buttons requesting a custom highlight. Set
         // box hover highlight for the rest of button variants.
         if (buttonData.getButtonSpec().shouldShowBackgroundHighlight()) {
             mOptionalButton.setBackgroundResource(
diff --git a/chrome/browser/ui/lens/BUILD.gn b/chrome/browser/ui/lens/BUILD.gn
index ba954fd..f72e3f8 100644
--- a/chrome/browser/ui/lens/BUILD.gn
+++ b/chrome/browser/ui/lens/BUILD.gn
@@ -38,13 +38,13 @@
     "lens_overlay_request_id_generator.h",
     "lens_overlay_side_panel_coordinator.h",
     "lens_overlay_side_panel_web_view.h",
-    "lens_searchbox_controller.h",
     "lens_overlay_theme_utils.h",
     "lens_overlay_translate_options.h",
     "lens_overlay_url_builder.h",
     "lens_permission_bubble_controller.h",
     "lens_preselection_bubble.h",
     "lens_search_contextualization_controller.h",
+    "lens_searchbox_controller.h",
     "page_content_type_conversions.h",
     "ref_counted_lens_overlay_client_logs.h",
   ]
@@ -65,6 +65,8 @@
     "//components/endpoint_fetcher",
     "//components/find_in_page",
     "//components/lens",
+    "//components/optimization_guide/content/browser",
+    "//components/optimization_guide/content/browser:page_context_eligibility",
     "//components/user_education/webui",
     "//content/public/browser",
     "//third_party/lens_server_proto:lens_overlay_proto",
@@ -92,7 +94,6 @@
     "lens_overlay_side_panel_coordinator.cc",
     "lens_overlay_side_panel_navigation_throttle.cc",
     "lens_overlay_side_panel_web_view.cc",
-    "lens_searchbox_controller.cc",
     "lens_overlay_theme_utils.cc",
     "lens_overlay_untrusted_ui.cc",
     "lens_overlay_url_builder.cc",
@@ -100,6 +101,7 @@
     "lens_preselection_bubble.cc",
     "lens_search_contextualization_controller.cc",
     "lens_search_controller.cc",
+    "lens_searchbox_controller.cc",
     "lens_side_panel_untrusted_ui.cc",
     "page_content_type_conversions.cc",
   ]
@@ -145,6 +147,7 @@
     "//components/lens/proto/server:proto",
     "//components/metrics_services_manager:metrics_services_manager",
     "//components/optimization_guide/content/browser",
+    "//components/optimization_guide/content/browser:page_context_eligibility",
     "//components/prefs",
     "//components/sessions",
     "//components/signin/public/identity_manager",
@@ -331,6 +334,7 @@
     "//components/base32",
     "//components/endpoint_fetcher",
     "//components/lens:features",
+    "//components/optimization_guide/content/browser:page_context_eligibility",
     "//content/public/browser",
     "//content/test:test_support",
     "//google_apis/common",
diff --git a/chrome/browser/ui/lens/lens_overlay_controller.cc b/chrome/browser/ui/lens/lens_overlay_controller.cc
index 3f82fa6..7960fbe 100644
--- a/chrome/browser/ui/lens/lens_overlay_controller.cc
+++ b/chrome/browser/ui/lens/lens_overlay_controller.cc
@@ -27,6 +27,7 @@
 #include "base/task/thread_pool.h"
 #include "chrome/browser/feedback/show_feedback_page.h"
 #include "chrome/browser/lens/core/mojom/geometry.mojom.h"
+#include "chrome/browser/lens/core/mojom/lens_side_panel.mojom.h"
 #include "chrome/browser/lens/core/mojom/overlay_object.mojom.h"
 #include "chrome/browser/lens/core/mojom/text.mojom.h"
 #include "chrome/browser/profiles/profile.h"
@@ -43,6 +44,7 @@
 #include "chrome/browser/ui/lens/lens_overlay_event_handler.h"
 #include "chrome/browser/ui/lens/lens_overlay_image_helper.h"
 #include "chrome/browser/ui/lens/lens_overlay_languages_controller.h"
+#include "chrome/browser/ui/lens/lens_overlay_proto_converter.h"
 #include "chrome/browser/ui/lens/lens_overlay_query_controller.h"
 #include "chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.h"
 #include "chrome/browser/ui/lens/lens_overlay_theme_utils.h"
@@ -73,9 +75,9 @@
 #include "components/lens/lens_overlay_metrics.h"
 #include "components/lens/lens_overlay_mime_type.h"
 #include "components/lens/lens_overlay_permission_utils.h"
-#include "components/lens/lens_overlay_side_panel_result.h"
 #include "components/omnibox/browser/lens_suggest_inputs_utils.h"
 #include "components/optimization_guide/content/browser/page_content_proto_provider.h"
+#include "components/optimization_guide/content/browser/page_context_eligibility.h"
 #include "components/permissions/permission_request_manager.h"
 #include "components/sessions/content/session_tab_helper.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
@@ -300,6 +302,20 @@
              : nullptr;
 }
 
+bool IsPageContextEligible(
+    const GURL& main_frame_url,
+    std::vector<optimization_guide::FrameMetadata> frame_metadata,
+    optimization_guide::PageContextEligibility* page_context_eligibility) {
+  if (!page_context_eligibility ||
+      !lens::features::IsLensSearchProtectedPageEnabled() ||
+      !lens::features::IsLensOverlayContextualSearchboxEnabled() ||
+      !lens::features::UseApcAsContext()) {
+    return true;
+  }
+  return page_context_eligibility->api().IsPageContextEligible(
+      main_frame_url.host(), main_frame_url.path(), std::move(frame_metadata));
+}
+
 }  // namespace
 
 LensOverlayController::LensOverlayController(
@@ -624,6 +640,7 @@
   return view && view->IsSurfaceAvailableForCopy();
 }
 
+// TOOD(crbug.com/404941800): Move this method to the search controller.
 void LensOverlayController::OnSidePanelWillHide(
     SidePanelEntryHideReason reason) {
   // If the tab is not in the foreground, this is not relevant.
@@ -642,11 +659,13 @@
     } else {
       // Trigger the close animation and notify the overlay that the side
       // panel is closing so that it can fade out the UI.
-      CloseUIAsync(lens::LensOverlayDismissalSource::kSidePanelCloseButton);
+      lens_search_controller_->CloseLensAsync(
+          lens::LensOverlayDismissalSource::kSidePanelCloseButton);
     }
   }
 }
 
+// TOOD(crbug.com/404941800): Move this method to the search controller.
 void LensOverlayController::OnSidePanelHidden() {
   if (state_ != State::kClosingSidePanel) {
     return;
@@ -1223,9 +1242,11 @@
     initialization_data_->selected_region_bitmap_.reset();
   }
 
-  lens_overlay_query_controller_->SendRegionSearch(
-      region.Clone(), selection_type,
-      initialization_data_->additional_search_query_params_, region_bytes);
+  if (is_page_context_eligible_) {
+    lens_overlay_query_controller_->SendRegionSearch(
+        region.Clone(), selection_type,
+        initialization_data_->additional_search_query_params_, region_bytes);
+  }
   MaybeOpenSidePanel();
   RecordTimeToFirstInteraction(
       lens::LensOverlayFirstInteractionType::kRegionSelect);
@@ -1238,17 +1259,21 @@
     const std::string& text_query,
     lens::LensOverlaySelectionType selection_type,
     std::optional<SkBitmap> region_bitmap) {
-  lens_overlay_query_controller_->SendMultimodalRequest(
-      std::move(region), text_query, selection_type,
-      initialization_data_->additional_search_query_params_, region_bitmap);
+  if (is_page_context_eligible_) {
+    lens_overlay_query_controller_->SendMultimodalRequest(
+        std::move(region), text_query, selection_type,
+        initialization_data_->additional_search_query_params_, region_bitmap);
+  }
 }
 
 void LensOverlayController::IssueContextualTextRequest(
     const std::string& text_query,
     lens::LensOverlaySelectionType selection_type) {
-  lens_overlay_query_controller_->SendContextualTextQuery(
-      text_query, selection_type,
-      initialization_data_->additional_search_query_params_);
+  if (is_page_context_eligible_) {
+    lens_overlay_query_controller_->SendContextualTextQuery(
+        text_query, selection_type,
+        initialization_data_->additional_search_query_params_);
+  }
 }
 
 void LensOverlayController::AddOverlayStateToSearchQuery(
@@ -1345,7 +1370,7 @@
       lens_overlay_controller_->NotifyPageContentUpdated();
       return;
     }
-    lens_overlay_controller_->CloseUISync(
+    lens_overlay_controller_->lens_search_controller_->CloseLensSync(
         lens::LensOverlayDismissalSource::kPageChanged);
   }
 
@@ -1357,7 +1382,7 @@
       return;
     }
 
-    lens_overlay_controller_->CloseUISync(
+    lens_overlay_controller_->lens_search_controller_->CloseLensSync(
         status == base::TERMINATION_STATUS_NORMAL_TERMINATION
             ? lens::LensOverlayDismissalSource::kPageRendererClosedNormally
             : lens::LensOverlayDismissalSource::
@@ -1380,7 +1405,7 @@
 
   // During initialization and shutdown a capture may not be possible.
   if (!IsScreenshotPossible(view)) {
-    CloseUISync(
+    lens_search_controller_->CloseLensSync(
         lens::LensOverlayDismissalSource::kErrorScreenshotCreationFailed);
     return;
   }
@@ -1458,7 +1483,7 @@
   // this is a multi-process, multi-threaded environment so there may be a
   // TOCTTOU race condition.
   if (bitmap.drawsNothing()) {
-    CloseUISync(
+    lens_search_controller_->CloseLensSync(
         lens::LensOverlayDismissalSource::kErrorScreenshotCreationFailed);
     return;
   }
@@ -1467,8 +1492,21 @@
     // Start the query as soon as the image is ready since it is the only
     // critical asynchronous flow. This optimization parallelizes the query flow
     // with other async startup processes.
+    const auto& tab_url = tab_->GetContents()->GetLastCommittedURL();
+
+    auto bitmap_to_send = bitmap;
+    auto page_url = GetPageURL();
+    auto page_title = GetPageTitle();
+    if (!IsPageContextEligible(
+            tab_url, {}, lens_search_controller_->page_context_eligibility())) {
+      is_page_context_eligible_ = false;
+      bitmap_to_send = SkBitmap();
+      page_url = GURL();
+      page_title = "";
+    }
+
     lens_overlay_query_controller_->StartQueryFlow(
-        bitmap, GetPageURL(), GetPageTitle(),
+        bitmap_to_send, page_url, page_title,
         ConvertSignificantRegionBoxes(all_bounds),
         std::vector<lens::PageContent>(), lens::MimeType::kUnknown,
         pdf_current_page, GetUiScaleFactor(), invocation_time_);
@@ -1503,7 +1541,7 @@
     SkBitmap rgb_screenshot) {
   if (state_ != State::kStartingWebUI || rgb_screenshot.drawsNothing()) {
     // TODO(b/334185985): Handle case when screenshot RGB encoding fails.
-    CloseUISync(
+    lens_search_controller_->CloseLensSync(
         lens::LensOverlayDismissalSource::kErrorScreenshotEncodingFailed);
     return;
   }
@@ -1558,6 +1596,9 @@
     return;
   }
 
+  is_page_context_eligible_ = true;
+  results_side_panel_coordinator_->SetShowProtectedErrorPage(false);
+
 #if BUILDFLAG(ENABLE_PDF)
   // Try and fetch the PDF bytes if enabled.
   pdf::PDFDocumentHelper* pdf_helper =
@@ -1763,6 +1804,7 @@
   blink::mojom::AIPageContentOptionsPtr ai_page_content_options =
       optimization_guide::DefaultAIPageContentOptions();
   ai_page_content_options->on_critical_path = true;
+  ai_page_content_options->max_meta_elements = 20;
   optimization_guide::GetAIPageContent(
       tab_->GetContents(), std::move(ai_page_content_options),
       base::BindOnce(&LensOverlayController::OnAnnotatedPageContentReceived,
@@ -1776,11 +1818,28 @@
     std::optional<optimization_guide::AIPageContentResult> result) {
   // Add the apc proto the page_contents if it exists.
   if (result) {
-    std::string serialized_apc;
-    result->proto.SerializeToString(&serialized_apc);
-    page_contents.emplace_back(
-        std::vector<uint8_t>(serialized_apc.begin(), serialized_apc.end()),
-        lens::MimeType::kAnnotatedPageContent);
+    // Convert the page metadata to a C struct defined in the optimization_guide
+    // component so it can be passed to the shared library.
+    std::vector<optimization_guide::FrameMetadata> frame_metadata_structs =
+        lens::ConvertFrameMetadataFromProto(result.value());
+
+    // If the page is protected, do not send the latest page content to the
+    // server.
+    const auto& tab_url = tab_->GetContents()->GetLastCommittedURL();
+    if (!IsPageContextEligible(
+            tab_url, std::move(frame_metadata_structs),
+            lens_search_controller_->page_context_eligibility())) {
+      is_page_context_eligible_ = false;
+      results_side_panel_coordinator_->SetShowProtectedErrorPage(true);
+      // Clear all previous page contents.
+      page_contents.clear();
+    } else {
+      std::string serialized_apc;
+      result->proto.SerializeToString(&serialized_apc);
+      page_contents.emplace_back(
+          std::vector<uint8_t>(serialized_apc.begin(), serialized_apc.end()),
+          lens::MimeType::kAnnotatedPageContent);
+    }
   }
   // Done fetching page contents.
   std::move(callback).Run(page_contents, lens::MimeType::kAnnotatedPageContent,
@@ -1851,6 +1910,12 @@
     return;
   }
 
+  // If the protected page is showing, then return early as none of the content
+  // will be sent.
+  if (results_side_panel_coordinator_->IsShowingProtectedErrorPage()) {
+    return;
+  }
+
   // Do not capture a new screenshot if the feature param is not enabled or if
   // the user is not viewing the live page, meaning the viewport cannot have
   // changed.
@@ -1958,6 +2023,7 @@
         lens_overlay_query_controller_->MaybeRestartQueryFlow();
         return;
       }
+
       // If the screenshot has changed but the bytes have not, send only the
       // screenshot.
       lens_overlay_query_controller_->SendUpdatedPageContent(
@@ -2222,6 +2288,8 @@
 
   lens_selection_type_ = lens::UNKNOWN_SELECTION_TYPE;
   should_show_overlay_ = true;
+  is_page_context_eligible_ = true;
+  should_send_screenshot_on_init_ = false;
 
   state_ = State::kOff;
 
@@ -2285,12 +2353,18 @@
   // If the StartQueryFlow optimization is enabled, the page contents will not
   // be sent with the initial image request, so we need to send it here.
   if (lens::features::IsLensOverlayContextualSearchboxEnabled() &&
-      lens::features::IsLensOverlayEarlyStartQueryFlowOptimizationEnabled()) {
+      lens::features::IsLensOverlayEarlyStartQueryFlowOptimizationEnabled() &&
+      is_page_context_eligible_) {
+    // The screenshot is not sent here unless forced by
+    // `should_send_screenshot_on_init_` as it should have been sent in the
+    // original StartQueryFlow call.
     lens_overlay_query_controller_->SendUpdatedPageContent(
         initialization_data_->page_contents_,
         initialization_data_->primary_content_type_, GetPageURL(),
         GetPageTitle(), initialization_data_->last_retrieved_most_visible_page_,
-        SkBitmap());
+        should_send_screenshot_on_init_
+            ? initialization_data_->initial_screenshot_
+            : SkBitmap());
   }
 
   // Show the preselection overlay now that the overlay is initialized and ready
@@ -2321,9 +2395,13 @@
   // response, unless the early start query flow optimization is enabled.
   if (!initialization_data_->has_full_image_response() &&
       !lens::features::IsLensOverlayEarlyStartQueryFlowOptimizationEnabled()) {
-    // Use std::move because significant_region_boxes_ is only used in this
-    // call, which should only occur once in the lifetime of
-    // LensOverlayQueryController and thus of LensOverlayController.
+    if (!is_page_context_eligible_) {
+      initialization_data_->initial_screenshot_ = SkBitmap();
+      initialization_data_->page_url_ = GURL();
+      initialization_data_->page_title_ = "";
+      should_send_screenshot_on_init_ = true;
+    }
+
     lens_overlay_query_controller_->StartQueryFlow(
         initialization_data_->initial_screenshot_,
         initialization_data_->page_url_, initialization_data_->page_title_,
@@ -2473,7 +2551,8 @@
   if (tab_->GetBrowserWindowInterface()->IsTabStripVisible()) {
     return;
   }
-  CloseUISync(lens::LensOverlayDismissalSource::kFullscreened);
+  lens_search_controller_->CloseLensSync(
+      lens::LensOverlayDismissalSource::kFullscreened);
 }
 
 void LensOverlayController::OnViewBoundsChanged(views::View* observed_view) {
@@ -2536,7 +2615,8 @@
   if (state_ == State::kLivePageAndResults) {
     return;
   }
-  CloseUIAsync(lens::LensOverlayDismissalSource::kFindInPageInvoked);
+  lens_search_controller_->CloseLensAsync(
+      lens::LensOverlayDismissalSource::kFindInPageInvoked);
 }
 
 void LensOverlayController::OnFindResultAvailable(
@@ -2544,7 +2624,8 @@
   if (state_ == State::kLivePageAndResults) {
     return;
   }
-  CloseUIAsync(lens::LensOverlayDismissalSource::kFindInPageInvoked);
+  lens_search_controller_->CloseLensAsync(
+      lens::LensOverlayDismissalSource::kFindInPageInvoked);
 }
 
 void LensOverlayController::OnImmersiveRevealStarted() {
@@ -2787,7 +2868,8 @@
   // If a side panel opens that is not ours, we must close the overlay.
   if (side_panel_coordinator_->GetCurrentEntryId() !=
       SidePanelEntry::Id::kLensOverlayResults) {
-    CloseUISync(lens::LensOverlayDismissalSource::kUnexpectedSidePanelOpen);
+    lens_search_controller_->CloseLensSync(
+        lens::LensOverlayDismissalSource::kUnexpectedSidePanelOpen);
   }
 }
 
@@ -2817,7 +2899,8 @@
   base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
       FROM_HERE,
       base::BindOnce(
-          &LensOverlayController::CloseUISync, weak_factory_.GetWeakPtr(),
+          &LensSearchController::CloseLensSync,
+          lens_search_controller_->GetWeakPtr(),
           info.status == base::TERMINATION_STATUS_NORMAL_TERMINATION
               ? lens::LensOverlayDismissalSource::kOverlayRendererClosedNormally
               : lens::LensOverlayDismissalSource::
@@ -2870,7 +2953,7 @@
   // This is still possible when the controller is in state kScreenshot and the
   // tab was backgrounded. We should close the UI as the overlay has not been
   // created yet.
-  CloseUISync(
+  lens_search_controller_->CloseLensSync(
       lens::LensOverlayDismissalSource::kTabBackgroundedWhileScreenshotting);
 }
 
@@ -2879,7 +2962,8 @@
     content::WebContents* old_contents,
     content::WebContents* new_contents) {
   // Background tab contents discarded.
-  CloseUISync(lens::LensOverlayDismissalSource::kTabContentsDiscarded);
+  lens_search_controller_->CloseLensSync(
+      lens::LensOverlayDismissalSource::kTabContentsDiscarded);
 }
 
 void LensOverlayController::WillDetach(
@@ -2890,10 +2974,12 @@
   // of `reason`. https://crbug.com/342921671.
   switch (reason) {
     case tabs::TabInterface::DetachReason::kDelete:
-      CloseUISync(lens::LensOverlayDismissalSource::kTabClosed);
+      lens_search_controller_->CloseLensSync(
+          lens::LensOverlayDismissalSource::kTabClosed);
       return;
     case tabs::TabInterface::DetachReason::kInsertIntoOtherWindow:
-      CloseUISync(lens::LensOverlayDismissalSource::kTabDragNewWindow);
+      lens_search_controller_->CloseLensSync(
+          lens::LensOverlayDismissalSource::kTabDragNewWindow);
       return;
   }
 }
@@ -2942,11 +3028,13 @@
 }
 
 void LensOverlayController::CloseRequestedByOverlayCloseButton() {
-  CloseUIAsync(lens::LensOverlayDismissalSource::kOverlayCloseButton);
+  lens_search_controller_->CloseLensAsync(
+      lens::LensOverlayDismissalSource::kOverlayCloseButton);
 }
 
 void LensOverlayController::CloseRequestedByOverlayBackgroundClick() {
-  CloseUIAsync(lens::LensOverlayDismissalSource::kOverlayBackgroundClick);
+  lens_search_controller_->CloseLensAsync(
+      lens::LensOverlayDismissalSource::kOverlayBackgroundClick);
 }
 
 void LensOverlayController::FeedbackRequestedByOverlay() {
@@ -3119,12 +3207,12 @@
             net::NetworkChangeNotifier::IsOffline(),
             /*exit_clicked_callback=*/
             base::BindRepeating(
-                &LensOverlayController::CloseUIAsync,
-                weak_factory_.GetWeakPtr(),
+                &LensSearchController::CloseLensSync,
+                lens_search_controller_->GetWeakPtr(),
                 lens::LensOverlayDismissalSource::kPreselectionToastExitButton),
             /*on_cancel_callback=*/
-            base::BindOnce(&LensOverlayController::CloseUIAsync,
-                           weak_factory_.GetWeakPtr(),
+            base::BindOnce(&LensSearchController::CloseLensSync,
+                           lens_search_controller_->GetWeakPtr(),
                            lens::LensOverlayDismissalSource::
                                kPreselectionToastEscapeKeyPress)));
     preselection_widget_->SetNativeWindowProperty(
@@ -3246,8 +3334,10 @@
     lens_selection_type_ = lens::MULTIMODAL_SUGGEST_TYPEAHEAD;
   }
 
-  if (initialization_data_->selected_region_.is_null() &&
-      IsContextualSearchbox()) {
+  if (!is_page_context_eligible_) {
+    // Do not send any requests if the page is not context eligible.
+  } else if (initialization_data_->selected_region_.is_null() &&
+             IsContextualSearchbox()) {
     lens_overlay_query_controller_->SendContextualTextQuery(
         search_box_text, lens_selection_type_,
         initialization_data_->additional_search_query_params_);
@@ -3304,7 +3394,10 @@
   SetSearchboxInputText(search_box_text);
 
   MaybeOpenSidePanel();
-  results_side_panel_coordinator_->SetSidePanelIsLoadingResults(true);
+  // Only set the side panel to loading if the page is context eligible because
+  // otherwise there will be no results to load.
+  results_side_panel_coordinator_->SetSidePanelIsLoadingResults(
+      is_page_context_eligible_);
   MaybeLaunchSurvey();
 
   // After the searchbox request is sent, mark the follow up zps as not shown so
@@ -3325,12 +3418,13 @@
   if (is_side_panel_open) {
     results_side_panel_coordinator_->MaybeSetSidePanelShowErrorPage(
         is_error,
-        is_error ? lens::SidePanelResultStatus::kErrorPageShownStartQueryError
-                 : lens::SidePanelResultStatus::kResultShown);
+        is_error
+            ? lens::mojom::SidePanelResultStatus::kErrorPageShownStartQueryError
+            : lens::mojom::SidePanelResultStatus::kResultShown);
   } else if (!is_side_panel_open && is_error) {
     results_side_panel_coordinator_->MaybeSetSidePanelShowErrorPage(
         /*should_show_error_page=*/true,
-        lens::SidePanelResultStatus::kErrorPageShownStartQueryError);
+        lens::mojom::SidePanelResultStatus::kErrorPageShownStartQueryError);
   }
 
   if (!objects.empty()) {
diff --git a/chrome/browser/ui/lens/lens_overlay_controller.h b/chrome/browser/ui/lens/lens_overlay_controller.h
index 8256443..3846292 100644
--- a/chrome/browser/ui/lens/lens_overlay_controller.h
+++ b/chrome/browser/ui/lens/lens_overlay_controller.h
@@ -214,17 +214,6 @@
       lens::mojom::CenterRotatedBoxPtr region,
       const SkBitmap& region_bitmap);
 
-  // Starts the closing process of the overlay. This is an asynchronous process
-  // with the following sequence:
-  //   (1) Close the side panel
-  //   (2) Close the overlay.
-  // Step (1) is asynchronous.
-  void CloseUIAsync(lens::LensOverlayDismissalSource dismissal_source);
-
-  // Instantly closes the overlay. This may not look nice if the overlay is
-  // visible when this is called.
-  void CloseUISync(lens::LensOverlayDismissalSource dismissal_source);
-
   // This method is used to set up communication between this instance and the
   // overlay WebUI. This is called by the WebUIController when the WebUI is
   // executing javascript and ready to bind.
@@ -590,6 +579,17 @@
   // be recorded in the relevant metrics.
   void ShowUI(lens::LensOverlayInvocationSource invocation_source);
 
+  // Starts the closing process of the overlay. This is an asynchronous process
+  // with the following sequence:
+  //   (1) Close the side panel
+  //   (2) Close the overlay.
+  // Step (1) is asynchronous.
+  void CloseUIAsync(lens::LensOverlayDismissalSource dismissal_source);
+
+  // Instantly closes the overlay. This may not look nice if the overlay is
+  // visible when this is called.
+  void CloseUISync(lens::LensOverlayDismissalSource dismissal_source);
+
   // Returns the vsrid to use for the new tab URL.
   std::string GetVsridForNewTab();
 
@@ -1390,6 +1390,16 @@
   // upload.
   bool is_upload_progress_bar_shown_ = true;
 
+  // Indicates whether the user is currently on a context eligible page.
+  bool is_page_context_eligible_ = true;
+
+  // Indicates whether the screenshot should be sent when updating the page
+  // content when first initializing the overlay. This is only used when the
+  // early start query flow optimization is enabled. Setting this to true does
+  // not guarantee the screenshot is sent on initialization, as that is still
+  // dependent on whether the page is context eligible or not.
+  bool should_send_screenshot_on_init_ = false;
+
   // TODO(384778180): The three `pre_initialization_*` fields below are used to
   // store data that came back before the initialization data was ready. This
   // should be refactored into one struct to make it cleaner.
diff --git a/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc b/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc
index 3b60333..99582812 100644
--- a/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc
+++ b/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/test/bind.h"
+#include "components/optimization_guide/content/browser/page_context_eligibility.h"
+#include "components/optimization_guide/content/browser/page_context_eligibility_api.h"
 #ifdef UNSAFE_BUFFERS_BUILD
 // TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
 #pragma allow_unsafe_libc_calls
@@ -617,6 +620,14 @@
   explicit LensSearchControllerFake(tabs::TabInterface* tab)
       : lens::TestLensSearchController(tab) {}
 
+  ~LensSearchControllerFake() override { ResetPageContextEligibilityAPI(); }
+
+  // Sets the context eligibility of the page and creates the new API.
+  void SetContextEligible(bool eligible) {
+    is_context_eligible_ = eligible;
+    CreatePageContextEligibilityAPI();
+  }
+
  protected:
   std::unique_ptr<LensOverlayController> CreateLensOverlayController(
       tabs::TabInterface* tab,
@@ -639,6 +650,43 @@
   CreateLensOverlaySidePanelCoordinator() override {
     return std::make_unique<lens::TestLensOverlaySidePanelCoordinator>(this);
   }
+
+  void CreatePageContextEligibilityAPI() override {
+    // Reset any old API pointers that could be dangling from a previous
+    // creation of the API.
+    ResetPageContextEligibilityAPI();
+
+    page_context_eligibility_api_ =
+        std::make_unique<optimization_guide::PageContextEligibilityAPI>();
+
+    page_context_eligibility_api_->IsPageContextEligible =
+        is_context_eligible_
+            ? [](const std::string& host, const std::string& path,
+                 std::vector<
+                     optimization_guide::FrameMetadata>) { return true; }
+            : [](const std::string& host, const std::string& path,
+                 std::vector<optimization_guide::FrameMetadata>) {
+                return false;
+              };
+
+    page_context_eligibility_ =
+        std::make_unique<optimization_guide::PageContextEligibility>(
+            page_context_eligibility_api_.get());
+    set_page_context_eligibility_for_testing(page_context_eligibility_.get());
+  }
+
+ private:
+  void ResetPageContextEligibilityAPI() {
+    set_page_context_eligibility_for_testing(nullptr);
+    page_context_eligibility_.reset();
+    page_context_eligibility_api_.reset();
+  }
+
+  bool is_context_eligible_ = true;
+  std::unique_ptr<optimization_guide::PageContextEligibilityAPI>
+      page_context_eligibility_api_;
+  std::unique_ptr<optimization_guide::PageContextEligibility>
+      page_context_eligibility_;
 };
 
 class TabFeaturesFake : public tabs::TabFeatures {
@@ -874,7 +922,14 @@
 
   void CloseOverlayAndWaitForOff(LensOverlayController* controller,
                                  LensOverlayDismissalSource dismissal_source) {
-    controller->CloseUIAsync(dismissal_source);
+    // TODO(crbug.com/404941800): This uses a roundabout way to close the UI.
+    // It has to go through the LensOverlayController because the search
+    // controller doesn't have proper state management. Use search controller
+    // directly once it has its own state for properly determining kOff.
+    controller->GetTabInterface()
+        ->GetTabFeatures()
+        ->lens_search_controller()
+        ->CloseLensAsync(dismissal_source);
     ASSERT_TRUE(base::test::RunUntil(
         [&]() { return controller->state() == State::kOff; }));
   }
@@ -1268,11 +1323,8 @@
   views::test::WidgetDestroyedWaiter modal_widget_destroy_waiter(modal_widget);
 
   // Close the lens overlay.
-  controller->CloseUISync(lens::LensOverlayDismissalSource::kPageChanged);
-
-  // Overlay should eventually close.
-  ASSERT_TRUE(base::test::RunUntil(
-      [&]() { return controller->state() == State::kOff; }));
+  CloseOverlayAndWaitForOff(controller,
+                            LensOverlayDismissalSource::kPageChanged);
 
   // Modal dialog should close without crashing.
   modal_widget_destroy_waiter.Wait();
@@ -5274,7 +5326,14 @@
 
   void CloseOverlayAndWaitForOff(LensOverlayController* controller,
                                  LensOverlayDismissalSource dismissal_source) {
-    controller->CloseUIAsync(dismissal_source);
+    // TODO(crbug.com/404941800): This uses a roundabout way to close the UI.
+    // It has to go through the LensOverlayController because the search
+    // controller doesn't have proper state management. Use search controller
+    // directly once it has its own state for properly determining kOff.
+    controller->GetTabInterface()
+        ->GetTabFeatures()
+        ->lens_search_controller()
+        ->CloseLensAsync(dismissal_source);
     ASSERT_TRUE(base::test::RunUntil(
         [&]() { return controller->state() == State::kOff; }));
   }
@@ -7480,6 +7539,65 @@
             fake_query_controller->last_sent_underlying_content_type());
 }
 
+IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
+                       ProtectedPageDoesNotShow) {
+  base::HistogramTester histogram_tester;
+  WaitForPaint();
+
+  // There should be no histograms logged.
+  histogram_tester.ExpectTotalCount("Lens.Overlay.SidePanelResultStatus",
+                                    /*expected_count=*/0);
+
+  // Set the search controller to return the page as not context eligible.
+  auto* fake_controller =
+      static_cast<LensSearchControllerFake*>(GetLensSearchController());
+  ASSERT_TRUE(fake_controller);
+  fake_controller->SetContextEligible(false);
+
+  // State should start in off.
+  auto* controller = GetLensOverlayController();
+  ASSERT_EQ(controller->state(), State::kOff);
+
+  // Showing UI should change the state to screenshot and eventually to overlay.
+  // When the overlay is bound, it should start the query flow which returns a
+  // response for the full image callback.
+  OpenLensOverlay(LensOverlayInvocationSource::kAppMenu);
+  ASSERT_EQ(controller->state(), State::kScreenshot);
+  ASSERT_TRUE(base::test::RunUntil(
+      [&]() { return controller->state() == State::kOverlay; }));
+  ASSERT_TRUE(content::WaitForLoadStop(GetOverlayWebContents()));
+
+  // Verify the error page histogram was not recorded since the result panel is
+  // not open.
+  histogram_tester.ExpectTotalCount("Lens.Overlay.SidePanelResultStatus",
+                                    /*expected_count=*/0);
+
+  // Side panel is not showing at first.
+  auto* coordinator = browser()->GetFeatures().side_panel_coordinator();
+  EXPECT_FALSE(coordinator->IsSidePanelShowing());
+  EXPECT_FALSE(controller->GetSidePanelWebContentsForTesting());
+
+  // Issuing a request should show the side panel even if navigation is expected
+  // to fail.
+  controller->IssueTextSelectionRequestForTesting("test query",
+                                                  /*selection_start_index=*/0,
+                                                  /*selection_end_index=*/0);
+  EXPECT_TRUE(content::WaitForLoadStop(
+      controller->GetSidePanelWebContentsForTesting()));
+
+  // Expect the Lens Overlay results panel to open.
+  ASSERT_TRUE(coordinator->IsSidePanelShowing());
+  EXPECT_EQ(coordinator->GetCurrentEntryId(),
+            SidePanelEntry::Id::kLensOverlayResults);
+
+  // The recorded histogram should be a normal result shown.
+  histogram_tester.ExpectTotalCount("Lens.Overlay.SidePanelResultStatus",
+                                    /*expected_count=*/1);
+  histogram_tester.ExpectBucketCount("Lens.Overlay.SidePanelResultStatus",
+                                     lens::SidePanelResultStatus::kResultShown,
+                                     /*expected_count=*/1);
+}
+
 class LensOverlayControllerInnerHtmlEnabledTest
     : public LensOverlayControllerBrowserTest {
  protected:
@@ -7928,15 +8046,17 @@
     : public LensOverlayControllerBrowserTest {
  protected:
   void SetupFeatureList() override {
-    feature_list_.InitAndEnableFeatureWithParameters(
-        lens::features::kLensOverlayContextualSearchbox,
-        {
-            {"send-page-url-for-contextualization", "true"},
-            {"use-inner-text-as-context", "true"},
-            {"use-inner-html-as-context", "true"},
-            {"use-apc-as-context", "true"},
-            {"use-updated-content-fields", "true"},
-        });
+    feature_list_.InitWithFeaturesAndParameters(
+        {{lens::features::kLensOverlayContextualSearchbox,
+          {
+              {"send-page-url-for-contextualization", "true"},
+              {"use-inner-text-as-context", "true"},
+              {"use-inner-html-as-context", "true"},
+              {"use-apc-as-context", "true"},
+              {"use-updated-content-fields", "true"},
+          }},
+         {lens::features::kLensSearchProtectedPage, {}}},
+        {});
   }
 };
 
@@ -8016,6 +8136,78 @@
                   .last_received_should_show_contextual_searchbox_);
 }
 
+IN_PROC_BROWSER_TEST_F(LensOverlayControllerInnerHtmlWithInnerTextAndApc,
+                       PageNotContextEligibleError) {
+  base::HistogramTester histogram_tester;
+  WaitForPaint(kDocumentWithNonAsciiCharacters);
+
+  // There should be no histograms logged.
+  histogram_tester.ExpectTotalCount("Lens.Overlay.SidePanelResultStatus",
+                                    /*expected_count=*/0);
+
+  // Set the search controller to return the page as not context eligible.
+  auto* fake_controller =
+      static_cast<LensSearchControllerFake*>(GetLensSearchController());
+  ASSERT_TRUE(fake_controller);
+  fake_controller->SetContextEligible(false);
+
+  // State should start in off.
+  auto* controller = GetLensOverlayController();
+  ASSERT_EQ(controller->state(), State::kOff);
+
+  // Showing UI should change the state to screenshot and eventually to overlay.
+  // When the overlay is bound, it should start the query flow which returns a
+  // response for the full image callback.
+  OpenLensOverlay(LensOverlayInvocationSource::kAppMenu);
+  ASSERT_EQ(controller->state(), State::kScreenshot);
+  ASSERT_TRUE(base::test::RunUntil(
+      [&]() { return controller->state() == State::kOverlay; }));
+  ASSERT_TRUE(content::WaitForLoadStop(GetOverlayWebContents()));
+
+  // Verify the error page histogram was not recorded since the result panel is
+  // not open.
+  histogram_tester.ExpectTotalCount("Lens.Overlay.SidePanelResultStatus",
+                                    /*expected_count=*/0);
+
+  // Side panel is not showing at first.
+  auto* coordinator = browser()->GetFeatures().side_panel_coordinator();
+  EXPECT_FALSE(coordinator->IsSidePanelShowing());
+  EXPECT_FALSE(controller->GetSidePanelWebContentsForTesting());
+
+  // Issuing a request should show the side panel even if navigation is expected
+  // to fail.
+  controller->IssueTextSelectionRequestForTesting("test query",
+                                                  /*selection_start_index=*/0,
+                                                  /*selection_end_index=*/0);
+  EXPECT_TRUE(content::WaitForLoadStop(
+      controller->GetSidePanelWebContentsForTesting()));
+
+  // Expect the Lens Overlay results panel to open.
+  ASSERT_TRUE(coordinator->IsSidePanelShowing());
+  EXPECT_EQ(coordinator->GetCurrentEntryId(),
+            SidePanelEntry::Id::kLensOverlayResults);
+
+  // No page data or screenshot should have been sent.
+  auto* fake_query_controller =
+      static_cast<lens::TestLensOverlayQueryController*>(
+          controller->get_lens_overlay_query_controller_for_testing());
+  const auto last_sent_content =
+      fake_query_controller->last_sent_page_content_payload().content();
+  EXPECT_EQ(last_sent_content.content_data().size(), 0);
+  EXPECT_TRUE(last_sent_content.webpage_url().empty());
+  EXPECT_TRUE(last_sent_content.webpage_title().empty());
+  EXPECT_TRUE(
+      fake_query_controller->last_sent_underlying_content_bytes().empty());
+
+  // The recorded histogram should be a protected error page being shown.
+  histogram_tester.ExpectTotalCount("Lens.Overlay.SidePanelResultStatus",
+                                    /*expected_count=*/1);
+  histogram_tester.ExpectBucketCount(
+      "Lens.Overlay.SidePanelResultStatus",
+      lens::SidePanelResultStatus::kErrorPageShownProtected,
+      /*expected_count=*/1);
+}
+
 class LensOverlayControllerContextualFeaturesDisabledTest
     : public LensOverlayControllerBrowserTest {
  protected:
diff --git a/chrome/browser/ui/lens/lens_overlay_entry_point_controller.cc b/chrome/browser/ui/lens/lens_overlay_entry_point_controller.cc
index ae8d36386..9238e84 100644
--- a/chrome/browser/ui/lens/lens_overlay_entry_point_controller.cc
+++ b/chrome/browser/ui/lens/lens_overlay_entry_point_controller.cc
@@ -220,7 +220,7 @@
   // Toggle the Lens overlay. There's no need to show or hide the side
   // panel as the overlay controller will handle that.
   if (overlay_controller->IsOverlayActive()) {
-    overlay_controller->CloseUIAsync(
+    search_controller->CloseLensAsync(
         lens::LensOverlayDismissalSource::kToolbar);
   } else {
     search_controller->OpenLensOverlay(
diff --git a/chrome/browser/ui/lens/lens_overlay_event_handler.cc b/chrome/browser/ui/lens/lens_overlay_event_handler.cc
index 786aaf5b..fc9728e 100644
--- a/chrome/browser/ui/lens/lens_overlay_event_handler.cc
+++ b/chrome/browser/ui/lens/lens_overlay_event_handler.cc
@@ -5,6 +5,8 @@
 #include "chrome/browser/ui/lens/lens_overlay_event_handler.h"
 
 #include "chrome/browser/ui/lens/lens_overlay_controller.h"
+#include "chrome/browser/ui/lens/lens_search_controller.h"
+#include "chrome/browser/ui/tabs/public/tab_features.h"
 #include "components/lens/lens_overlay_dismissal_source.h"
 
 namespace lens {
@@ -37,8 +39,14 @@
   }
 
   if (IsEscapeEvent(event)) {
-    lens_overlay_controller_->CloseUIAsync(
-        lens::LensOverlayDismissalSource::kEscapeKeyPress);
+    // TODO(crbug.com/404941800): This is a roundabout way to close the overlay,
+    // but this class isn't yet owned by the search controller, so it can't
+    // directly call it. This should be cleaned up once this class is owned by
+    // the search controller.
+    lens_overlay_controller_->GetTabInterface()
+        ->GetTabFeatures()
+        ->lens_search_controller()
+        ->CloseLensAsync(lens::LensOverlayDismissalSource::kEscapeKeyPress);
     return true;
   }
   // We only want to copy if the user is not currently making a native text
diff --git a/chrome/browser/ui/lens/lens_overlay_proto_converter.cc b/chrome/browser/ui/lens/lens_overlay_proto_converter.cc
index fa9465f..ebb68f5 100644
--- a/chrome/browser/ui/lens/lens_overlay_proto_converter.cc
+++ b/chrome/browser/ui/lens/lens_overlay_proto_converter.cc
@@ -15,6 +15,8 @@
 #include "chrome/browser/lens/core/mojom/polygon.mojom.h"
 #include "chrome/browser/lens/core/mojom/text.mojom-forward.h"
 #include "chrome/browser/lens/core/mojom/text.mojom.h"
+#include "components/optimization_guide/content/browser/page_content_proto_provider.h"
+#include "components/optimization_guide/content/browser/page_context_eligibility_api.h"
 #include "third_party/icu/source/common/unicode/unistr.h"
 #include "third_party/lens_server_proto/lens_overlay_deep_gleam_data.pb.h"
 #include "third_party/lens_server_proto/lens_overlay_geometry.pb.h"
@@ -458,4 +460,22 @@
       region_crop_box, resized_bitmap_size);
 }
 
+std::vector<optimization_guide::FrameMetadata> ConvertFrameMetadataFromProto(
+    const optimization_guide::AIPageContentResult& result) {
+  std::vector<optimization_guide::FrameMetadata> frame_metadata_structs;
+  const auto& page_metadata = result.metadata;
+  for (auto& frame_metadata_mojom : page_metadata->frame_metadata) {
+    std::vector<optimization_guide::MetaTag> meta_tags;
+    for (auto& tag : frame_metadata_mojom->meta_tags) {
+      optimization_guide::MetaTag meta_tag(tag->name, tag->content);
+      meta_tags.push_back(std::move(meta_tag));
+    }
+    optimization_guide::FrameMetadata metadata(frame_metadata_mojom->url.host(),
+                                               frame_metadata_mojom->url.path(),
+                                               std::move(meta_tags));
+    frame_metadata_structs.push_back(std::move(metadata));
+  }
+  return frame_metadata_structs;
+}
+
 }  // namespace lens
diff --git a/chrome/browser/ui/lens/lens_overlay_proto_converter.h b/chrome/browser/ui/lens/lens_overlay_proto_converter.h
index 41a00800..1af6fb4 100644
--- a/chrome/browser/ui/lens/lens_overlay_proto_converter.h
+++ b/chrome/browser/ui/lens/lens_overlay_proto_converter.h
@@ -7,6 +7,8 @@
 
 #include "chrome/browser/lens/core/mojom/overlay_object.mojom.h"
 #include "chrome/browser/lens/core/mojom/text.mojom.h"
+#include "components/optimization_guide/content/browser/page_content_proto_provider.h"
+#include "components/optimization_guide/content/browser/page_context_eligibility_api.h"
 #include "third_party/lens_server_proto/lens_overlay_geometry.pb.h"
 #include "third_party/lens_server_proto/lens_overlay_server.pb.h"
 #include "third_party/lens_server_proto/lens_overlay_service_deps.pb.h"
@@ -39,6 +41,12 @@
     const lens::LensOverlayInteractionResponse& response,
     const lens::ZoomedCrop& region_crop_box,
     const gfx::Size& resized_bitmap_size);
+
+// Convert the page metadata from the AIPageContentResult proto to a C struct
+// defined in the optimization_guide component so it can be passed to a shared
+// library.
+std::vector<optimization_guide::FrameMetadata> ConvertFrameMetadataFromProto(
+    const optimization_guide::AIPageContentResult& result);
 }  // namespace lens
 
 #endif  // CHROME_BROWSER_UI_LENS_LENS_OVERLAY_PROTO_CONVERTER_H_
diff --git a/chrome/browser/ui/lens/lens_overlay_proto_converter_unittest.cc b/chrome/browser/ui/lens/lens_overlay_proto_converter_unittest.cc
index bb6c85e2..c48bec9 100644
--- a/chrome/browser/ui/lens/lens_overlay_proto_converter_unittest.cc
+++ b/chrome/browser/ui/lens/lens_overlay_proto_converter_unittest.cc
@@ -12,6 +12,10 @@
 #include "chrome/browser/lens/core/mojom/polygon.mojom.h"
 #include "chrome/browser/lens/core/mojom/text.mojom-forward.h"
 #include "chrome/browser/lens/core/mojom/text.mojom.h"
+#include "components/optimization_guide/content/browser/page_content_proto_provider.h"
+#include "components/optimization_guide/content/browser/page_context_eligibility.h"
+#include "components/optimization_guide/content/mojom/ai_page_content_metadata.mojom-forward.h"
+#include "components/optimization_guide/content/mojom/ai_page_content_metadata.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/lens_server_proto/lens_overlay_deep_gleam_data.pb.h"
 #include "third_party/lens_server_proto/lens_overlay_geometry.pb.h"
@@ -895,4 +899,38 @@
             test_word_struct.formula_metadata_latex);
 }
 
+TEST_F(LensOverlayProtoConverterTest, ConvertFrameMetadataFromProto) {
+  optimization_guide::AIPageContentResult result;
+  optimization_guide::mojom::PageMetadataPtr page_metadata =
+      optimization_guide::mojom::PageMetadata::New();
+  std::vector<optimization_guide::mojom::FrameMetadataPtr> frame_metadata_list;
+  optimization_guide::mojom::FrameMetadataPtr frame_metadata =
+      optimization_guide::mojom::FrameMetadata::New();
+  std::vector<optimization_guide::mojom::MetaTagPtr> meta_tags;
+  optimization_guide::mojom::MetaTagPtr meta_tag =
+      optimization_guide::mojom::MetaTag::New();
+
+  frame_metadata->url = GURL("https://www.google.com/search?q=text#someref");
+  meta_tag->name = "meta-tag-name";
+  meta_tag->content = "meta-tag-content";
+  meta_tags.push_back(std::move(meta_tag));
+  frame_metadata->meta_tags = std::move(meta_tags);
+  frame_metadata_list.push_back(std::move(frame_metadata));
+
+  page_metadata->frame_metadata = std::move(frame_metadata_list);
+  result.metadata = std::move(page_metadata);
+
+  const auto frame_metadata_structs = ConvertFrameMetadataFromProto(result);
+  ASSERT_EQ(1ul, frame_metadata_structs.size());
+
+  const auto frame_metadata_struct = frame_metadata_structs[0];
+  EXPECT_EQ("www.google.com", frame_metadata_struct.host);
+  EXPECT_EQ("/search", frame_metadata_struct.path);
+  ASSERT_EQ(1ul, frame_metadata_struct.meta_tags.size());
+
+  const auto meta_tag_struct = frame_metadata_struct.meta_tags[0];
+  EXPECT_EQ("meta-tag-name", meta_tag_struct.name);
+  EXPECT_EQ("meta-tag-content", meta_tag_struct.content);
+}
+
 }  // namespace lens
diff --git a/chrome/browser/ui/lens/lens_overlay_query_controller.cc b/chrome/browser/ui/lens/lens_overlay_query_controller.cc
index 781e9ef2..b619214 100644
--- a/chrome/browser/ui/lens/lens_overlay_query_controller.cc
+++ b/chrome/browser/ui/lens/lens_overlay_query_controller.cc
@@ -1116,6 +1116,11 @@
     return;
   }
 
+  // If the screenshot draws nothing, return.
+  if (original_screenshot_.drawsNothing()) {
+    return;
+  }
+
   // There can be multiple full image requests that are called. For example,
   // when translate mode is enabled after opening the overlay or when turning
   // translate mode back off after enabling. Reset if there is one pending.
diff --git a/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.cc b/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.cc
index 983fc3e..adcf7ba 100644
--- a/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.cc
+++ b/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.cc
@@ -8,6 +8,7 @@
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/companion/text_finder/text_finder_manager.h"
 #include "chrome/browser/companion/text_finder/text_highlighter_manager.h"
+#include "chrome/browser/lens/core/mojom/lens_side_panel.mojom.h"
 #include "chrome/browser/ui/browser_window/public/browser_window_features.h"
 #include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
 #include "chrome/browser/ui/lens/lens_overlay_controller.h"
@@ -160,8 +161,10 @@
 
 void LensOverlaySidePanelCoordinator::RecordAndShowSidePanelErrorPage() {
   CHECK(side_panel_page_);
-  side_panel_page_->SetShowErrorPage(side_panel_should_show_error_page_);
-  lens::RecordSidePanelResultStatus(side_panel_result_status_);
+  side_panel_page_->SetShowErrorPage(side_panel_should_show_error_page_,
+                                     side_panel_result_status_);
+  lens::RecordSidePanelResultStatus(
+      static_cast<lens::SidePanelResultStatus>(side_panel_result_status_));
 }
 
 void LensOverlaySidePanelCoordinator::SetSidePanelNewTabUrl(const GURL& url) {
@@ -435,6 +438,29 @@
   }
 }
 
+void LensOverlaySidePanelCoordinator::SetShowProtectedErrorPage(
+    bool show_protected_error_page) {
+  if (show_protected_error_page) {
+    side_panel_should_show_error_page_ = true;
+    side_panel_result_status_ =
+        mojom::SidePanelResultStatus::kErrorPageShownProtected;
+  } else if (side_panel_result_status_ ==
+             mojom::SidePanelResultStatus::kErrorPageShownProtected) {
+    side_panel_should_show_error_page_ = false;
+    side_panel_result_status_ = mojom::SidePanelResultStatus::kResultShown;
+  }
+
+  if (side_panel_page_) {
+    RecordAndShowSidePanelErrorPage();
+  }
+}
+
+bool LensOverlaySidePanelCoordinator::IsShowingProtectedErrorPage() {
+  return side_panel_should_show_error_page_ &&
+         side_panel_result_status_ ==
+             mojom::SidePanelResultStatus::kErrorPageShownProtected;
+}
+
 void LensOverlaySidePanelCoordinator::BindSidePanel(
     mojo::PendingReceiver<lens::mojom::LensSidePanelPageHandler> receiver,
     mojo::PendingRemote<lens::mojom::LensSidePanelPage> page) {
@@ -491,12 +517,12 @@
 
 void LensOverlaySidePanelCoordinator::MaybeSetSidePanelShowErrorPage(
     bool should_show_error_page,
-    lens::SidePanelResultStatus status) {
+    mojom::SidePanelResultStatus status) {
   // Only show / hide the error page if the side panel is not already in that
   // state. Return early if the state should not change unless the initial load
   // has not been logged (`side_panel_result_status_` set to kUnknown).
   if (side_panel_should_show_error_page_ == should_show_error_page &&
-      side_panel_result_status_ != lens::SidePanelResultStatus::kUnknown) {
+      side_panel_result_status_ != mojom::SidePanelResultStatus::kUnknown) {
     return;
   }
 
@@ -508,17 +534,19 @@
 }
 
 void LensOverlaySidePanelCoordinator::SetSidePanelIsOffline(bool is_offline) {
-  // If the side panel is already showing an error page due to start query
-  // error, then this should be a no-op.
+  // If the side panel is already showing an error page, then this should be a
+  // no-op.
   if (side_panel_result_status_ ==
-      lens::SidePanelResultStatus::kErrorPageShownStartQueryError) {
+          mojom::SidePanelResultStatus::kErrorPageShownStartQueryError ||
+      side_panel_result_status_ ==
+          mojom::SidePanelResultStatus::kErrorPageShownProtected) {
     return;
   }
 
   MaybeSetSidePanelShowErrorPage(
       is_offline, is_offline
-                      ? lens::SidePanelResultStatus::kErrorPageShownOffline
-                      : lens::SidePanelResultStatus::kResultShown);
+                      ? mojom::SidePanelResultStatus::kErrorPageShownOffline
+                      : mojom::SidePanelResultStatus::kResultShown);
 }
 
 void LensOverlaySidePanelCoordinator::SetSidePanelIsLoadingResults(
@@ -595,7 +623,7 @@
   pending_side_panel_url_.reset();
   side_panel_should_show_error_page_ = false;
   side_panel_new_tab_url_ = GURL();
-  side_panel_result_status_ = lens::SidePanelResultStatus::kUnknown;
+  side_panel_result_status_ = mojom::SidePanelResultStatus::kUnknown;
 
   state_ = State::kOff;
 }
diff --git a/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.h b/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.h
index e9d5048..23a312e 100644
--- a/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.h
+++ b/chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.h
@@ -12,7 +12,6 @@
 #include "chrome/browser/ui/lens/lens_overlay_translate_options.h"
 #include "chrome/browser/ui/lens/lens_search_controller.h"
 #include "chrome/browser/ui/views/side_panel/side_panel_entry_observer.h"
-#include "components/lens/lens_overlay_side_panel_result.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -169,6 +168,13 @@
   // SimpleMenuModel::Delegate:
   void ExecuteCommand(int command_id, int event_flags) override;
 
+  // Show or hide the protected error page based on the value of
+  // `show_protected_error_page.
+  void SetShowProtectedErrorPage(bool show_protected_error_page);
+
+  // Whether the side panel is currently showing the protected error page.
+  bool IsShowingProtectedErrorPage();
+
   // Internal state machine. States are mutually exclusive. Exposed for testing.
   enum class State {
     // This is the default state. This is the state when the side panel is not
@@ -219,7 +225,7 @@
   // done if the side panel is not already in the state provided by the
   // parameters or on its first load.
   void MaybeSetSidePanelShowErrorPage(bool should_show_error_page,
-                                      lens::SidePanelResultStatus status);
+                                      mojom::SidePanelResultStatus status);
 
   // Set the side panel state as being offline.
   void SetSidePanelIsOffline(bool is_offline);
@@ -367,8 +373,8 @@
 
   // The status of the side panel, or whether it is currently showing an error
   // page.
-  lens::SidePanelResultStatus side_panel_result_status_ =
-      lens::SidePanelResultStatus::kUnknown;
+  mojom::SidePanelResultStatus side_panel_result_status_ =
+      mojom::SidePanelResultStatus::kUnknown;
 
   // General side panel coordinator responsible for all side panel interactions.
   // Separate from this class because this controls interactions to other side
diff --git a/chrome/browser/ui/lens/lens_search_controller.cc b/chrome/browser/ui/lens/lens_search_controller.cc
index f95f5f1..83f4287 100644
--- a/chrome/browser/ui/lens/lens_search_controller.cc
+++ b/chrome/browser/ui/lens/lens_search_controller.cc
@@ -5,12 +5,15 @@
 #include "chrome/browser/ui/lens/lens_search_controller.h"
 
 #include "base/check.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/lens/lens_overlay_controller.h"
 #include "chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.h"
 #include "chrome/browser/ui/lens/lens_searchbox_controller.h"
 #include "chrome/browser/ui/tabs/public/tab_features.h"
 #include "chrome/browser/ui/webui/webui_embedding_context.h"
+#include "components/optimization_guide/content/browser/page_context_eligibility.h"
 
 namespace {
 LensSearchController* GetLensSearchControllerFromTabInterface(
@@ -42,6 +45,8 @@
       CreateLensOverlaySidePanelCoordinator();
 
   lens_searchbox_controller_ = CreateLensSearchboxController();
+
+  CreatePageContextEligibilityAPI();
 }
 
 // static.
@@ -69,12 +74,36 @@
   // TODO(crbug.com/404941800): Add logic based on this classes state once the
   // state machine is available.
   lens_overlay_controller_->ShowUI(invocation_source);
+
+  // TODO(crbug.com/404941800): This state should start with kInitializing and
+  // then move to kActive once the overlay is fully initialized. Setting
+  // straight to kActive for now to unblock development.
+  state_ = State::kActive;
+}
+
+void LensSearchController::CloseLensAsync(
+    lens::LensOverlayDismissalSource dismissal_source) {
+  lens_overlay_controller_->CloseUIAsync(dismissal_source);
+  // TODO(crbug.com/404941800): This state should start with kClosing and
+  // then move to kOff once all Lens feature have finished closing. Setting
+  // straight to kOff for now to unblock development.
+  state_ = State::kOff;
+}
+
+void LensSearchController::CloseLensSync(
+    lens::LensOverlayDismissalSource dismissal_source) {
+  lens_overlay_controller_->CloseUISync(dismissal_source);
+  state_ = State::kOff;
 }
 
 tabs::TabInterface* LensSearchController::GetTabInterface() {
   return tab_;
 }
 
+base::WeakPtr<LensSearchController> LensSearchController::GetWeakPtr() {
+  return weak_ptr_factory_.GetWeakPtr();
+}
+
 LensOverlayController* LensSearchController::lens_overlay_controller() {
   CHECK(initialized_)
       << "The LensSearchController has not been initialized. Initialize() must "
@@ -90,6 +119,18 @@
   return lens_overlay_side_panel_coordinator_.get();
 }
 
+optimization_guide::PageContextEligibility*
+LensSearchController::page_context_eligibility() {
+  CHECK(initialized_)
+      << "The LensSearchController has not been initialized. Initialize() must "
+         "be called before using the LensSearchController.";
+  if (page_context_eligibility_) {
+    return page_context_eligibility_;
+  }
+
+  return nullptr;
+}
+
 std::unique_ptr<LensOverlayController>
 LensSearchController::CreateLensOverlayController(
     tabs::TabInterface* tab,
@@ -113,3 +154,17 @@
 LensSearchController::CreateLensSearchboxController() {
   return std::make_unique<lens::LensSearchboxController>(this);
 }
+
+void LensSearchController::CreatePageContextEligibilityAPI() {
+  // Post to a background thread to avoid blocking the set up of the overlay.
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
+      base::BindOnce(&optimization_guide::PageContextEligibility::Get),
+      base::BindOnce(&LensSearchController::OnPageContextEligibilityAPILoaded,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void LensSearchController::OnPageContextEligibilityAPILoaded(
+    optimization_guide::PageContextEligibility* page_context_eligibility) {
+  page_context_eligibility_ = page_context_eligibility;
+}
diff --git a/chrome/browser/ui/lens/lens_search_controller.h b/chrome/browser/ui/lens/lens_search_controller.h
index d89ccc59..01397a3 100644
--- a/chrome/browser/ui/lens/lens_search_controller.h
+++ b/chrome/browser/ui/lens/lens_search_controller.h
@@ -5,8 +5,13 @@
 #ifndef CHROME_BROWSER_UI_LENS_LENS_SEARCH_CONTROLLER_H_
 #define CHROME_BROWSER_UI_LENS_LENS_SEARCH_CONTROLLER_H_
 
+#include <memory>
+
 #include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "components/lens/lens_overlay_dismissal_source.h"
 #include "components/lens/lens_overlay_invocation_source.h"
+#include "components/optimization_guide/content/browser/page_context_eligibility.h"
 #include "components/tabs/public/tab_interface.h"
 
 class LensOverlayController;
@@ -68,15 +73,39 @@
   virtual void OpenLensOverlay(
       lens::LensOverlayInvocationSource invocation_source);
 
+  // Starts the closing process of the overlay. This is an asynchronous process
+  // with the following sequence:
+  //   (1) Close the side panel
+  //   (2) Close the overlay.
+  // Step (1) is asynchronous.
+  virtual void CloseLensAsync(
+      lens::LensOverlayDismissalSource dismissal_source);
+
+  // Instantly closes all Lens components currently opened.This may not look
+  // nice if the overlay is visible when this is called.
+  virtual void CloseLensSync(lens::LensOverlayDismissalSource dismissal_source);
+
   // Returns the tab interface that owns this controller.
   tabs::TabInterface* GetTabInterface();
 
+  // Returns the weak pointer to this class.
+  base::WeakPtr<LensSearchController> GetWeakPtr();
+
   // Returns the LensOverlayController.
   LensOverlayController* lens_overlay_controller();
 
   // Returns the LensOverlaySidePanelCoordinator.
   lens::LensOverlaySidePanelCoordinator* lens_overlay_side_panel_coordinator();
 
+  optimization_guide::PageContextEligibility* page_context_eligibility();
+
+  // Testing function for setting the page context eligibility API for this
+  // controller.
+  void set_page_context_eligibility_for_testing(
+      optimization_guide::PageContextEligibility* page_context_eligibility) {
+    page_context_eligibility_ = page_context_eligibility;
+  }
+
  protected:
   // Override these methods to stub out individual feature controllers for
   // testing.
@@ -99,10 +128,35 @@
   virtual std::unique_ptr<lens::LensSearchboxController>
   CreateLensSearchboxController();
 
+  // Override these methods to be able to track calls made to the page context
+  // eligibility API.
+  virtual void CreatePageContextEligibilityAPI();
+
+  // Internal state machine. States are mutually exclusive. Exposed for testing.
+  enum class State {
+    // This is the default state. No feature is currently active or soon to be
+    // active.
+    kOff,
+
+    // One or more Lens features are active on this tab.
+    kActive,
+
+    // TODO(crbug.com/335516480): Implement suspended state.
+    kSuspended,
+  };
+  State state() { return state_; }
+
  private:
-  // Whether the LensSearchController has been initialized.
+  void OnPageContextEligibilityAPILoaded(
+      optimization_guide::PageContextEligibility* page_context_eligibility);
+
+  // Whether the LensSearchController has been initialized. Meaning, all the
+  // dependencies have been initialized and the controller is ready to use.
   bool initialized_ = false;
 
+  // Tracks the internal state machine.
+  State state_ = State::kOff;
+
   // The overlay controller for the Lens Search feature on this tab.
   std::unique_ptr<LensOverlayController> lens_overlay_controller_;
 
@@ -115,8 +169,14 @@
   // interactions, without a dependency on the overlay controller.
   std::unique_ptr<lens::LensSearchboxController> lens_searchbox_controller_;
 
+  // The page context eligibility API if it has been fetched. Can be nullptr.
+  raw_ptr<optimization_guide::PageContextEligibility> page_context_eligibility_;
+
   // Owns this class.
   raw_ptr<tabs::TabInterface> tab_;
+
+  // Must be the last member.
+  base::WeakPtrFactory<LensSearchController> weak_ptr_factory_{this};
 };
 
 #endif  // CHROME_BROWSER_UI_LENS_LENS_SEARCH_CONTROLLER_H_
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
index 121eb447..57f4deb6 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
@@ -60,6 +60,7 @@
 #include "chrome/browser/ui/hats/hats_service_factory.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/lens/lens_overlay_controller.h"
+#include "chrome/browser/ui/lens/lens_search_controller.h"
 #include "chrome/browser/ui/location_bar/location_bar.h"
 #include "chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer.h"
 #include "chrome/browser/ui/omnibox/omnibox_tab_helper.h"
@@ -122,6 +123,12 @@
                       : nullptr;
 }
 
+LensSearchController* GetLensSearchController(
+    content::WebContents* web_contents) {
+  return web_contents ? LensSearchController::FromTabWebContents(web_contents)
+                      : nullptr;
+}
+
 }  // namespace
 
 ChromeOmniboxClient::ChromeOmniboxClient(LocationBar* location_bar,
@@ -381,10 +388,10 @@
     return;
   }
 
-  if (LensOverlayController* lens_overlay_controller =
-          GetLensOverlayController(location_bar_->GetWebContents())) {
+  if (LensSearchController* lens_search_controller =
+          GetLensSearchController(location_bar_->GetWebContents())) {
     // TODO(crbug.com/408073216): Create and use new dismissal source.
-    lens_overlay_controller->CloseUIAsync(
+    lens_search_controller->CloseLensAsync(
         lens::LensOverlayDismissalSource::kEscapeKeyPress);
   }
 }
diff --git a/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager.cc b/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager.cc
index acdde9f..de5287e 100644
--- a/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager.cc
+++ b/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager.cc
@@ -545,6 +545,55 @@
 }
 
 // static
+void DisruptiveNotificationPermissionsManager::MaybeReportUserRegrant(
+    Profile* profile,
+    const GURL& url,
+    ukm::SourceId source_id) {
+  if (!profile) {
+    return;
+  }
+  auto* hcsm = HostContentSettingsMapFactory::GetForProfile(profile);
+  if (!hcsm || !url.is_valid()) {
+    return;
+  }
+  content_settings::SettingInfo info;
+  base::Value stored_value = hcsm->GetWebsiteSetting(
+      url, url,
+      ContentSettingsType::REVOKED_DISRUPTIVE_NOTIFICATION_PERMISSIONS, &info);
+  if (stored_value.is_none()) {
+    return;
+  }
+  CHECK(stored_value.is_dict());
+  base::Value::Dict dict = std::move(stored_value).TakeDict();
+
+  const std::string* revoked_status =
+      dict.FindString(safety_hub::kRevokedStatusDictKeyStr);
+  if (!revoked_status) {
+    return;
+  }
+
+  // It should be already false positive since the website is being visited.
+  if (*revoked_status != safety_hub::kFalsePositiveStr) {
+    return;
+  }
+
+  const base::Value* stored_timestamp = dict.Find(safety_hub::kTimestampStr);
+  base::TimeDelta delta_since_revocation =
+      base::Time::Now() -
+      base::ValueToTime(stored_timestamp).value_or(base::Time::Now());
+  ukm::builders::SafetyHub_DisruptiveNotificationRevocations_UserRegrant(
+      source_id)
+      .SetDaysSinceRevocation(delta_since_revocation.InDays())
+      .SetNewSiteEngagement(
+          site_engagement::SiteEngagementService::Get(profile)->GetScore(url))
+      .SetOldSiteEngagement(
+          dict.FindDouble(safety_hub::kSiteEngagementStr).value_or(0))
+      .SetDailyAverageVolume(
+          dict.FindInt(safety_hub::kDailyNotificationCountStr).value_or(0))
+      .Record(ukm::UkmRecorder::Get());
+}
+
+// static
 void DisruptiveNotificationPermissionsManager::LogMetrics(
     Profile* profile,
     const GURL& url,
diff --git a/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager.h b/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager.h
index 0bef7cb..5c48b1b3 100644
--- a/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager.h
+++ b/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager.h
@@ -148,6 +148,13 @@
                                     FalsePositiveReason reason,
                                     ukm::SourceId source_id);
 
+  // If the URL is in the false positive list, report user regrant after a
+  // revocation. Since the user regrant only happens on a page visit, the site
+  // will be in false positive list, not in the revoked list.
+  static void MaybeReportUserRegrant(Profile* profile,
+                                     const GURL& url,
+                                     ukm::SourceId source_id);
+
   // Logs metrics for proposed disruptive notification revocation, to be called
   // when displaying a persistent notification.
   static void LogMetrics(Profile* profile,
diff --git a/chrome/browser/ui/safety_hub/revoked_permissions_service.cc b/chrome/browser/ui/safety_hub/revoked_permissions_service.cc
index 7ebc1a3..68b8ba9 100644
--- a/chrome/browser/ui/safety_hub/revoked_permissions_service.cc
+++ b/chrome/browser/ui/safety_hub/revoked_permissions_service.cc
@@ -220,7 +220,13 @@
     : content::WebContentsObserver(web_contents),
       content::WebContentsUserData<TabHelper>(*web_contents),
       unused_site_permission_service_(
-          unused_site_permission_service->AsWeakPtr()) {}
+          unused_site_permission_service->AsWeakPtr()) {
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  auto* host_content_settings_map_ =
+      HostContentSettingsMapFactory::GetForProfile(profile);
+  observation_.Observe(host_content_settings_map_);
+}
 
 RevokedPermissionsService::TabHelper::~TabHelper() = default;
 
@@ -355,6 +361,43 @@
   }
 }
 
+void RevokedPermissionsService::TabHelper::OnContentSettingChanged(
+    const ContentSettingsPattern& primary_pattern,
+    const ContentSettingsPattern& secondary_pattern,
+    ContentSettingsTypeSet content_type_set) {
+  if (content_type_set.ContainsAllTypes() ||
+      content_type_set.GetType() != ContentSettingsType::NOTIFICATIONS) {
+    return;
+  }
+
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
+  auto* hcsm = HostContentSettingsMapFactory::GetForProfile(profile);
+  if (!content_settings::PatternAppliesToSingleOrigin(primary_pattern,
+                                                      secondary_pattern)) {
+    return;
+  }
+
+  const GURL last_visited_url =
+      web_contents()->GetPrimaryMainFrame()->GetLastCommittedURL();
+
+  // Only trigger if the user is currently visiting the URL.
+  if (!primary_pattern.Matches(last_visited_url)) {
+    return;
+  }
+
+  // Only when the notification is allowed.
+  if (hcsm->GetContentSetting(last_visited_url, last_visited_url,
+                              ContentSettingsType::NOTIFICATIONS) !=
+      CONTENT_SETTING_ALLOW) {
+    return;
+  }
+
+  DisruptiveNotificationPermissionsManager::MaybeReportUserRegrant(
+      profile, last_visited_url,
+      web_contents()->GetPrimaryMainFrame()->GetPageUkmSourceId());
+}
+
 WEB_CONTENTS_USER_DATA_KEY_IMPL(RevokedPermissionsService::TabHelper);
 
 RevokedPermissionsService::RevokedPermissionsService(
diff --git a/chrome/browser/ui/safety_hub/revoked_permissions_service.h b/chrome/browser/ui/safety_hub/revoked_permissions_service.h
index 9e9d95b3..63eba06 100644
--- a/chrome/browser/ui/safety_hub/revoked_permissions_service.h
+++ b/chrome/browser/ui/safety_hub/revoked_permissions_service.h
@@ -135,7 +135,8 @@
   };
 
   class TabHelper : public content::WebContentsObserver,
-                    public content::WebContentsUserData<TabHelper> {
+                    public content::WebContentsUserData<TabHelper>,
+                    public content_settings::Observer {
    public:
     TabHelper(const TabHelper&) = delete;
     TabHelper& operator=(const TabHelper&) = delete;
@@ -144,6 +145,12 @@
     // WebContentsObserver:
     void PrimaryPageChanged(content::Page& page) override;
 
+    // content_settings::Observer:
+    void OnContentSettingChanged(
+        const ContentSettingsPattern& primary_pattern,
+        const ContentSettingsPattern& secondary_pattern,
+        ContentSettingsTypeSet content_type_set) override;
+
    private:
     explicit TabHelper(
         content::WebContents* web_contents,
@@ -151,6 +158,9 @@
 
     base::WeakPtr<RevokedPermissionsService> unused_site_permission_service_;
 
+    base::ScopedObservation<HostContentSettingsMap, content_settings::Observer>
+        observation_{this};
+
     friend class content::WebContentsUserData<TabHelper>;
     WEB_CONTENTS_USER_DATA_KEY_DECL();
   };
diff --git a/chrome/browser/ui/safety_hub/revoked_permissions_service_browsertest.cc b/chrome/browser/ui/safety_hub/revoked_permissions_service_browsertest.cc
index 700aada..4d97a3559 100644
--- a/chrome/browser/ui/safety_hub/revoked_permissions_service_browsertest.cc
+++ b/chrome/browser/ui/safety_hub/revoked_permissions_service_browsertest.cc
@@ -934,3 +934,39 @@
   recorder_->ExpectEntryMetric(entry, "OldSiteEngagement", 0.0);
   recorder_->ExpectEntryMetric(entry, "DailyAverageVolume", 5);
 }
+
+IN_PROC_BROWSER_TEST_F(DisruptiveNotificationPermissionsRevocationBrowserTest,
+                       TestReportUserRegrant) {
+  auto* hcsm =
+      HostContentSettingsMapFactory::GetForProfile(browser()->profile());
+  GURL url = embedded_test_server()->GetURL("/title1.html");
+
+  // Set up a proposed revoked notification.
+  base::Value::Dict dict;
+  dict.Set(safety_hub::kRevokedStatusDictKeyStr, safety_hub::kRevokeStr);
+  dict.Set(safety_hub::kSiteEngagementStr, 0.0);
+  dict.Set(safety_hub::kDailyNotificationCountStr, 5);
+  dict.Set(safety_hub::kTimestampStr,
+           base::TimeToValue(base::Time::Now() - base::Days(3)));
+  hcsm->SetWebsiteSettingCustomScope(
+      ContentSettingsPattern::FromURLNoWildcard(url),
+      ContentSettingsPattern::Wildcard(),
+      ContentSettingsType::REVOKED_DISRUPTIVE_NOTIFICATION_PERMISSIONS,
+      base::Value(std::move(dict)));
+
+  // Visit the page.
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
+
+  // Allow notifications.
+  hcsm->SetContentSettingDefaultScope(
+      url, url, ContentSettingsType::NOTIFICATIONS, CONTENT_SETTING_ALLOW);
+
+  auto entries = recorder_->GetEntriesByName(
+      "SafetyHub.DisruptiveNotificationRevocations.UserRegrant");
+  ASSERT_EQ(1u, entries.size());
+  auto* entry = entries[0].get();
+  recorder_->ExpectEntryMetric(entry, "DaysSinceRevocation", 3);
+  recorder_->ExpectEntryMetric(entry, "NewSiteEngagement", 3.0);
+  recorder_->ExpectEntryMetric(entry, "OldSiteEngagement", 0.0);
+  recorder_->ExpectEntryMetric(entry, "DailyAverageVolume", 5);
+}
diff --git a/chrome/browser/ui/tabs/tab_strip_collection.cc b/chrome/browser/ui/tabs/tab_strip_collection.cc
index 3050500..a1a01b6 100644
--- a/chrome/browser/ui/tabs/tab_strip_collection.cc
+++ b/chrome/browser/ui/tabs/tab_strip_collection.cc
@@ -425,11 +425,30 @@
   parent_collection->MaybeRemoveCollection(split).reset();
 }
 
+void TabStripCollection::MoveSplit(split_tabs::SplitTabId split_id,
+                                   bool pinned) {
+  SplitTabCollection* split = GetSplitTabCollection(split_id);
+  std::unique_ptr<TabCollection> removed_collection =
+      split->GetParentCollection()->MaybeRemoveCollection(split);
+  if (pinned) {
+    pinned_collection()->AddCollection(std::move(removed_collection),
+                                       pinned_collection()->ChildCount());
+  } else {
+    unpinned_collection()->AddCollection(std::move(removed_collection), 0);
+  }
+}
+
 void TabStripCollection::ValidateData() const {
   CHECK(detached_group_collections_.empty());
   for (const auto& [_, group] : group_mapping_) {
     CHECK(group->ChildCount() > 0);
   }
+  for (const auto& [_, split] : split_mapping_) {
+    CHECK(split->ChildCount() >= 2);
+    for (auto child : split->GetTabsRecursive()) {
+      CHECK(split->GetSplitTabId() == child->GetSplit().value());
+    }
+  }
 }
 
 TabGroupTabCollection* TabStripCollection::MaybeAttachDetachedGroupCollection(
diff --git a/chrome/browser/ui/tabs/tab_strip_collection.h b/chrome/browser/ui/tabs/tab_strip_collection.h
index 534aed4..9206b40 100644
--- a/chrome/browser/ui/tabs/tab_strip_collection.h
+++ b/chrome/browser/ui/tabs/tab_strip_collection.h
@@ -106,6 +106,7 @@
                    const std::vector<TabInterface*>& tabs,
                    split_tabs::SplitTabVisualData visual_data);
   void Unsplit(split_tabs::SplitTabId split_id);
+  void MoveSplit(split_tabs::SplitTabId split_id, bool pinned);
 
   void ValidateData() const;
 
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 9c59fdf..e303ede 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -75,7 +75,6 @@
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/tabs/tab_strip_user_gesture_details.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
-#include "chrome/browser/ui/tabs/unpinned_tab_collection.h"
 #include "chrome/browser/ui/thumbnails/thumbnail_tab_helper.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/tabs/dragging/tab_drag_controller.h"
@@ -870,28 +869,11 @@
     tab_indices.push_back(i);
   }
 
-  const std::vector<MoveNotification> notifications =
-      PrepareTabsToMoveToIndex(tab_indices, to_index);
-
   // Remove all the tabs from the model.
-  contents_data_->MoveTabGroupTo(group, to_index);
-
-  UpdateSelectionModelForMoves(tab_indices, to_index);
-  ValidateTabStripModel();
-
-  for (auto notification : notifications) {
-    const int final_index = GetIndexOfTab(notification.tab);
-    tabs::TabInterface* tab = GetTabAtIndex(final_index);
-    if (notification.initial_index != final_index) {
-      SendMoveNotificationForTab(notification.initial_index, final_index, tab,
-                                 notification.selection_change);
-    }
-
-    if (notification.intial_group != tab->GetGroup()) {
-      TabGroupStateChanged(final_index, tab, notification.intial_group,
-                           tab->GetGroup());
-    }
-  }
+  MoveTabsWithNotifications(
+      tab_indices, to_index,
+      base::BindOnce(&tabs::TabStripCollection::MoveTabGroupTo,
+                     base::Unretained(contents_data_.get()), group, to_index));
 
   MoveTabGroup(group);
 }
@@ -1090,17 +1072,11 @@
   ReentrancyCheck reentrancy_check(&reentrancy_guard_);
   CHECK(ContainsIndex(index));
 
-  const tabs::TabInterface* const tab = GetTabAtIndex(index);
-
-  if (tab->IsPinned() == pinned) {
+  if (IsTabPinned(index) == pinned) {
     return index;
   }
 
-  const int final_index =
-      pinned ? IndexOfFirstNonPinnedTab() : IndexOfFirstNonPinnedTab() - 1;
-
-  MoveTabToIndexImpl(index, final_index, std::nullopt, pinned, false);
-  return final_index;
+  return SetTabPinnedImpl(index, pinned);
 }
 
 bool TabStripModel::IsTabPinned(int index) const {
@@ -2733,6 +2709,17 @@
 
 std::vector<int> TabStripModel::GetIndicesForCommand(int index) const {
   if (!IsTabSelected(index)) {
+    // When the context menu is triggered on an unselected tab that is part of
+    // the split, return all the tabs in that split so that context menu
+    // actions can operate on the entire split.
+    std::optional<split_tabs::SplitTabId> split = GetSplitForTab(index);
+    if (split.has_value()) {
+      gfx::Range index_range = GetIndexRangeOfSplit(split.value());
+      std::vector<int> split_indices(index_range.length());
+      std::iota(split_indices.begin(), split_indices.end(),
+                static_cast<int>(index_range.start()));
+      return split_indices;
+    }
     return {index};
   }
   const ui::ListSelectionModel::SelectedIndices& sel =
@@ -3680,31 +3667,12 @@
   CHECK(all_tabs_pinned || all_tabs_unpinned);
   CHECK(std::ranges::is_sorted(tab_indices));
 
-  const std::vector<MoveNotification> notifications =
-      PrepareTabsToMoveToIndex(tab_indices, destination_index);
-
   // Update `contents_data`.
-  contents_data_->MoveTabsRecursive(tab_indices, destination_index, group, pin);
-
-  UpdateSelectionModelForMoves(tab_indices, destination_index);
-
-  for (auto notification : notifications) {
-    const int final_index = GetIndexOfTab(notification.tab);
-    tabs::TabInterface* tab = GetTabAtIndex(final_index);
-    if (notification.initial_index != final_index) {
-      SendMoveNotificationForTab(notification.initial_index, final_index, tab,
-                                 notification.selection_change);
-    }
-
-    if (group_model_) {
-      if (notification.intial_group != tab->GetGroup()) {
-        TabGroupStateChanged(final_index, tab, notification.intial_group,
-                             tab->GetGroup());
-      }
-    }
-  }
-
-  ValidateTabStripModel();
+  MoveTabsWithNotifications(
+      tab_indices, destination_index,
+      base::BindOnce(&tabs::TabStripCollection::MoveTabsRecursive,
+                     base::Unretained(contents_data_.get()), tab_indices,
+                     destination_index, group, pin));
 }
 
 void TabStripModel::TabGroupStateChanged(
@@ -3964,8 +3932,8 @@
     }
 
     const tabs::TabInterface* const tab = GetTabAtIndex(move.first);
-    const MoveNotification notification = {move.first, tab->GetGroup(), tab,
-                                           selection};
+    const MoveNotification notification = {move.first, tab->GetGroup(),
+                                           tab->IsPinned(), tab, selection};
     notifications.push_back(notification);
   }
 
@@ -3973,22 +3941,116 @@
 }
 
 void TabStripModel::SetTabsPinned(std::vector<int> indices, bool pinned) {
+  // `indices` are given in ascending order. If pinning, process the indices as
+  // is, since when moving the tab at `index` to the left, this will not change
+  // the tabs that are pointed to by indices larger than `index`. Similarly, if
+  // unpinning, process the indices in descending order.
   if (!pinned) {
     std::reverse(indices.begin(), indices.end());
   }
 
-  for (int index : indices) {
+  // When we see a tab that is part of a split, do not move it until we look
+  // forward and see if all the tabs in the split are in indices. If so, move
+  // the whole split, otherwise move the tabs individually. Splits are
+  // contiguous, so once we stop seeing a split, we will not see it again,
+  // therefore we dont have to worry about processing the same split twice.
+  size_t next_i;
+  for (size_t i = 0; i < indices.size(); i = next_i) {
+    next_i = i + 1;
+
+    int index = indices[i];
     if (IsTabPinned(index) == pinned) {
       continue;
     }
 
-    const int non_pinned_tab_index = IndexOfFirstNonPinnedTab();
-    MoveTabToIndexImpl(index,
-                       pinned ? non_pinned_tab_index : non_pinned_tab_index - 1,
-                       std::nullopt, pinned, false);
+    tabs::TabInterface* tab = GetTabAtIndex(index);
+
+    if (tab->IsSplit()) {
+      tabs::SplitTabCollection* split =
+          contents_data_->GetSplitTabCollection(tab->GetSplit().value());
+
+      // Fast forward until we are no longer in the split.
+      while (next_i < indices.size() &&
+             next_i < i + split->TabCountRecursive() &&
+             GetTabAtIndex(indices[next_i])->GetSplit() == tab->GetSplit()) {
+        next_i++;
+      }
+
+      if (next_i == i + split->TabCountRecursive()) {
+        SetSplitPinnedImpl(split, pinned);
+      } else {
+        for (size_t j = i; j < next_i; j++) {
+          SetTabPinnedImpl(indices[j], pinned);
+        }
+      }
+    } else {
+      SetTabPinnedImpl(index, pinned);
+    }
   }
 }
 
+int TabStripModel::SetTabPinnedImpl(int index, bool pinned) {
+  const int final_index =
+      pinned ? IndexOfFirstNonPinnedTab() : IndexOfFirstNonPinnedTab() - 1;
+
+  MoveTabToIndexImpl(index, final_index, std::nullopt, pinned, false);
+  return final_index;
+}
+
+void TabStripModel::SetSplitPinnedImpl(tabs::SplitTabCollection* split,
+                                       bool pinned) {
+  std::vector<tabs::TabInterface*> tabs = split->GetTabsRecursive();
+  std::vector<int> tab_indices = {};
+  for (size_t index = GetIndexOfTab(tabs[0]); tabs::TabInterface* _ : tabs) {
+    tab_indices.push_back(index++);
+  }
+  const int destination_index = pinned
+                                    ? IndexOfFirstNonPinnedTab()
+                                    : IndexOfFirstNonPinnedTab() - tabs.size();
+
+  MoveTabsWithNotifications(
+      tab_indices, destination_index,
+      base::BindOnce(&tabs::TabStripCollection::MoveSplit,
+                     base::Unretained(contents_data_.get()),
+                     split->GetSplitTabId(), pinned));
+}
+
+void TabStripModel::MoveTabsWithNotifications(
+    std::vector<int> tab_indices,
+    int destination_index,
+    base::OnceClosure execute_tabs_move_operation) {
+  const std::vector<MoveNotification> notifications =
+      PrepareTabsToMoveToIndex(tab_indices, destination_index);
+
+  std::move(execute_tabs_move_operation).Run();
+
+  UpdateSelectionModelForMoves(tab_indices, destination_index);
+
+  for (auto notification : notifications) {
+    const int final_index = GetIndexOfTab(notification.tab);
+    tabs::TabInterface* tab = GetTabAtIndex(final_index);
+    if (notification.initial_index != final_index) {
+      SendMoveNotificationForTab(notification.initial_index, final_index, tab,
+                                 notification.selection_change);
+    }
+
+    if (group_model_) {
+      if (notification.intial_group != tab->GetGroup()) {
+        TabGroupStateChanged(final_index, tab, notification.intial_group,
+                             tab->GetGroup());
+      }
+    }
+
+    if (notification.initial_pinned != tab->IsPinned()) {
+      for (auto& observer : observers_) {
+        observer.TabPinnedStateChanged(this, tab->GetContents(), final_index);
+      }
+    }
+  }
+
+  ValidateTabStripModel();
+}
+
 // Sets the sound content setting for each site at the |indices|.
 void TabStripModel::SetSitesMuted(const std::vector<int>& indices,
                                   bool mute) const {
@@ -4404,7 +4466,7 @@
 }
 
 gfx::Range TabStripModel::GetIndexRangeOfSplit(
-    split_tabs::SplitTabId split_id) {
+    split_tabs::SplitTabId split_id) const {
   const tabs::SplitTabCollection* split =
       contents_data_->GetSplitTabCollection(split_id);
   if (!split) {
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index 97bc265..19e2227 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -58,6 +58,7 @@
 }
 
 namespace tabs {
+class SplitTabCollection;
 class TabStripCollection;
 class TabGroupTabCollection;
 }
@@ -789,6 +790,7 @@
   struct MoveNotification {
     int initial_index;
     std::optional<tab_groups::TabGroupId> intial_group;
+    bool initial_pinned;
     raw_ptr<const tabs::TabInterface> tab;
     TabStripSelectionChange selection_change;
   };
@@ -1083,9 +1085,24 @@
       int destination_index) const;
 
   // Changes the pinned state of all tabs at `indices`, moving them in the
-  // process if necessary.
+  // process if necessary. If indices contains all tabs in a split, the whole
+  // split is pinned/unpinned. Otherwise, the tabs will be individually
+  // processed, resulting in the split being unsplit.
   void SetTabsPinned(const std::vector<int> indices, bool pinned);
 
+  // Implementation for setting the pinned state of the tab at `index`.
+  int SetTabPinnedImpl(int indices, bool pinned);
+
+  // Changes the pinned state of a split collection, moving it in the process if
+  // necessary.
+  void SetSplitPinnedImpl(tabs::SplitTabCollection* split, bool pinned);
+
+  // Wrapper for bulk move operations to make them send out the appropriate
+  // change notifications.
+  void MoveTabsWithNotifications(std::vector<int> tab_indices,
+                                 int destination_index,
+                                 base::OnceClosure execute_tabs_move_operation);
+
   // Sets the sound content setting for each site at the |indices|.
   void SetSitesMuted(const std::vector<int>& indices, bool mute) const;
 
@@ -1127,7 +1144,7 @@
 
   // Returns [start, end) where the leftmost tab in the split has index start
   // and the rightmost tab in the split has index end - 1.
-  gfx::Range GetIndexRangeOfSplit(split_tabs::SplitTabId split_id);
+  gfx::Range GetIndexRangeOfSplit(split_tabs::SplitTabId split_id) const;
 
   // If inserting at `index` breaks a split, returns its id, otherwise nullopt.
   std::optional<split_tabs::SplitTabId> InsertionBreaksSplitContiguity(
diff --git a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
index 1e13829..dfa86b4 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
@@ -1742,6 +1742,72 @@
   EXPECT_TRUE(tabstrip()->empty());
 }
 
+TEST_F(TabStripModelTest, SplitTabPinning) {
+  for (bool split_is_selected : {true, false}) {
+    for (bool use_left_tab : {true, false}) {
+      ASSERT_NO_FATAL_FAILURE(
+          PrepareTabstripForSelectionTest(tabstrip(), 5, 1, {2}));
+      tabstrip()->AddToNewSplit({3}, split_tabs::SplitTabLayout::kHorizontal);
+      ASSERT_EQ("0p 1 2s 3s 4", GetTabStripStateString(tabstrip()));
+      if (!split_is_selected) {
+        tabstrip()->ActivateTabAt(1);
+      }
+
+      tabstrip()->ExecuteContextMenuCommand(2 + !use_left_tab,
+                                            TabStripModel::CommandTogglePinned);
+      EXPECT_EQ("0p 2ps 3ps 1 4", GetTabStripStateString(tabstrip()));
+
+      tabstrip()->ExecuteContextMenuCommand(1 + !use_left_tab,
+                                            TabStripModel::CommandTogglePinned);
+      EXPECT_EQ("0p 2s 3s 1 4", GetTabStripStateString(tabstrip()));
+
+      tabstrip()->CloseAllTabs();
+      EXPECT_TRUE(tabstrip()->empty());
+    }
+  }
+}
+
+TEST_F(TabStripModelTest, SplitTabPinningBulk) {
+  ASSERT_NO_FATAL_FAILURE(
+      PrepareTabstripForSelectionTest(tabstrip(), 12, 2, {4}));
+  tabstrip()->AddToNewSplit({5}, split_tabs::SplitTabLayout::kHorizontal);
+  ASSERT_EQ("0p 1p 2 3 4s 5s 6 7 8 9 10 11",
+            GetTabStripStateString(tabstrip()));
+  tabstrip()->ActivateTabAt(8);
+  tabstrip()->AddToNewSplit({9}, split_tabs::SplitTabLayout::kHorizontal);
+  ASSERT_EQ("0p 1p 2 3 4s 5s 6 7 8s 9s 10 11",
+            GetTabStripStateString(tabstrip()));
+  tabstrip()->SelectTabAt(0);
+  tabstrip()->SelectTabAt(2);
+  tabstrip()->SelectTabAt(4);
+  tabstrip()->SelectTabAt(5);
+  tabstrip()->SelectTabAt(7);
+  tabstrip()->SelectTabAt(10);
+  // tabs 0 2 4 5 7 8 9 10 should be selected
+  ASSERT_EQ(base::MakeFlatSet<size_t>(std::vector{0, 2, 4, 5, 7, 8, 9, 10}),
+            tabstrip()->selection_model().selected_indices());
+
+  // pin multiple selected tabs and splits
+  tabstrip()->ExecuteContextMenuCommand(
+      5, TabStripModel::CommandTogglePinned);  // tab 5
+  EXPECT_EQ("0p 1p 2p 4ps 5ps 7p 8ps 9ps 10p 3 6 11",
+            GetTabStripStateString(tabstrip()));
+
+  // unpin multiple selected tabs and splits
+  tabstrip()->DeselectTabAt(2);  // tab 2
+  tabstrip()->DeselectTabAt(8);  // tab 10
+  // tabs 0 4 5 7 8 9 should be selected
+  ASSERT_EQ(base::MakeFlatSet<size_t>(std::vector{0, 3, 4, 5, 6, 7}),
+            tabstrip()->selection_model().selected_indices());
+  tabstrip()->ExecuteContextMenuCommand(
+      0, TabStripModel::CommandTogglePinned);  // tab 0
+  EXPECT_EQ("1p 2p 10p 0 4s 5s 7 8s 9s 3 6 11",
+            GetTabStripStateString(tabstrip()));
+
+  tabstrip()->CloseAllTabs();
+  EXPECT_TRUE(tabstrip()->empty());
+}
+
 TEST_F(TabStripModelTest, AddToSplitInGroup) {
   // Create five tabs with two pinned.
   ASSERT_NO_FATAL_FAILURE(
diff --git a/chrome/browser/ui/views/accelerator_table.cc b/chrome/browser/ui/views/accelerator_table.cc
index 6db32fe..647b87e 100644
--- a/chrome/browser/ui/views/accelerator_table.cc
+++ b/chrome/browser/ui/views/accelerator_table.cc
@@ -252,7 +252,7 @@
 const AcceleratorMapping kTabGroupAcceleratorMap[] = {
     // Tab group commands.
     {ui::VKEY_C, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, IDC_ADD_NEW_TAB_TO_GROUP},
-    {ui::VKEY_D, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, IDC_CREATE_NEW_TAB_GROUP},
+    {ui::VKEY_P, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, IDC_CREATE_NEW_TAB_GROUP},
     {ui::VKEY_X, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, IDC_FOCUS_NEXT_TAB_GROUP},
     {ui::VKEY_Z, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, IDC_FOCUS_PREV_TAB_GROUP},
     {ui::VKEY_W, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, IDC_CLOSE_TAB_GROUP},
diff --git a/chrome/browser/ui/views/tabs/tab_strip_layout.cc b/chrome/browser/ui/views/tabs/tab_strip_layout.cc
index 94f16c5d..5e97e4b 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_layout.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_layout.cc
@@ -79,14 +79,27 @@
 
 int TabSizer::CalculateTabWidth(const TabWidthConstraints& tab) const {
   switch (domain_) {
-    case LayoutDomain::kInactiveWidthBelowActiveWidth:
-      return std::floor(gfx::Tween::FloatValueBetween(
+    case LayoutDomain::kInactiveWidthBelowActiveWidth: {
+      // First calculate the scaled width without including split minimums which
+      // will ensure two split tabs are the width of one regular tab.
+      const float scaled_width = std::floor(gfx::Tween::FloatValueBetween(
           space_fraction_available_, tab.GetMinimumWidth(),
-          tab.GetLayoutCrossoverWidth()));
-    case LayoutDomain::kInactiveWidthEqualsActiveWidth:
-      return std::floor(gfx::Tween::FloatValueBetween(
+          tab.GetLayoutCrossoverWidth(/*compensate_for_splits=*/true)));
+      // Ensure tabs are at least their min width when accounting for splits.
+      return std::max(scaled_width,
+                      tab.GetMinimumWidth(/*compensate_for_splits=*/true));
+    }
+    case LayoutDomain::kInactiveWidthEqualsActiveWidth: {
+      // First calculate the scaled width without including split crossover
+      // widths which will ensure two split tabs are the width of one regular
+      // tab.
+      const float scaled_width = std::floor(gfx::Tween::FloatValueBetween(
           space_fraction_available_, tab.GetLayoutCrossoverWidth(),
           tab.GetPreferredWidth()));
+      // Ensure tabs are at least their min width when accounting for splits.
+      return std::max(scaled_width, tab.GetLayoutCrossoverWidth(
+                                        /*compensate_for_splits=*/true));
+    }
   }
 }
 
diff --git a/chrome/browser/ui/views/tabs/tab_strip_layout_unittest.cc b/chrome/browser/ui/views/tabs/tab_strip_layout_unittest.cc
index c104b3a..c5876accf 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_layout_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_layout_unittest.cc
@@ -195,6 +195,17 @@
   EXPECT_EQ("116 115 213 212", TabWidthsAsString(bounds));
 }
 
+TEST(TabStripLayoutTest, MiddleWidthAndMinWidthSplitTab) {
+  TestCase test_case;
+  test_case.tabstrip_width = 140;
+  test_case.num_tabs = 4;
+  test_case.split_tabs = {0, 1};
+  test_case.active_index = 2;
+
+  auto bounds = CalculateTabBounds(test_case);
+  EXPECT_EQ("53 53 58 58", TabWidthsAsString(bounds));
+}
+
 TEST(TabStripLayoutTest, BelowMinActiveWidthOneTab) {
   TestCase test_case;
   test_case.tabstrip_width = 15;
@@ -257,6 +268,17 @@
             TabWidthsAsString(CalculateTabBounds(test_case)));
 }
 
+TEST(TabStripLayoutTest, BelowMinActiveWidthSplitTab) {
+  TestCase test_case;
+  test_case.tabstrip_width = 200;
+  test_case.num_tabs = 6;
+  test_case.split_tabs = {0, 1};
+  test_case.active_index = 2;
+
+  auto bounds = CalculateTabBounds(test_case);
+  EXPECT_EQ("50 50 56 53 53 53", TabWidthsAsString(bounds));
+}
+
 TEST(TabStripLayoutTest, NotEnoughSpace) {
   TestCase test_case;
   test_case.tabstrip_width = 10;
diff --git a/chrome/browser/ui/views/tabs/tab_width_constraints.cc b/chrome/browser/ui/views/tabs/tab_width_constraints.cc
index 27f7c93..20f4d2d 100644
--- a/chrome/browser/ui/views/tabs/tab_width_constraints.cc
+++ b/chrome/browser/ui/views/tabs/tab_width_constraints.cc
@@ -9,19 +9,36 @@
 #include "chrome/browser/ui/views/tabs/tab_strip_layout.h"
 #include "ui/gfx/animation/tween.h"
 
+namespace {
+// We try to render split tabs such that the whole split is the same size as a
+// regular tab but as tabs shrink, we end up with very condensed split tabs
+// while other tabs still have lots of padding. This constant was decided in
+// collaboration with UX to make the layout of split tabs look smooth as more
+// tabs are added to the tab strip. In practice, a split tab will appear the
+// same size as a regular tab until half of the split hits this constant at
+// which point a split tab will appear larger than a regular tab.
+constexpr int kSplitTabLayoutCrossoverWidth = 53;
+}  // namespace
+
 TabWidthConstraints::TabWidthConstraints(const TabLayoutState& state,
                                          const TabSizeInfo& size_info)
     : state_(state), size_info_(size_info) {}
 
-float TabWidthConstraints::GetMinimumWidth() const {
-  const float min_width = state_.active() == TabActive::kActive
-                              ? size_info_.min_active_width
-                              : size_info_.min_inactive_width;
+float TabWidthConstraints::GetMinimumWidth(bool compensate_for_splits) const {
+  const bool use_active_width =
+      state_.active() == TabActive::kActive ||
+      (compensate_for_splits && state_.split().has_value());
+  const float min_width = use_active_width ? size_info_.min_active_width
+                                           : size_info_.min_inactive_width;
   return TransformForPinnednessAndOpenness(min_width);
 }
 
-float TabWidthConstraints::GetLayoutCrossoverWidth() const {
-  return TransformForPinnednessAndOpenness(size_info_.min_active_width);
+float TabWidthConstraints::GetLayoutCrossoverWidth(
+    bool compensate_for_splits) const {
+  return TransformForPinnednessAndOpenness(compensate_for_splits &&
+                                                   state_.split().has_value()
+                                               ? kSplitTabLayoutCrossoverWidth
+                                               : size_info_.min_active_width);
 }
 
 float TabWidthConstraints::GetPreferredWidth() const {
diff --git a/chrome/browser/ui/views/tabs/tab_width_constraints.h b/chrome/browser/ui/views/tabs/tab_width_constraints.h
index 627fd935..dc11ddb 100644
--- a/chrome/browser/ui/views/tabs/tab_width_constraints.h
+++ b/chrome/browser/ui/views/tabs/tab_width_constraints.h
@@ -15,13 +15,21 @@
                       const TabSizeInfo& size_info);
 
   // The smallest width this tab should ever have.
-  float GetMinimumWidth() const;
+  //
+  // Split tabs will have a different min width. When `compensate_for_splits`
+  // is set to true and the tab is split, return the split tab minimum width.
+  float GetMinimumWidth(bool compensate_for_splits = false) const;
 
   // The width this tab should have at the crossover point between the
-  // tabstrip's two layout domains.  Above this width, inactive tabs have the
+  // tabstrip's two layout domains. Above this width, inactive tabs have the
   // same width as active tabs.  Below this width, inactive tabs are smaller
   // than active tabs.
-  float GetLayoutCrossoverWidth() const;
+  //
+  // Split tabs will have a different crossover width because they should stop
+  // shrinking before they reach the crossover width. When
+  // `compensate_for_splits` is set to true and the tab is split, return the
+  // split tab layout crossover width.
+  float GetLayoutCrossoverWidth(bool compensate_for_splits = false) const;
 
   // The width this tab would like to have, if space is available.
   float GetPreferredWidth() const;
diff --git a/chrome/browser/ui/webui/browser_switch/browser_switch_ui.cc b/chrome/browser/ui/webui/browser_switch/browser_switch_ui.cc
index 7d23fad..5dfad95 100644
--- a/chrome/browser/ui/webui/browser_switch/browser_switch_ui.cc
+++ b/chrome/browser/ui/webui/browser_switch/browser_switch_ui.cc
@@ -544,6 +544,11 @@
   ResolveJavascriptCallback(args[0], base::Value(service->prefs().IsEnabled()));
 }
 
+bool BrowserSwitchUIConfig::IsWebUIEnabled(
+    content::BrowserContext* browser_context) {
+  return browser_context && !browser_context->IsOffTheRecord();
+}
+
 BrowserSwitchUI::BrowserSwitchUI(content::WebUI* web_ui)
     : WebUIController(web_ui) {
   web_ui->AddMessageHandler(std::make_unique<BrowserSwitchHandler>());
diff --git a/chrome/browser/ui/webui/browser_switch/browser_switch_ui.h b/chrome/browser/ui/webui/browser_switch/browser_switch_ui.h
index de642457..d3d28109 100644
--- a/chrome/browser/ui/webui/browser_switch/browser_switch_ui.h
+++ b/chrome/browser/ui/webui/browser_switch/browser_switch_ui.h
@@ -19,6 +19,9 @@
   BrowserSwitchUIConfig()
       : DefaultWebUIConfig(content::kChromeUIScheme,
                            chrome::kChromeUIBrowserSwitchHost) {}
+
+  // WebUIConfig:
+  bool IsWebUIEnabled(content::BrowserContext* browser_context) override;
 };
 
 class BrowserSwitchUI : public content::WebUIController {
diff --git a/chrome/browser/ui/webui/on_device_internals/on_device_internals_page_handler.cc b/chrome/browser/ui/webui/on_device_internals/on_device_internals_page_handler.cc
index 1b45702..e213829 100644
--- a/chrome/browser/ui/webui/on_device_internals/on_device_internals_page_handler.cc
+++ b/chrome/browser/ui/webui/on_device_internals/on_device_internals_page_handler.cc
@@ -49,13 +49,6 @@
     model_paths.weights = model_path;
   }
 
-  if (optimization_guide::features::ForceCpuBackendForOnDeviceModel()) {
-    // TODO(crbug.com/401011041): Pass the model via a file descriptor.
-    on_device_model::ModelAssets assets;
-    assets.weights_path = model_paths.weights;
-    return assets;
-  }
-
   return on_device_model::LoadModelAssets(model_paths);
 }
 #endif
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index 8831f7c6..f2cc5ec 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -47,6 +47,8 @@
     "commands/launch_web_app_command.h",
     "commands/manifest_update_check_command.cc",
     "commands/manifest_update_check_command.h",
+    "commands/manifest_update_check_command_v2.cc",
+    "commands/manifest_update_check_command_v2.h",
     "commands/manifest_update_finalize_command.cc",
     "commands/manifest_update_finalize_command.h",
     "commands/navigate_and_trigger_install_dialog_command.cc",
diff --git a/chrome/browser/web_applications/commands/manifest_update_check_command_v2.cc b/chrome/browser/web_applications/commands/manifest_update_check_command_v2.cc
new file mode 100644
index 0000000..4046be93
--- /dev/null
+++ b/chrome/browser/web_applications/commands/manifest_update_check_command_v2.cc
@@ -0,0 +1,114 @@
+// 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/web_applications/commands/manifest_update_check_command_v2.h"
+
+#include "base/feature_list.h"
+#include "base/functional/callback_forward.h"
+#include "base/i18n/time_formatting.h"
+#include "base/notreached.h"
+#include "base/strings/to_string.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/web_applications/callback_utils.h"
+#include "chrome/browser/web_applications/generated_icon_fix_util.h"
+#include "chrome/browser/web_applications/locks/app_lock.h"
+#include "chrome/browser/web_applications/manifest_update_manager.h"
+#include "chrome/browser/web_applications/web_app.h"
+#include "chrome/browser/web_applications/web_app_helpers.h"
+#include "chrome/browser/web_applications/web_app_icon_operations.h"
+#include "chrome/browser/web_applications/web_app_install_utils.h"
+#include "chrome/browser/web_applications/web_app_registrar.h"
+#include "chrome/browser/web_applications/web_app_registry_update.h"
+#include "chrome/browser/web_applications/web_app_sync_bridge.h"
+#include "chrome/browser/web_applications/web_app_ui_manager.h"
+#include "chrome/browser/web_applications/web_contents/web_app_icon_downloader.h"
+#include "chrome/common/chrome_features.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace web_app {
+
+ManifestUpdateCheckCommandV2::ManifestUpdateCheckCommandV2(
+    const GURL& url,
+    const webapps::AppId& app_id,
+    base::Time check_time,
+    base::WeakPtr<content::WebContents> web_contents,
+    CompletedCallback callback,
+    std::unique_ptr<WebAppDataRetriever> data_retriever,
+    std::unique_ptr<WebAppIconDownloader> icon_downloader)
+    : WebAppCommand<AppLock,
+                    ManifestUpdateCheckResult,
+                    std::unique_ptr<WebAppInstallInfo>>(
+          "ManifestUpdateCheckCommandV2",
+          AppLockDescription(app_id),
+          std::move(callback),
+          /*args_for_shutdown=*/
+          std::make_tuple(ManifestUpdateCheckResult::kSystemShutdown,
+                          /*new_install_info=*/nullptr)),
+      url_(url),
+      app_id_(app_id),
+      check_time_(check_time),
+      web_contents_(web_contents),
+      data_retriever_(std::move(data_retriever)),
+      icon_downloader_(std::move(icon_downloader)) {
+  GetMutableDebugValue().Set("app_id", app_id_);
+  GetMutableDebugValue().Set("url", url_.spec());
+  GetMutableDebugValue().Set("stage", base::ToString(stage_));
+  GetMutableDebugValue().Set("check_time",
+                             base::TimeFormatFriendlyDateAndTime(check_time_));
+}
+
+ManifestUpdateCheckCommandV2::~ManifestUpdateCheckCommandV2() = default;
+
+void ManifestUpdateCheckCommandV2::StartWithLock(
+    std::unique_ptr<AppLock> lock) {
+  lock_ = std::move(lock);
+
+  if (IsWebContentsDestroyed()) {
+    CompleteCommandAndSelfDestruct(
+        ManifestUpdateCheckResult::kWebContentsDestroyed);
+    return;
+  }
+  Observe(web_contents_.get());
+}
+
+bool ManifestUpdateCheckCommandV2::IsWebContentsDestroyed() {
+  return !web_contents_ || web_contents_->IsBeingDestroyed();
+}
+
+void ManifestUpdateCheckCommandV2::CompleteCommandAndSelfDestruct(
+    ManifestUpdateCheckResult check_result) {
+  GetMutableDebugValue().Set("result", base::ToString(check_result));
+
+  CommandResult command_result = [&] {
+    switch (check_result) {
+      case ManifestUpdateCheckResult::kAppUpdateNeeded:
+      case ManifestUpdateCheckResult::kAppIdentityUpdateRejectedAndUninstalled:
+      case ManifestUpdateCheckResult::kAppUpToDate:
+        return CommandResult::kSuccess;
+      case ManifestUpdateCheckResult::kAppIdMismatch:
+      case ManifestUpdateCheckResult::kAppNotEligible:
+      case ManifestUpdateCheckResult::kIconDownloadFailed:
+      case ManifestUpdateCheckResult::kIconReadFromDiskFailed:
+      case ManifestUpdateCheckResult::kWebContentsDestroyed:
+      case ManifestUpdateCheckResult::kCancelledDueToMainFrameNavigation:
+        return CommandResult::kFailure;
+      case ManifestUpdateCheckResult::kSystemShutdown:
+        NOTREACHED() << "This should be handled by OnShutdown()";
+    }
+  }();
+
+  Observe(nullptr);
+  CompleteAndSelfDestruct(
+      command_result, check_result,
+      check_result == ManifestUpdateCheckResult::kAppUpdateNeeded
+          ? std::move(new_install_info_)
+          : nullptr);
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/commands/manifest_update_check_command_v2.h b/chrome/browser/web_applications/commands/manifest_update_check_command_v2.h
new file mode 100644
index 0000000..e5d9c9ff7
--- /dev/null
+++ b/chrome/browser/web_applications/commands/manifest_update_check_command_v2.h
@@ -0,0 +1,97 @@
+// 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_WEB_APPLICATIONS_COMMANDS_MANIFEST_UPDATE_CHECK_COMMAND_V2_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_COMMANDS_MANIFEST_UPDATE_CHECK_COMMAND_V2_H_
+
+#include "chrome/browser/web_applications/commands/web_app_command.h"
+#include "chrome/browser/web_applications/locks/app_lock.h"
+#include "chrome/browser/web_applications/manifest_update_utils.h"
+#include "chrome/browser/web_applications/web_contents/web_app_data_retriever.h"
+
+class GURL;
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+namespace web_app {
+
+struct WebAppInstallInfo;
+
+// Documentation: docs/webapps/manifest_update_process.md
+//
+// Checks whether the installed web app associated with a given WebContents has
+// out of date manifest data and what to update it to.
+//
+// High level procedure for this command:
+// - Download new manifest data from site including external resources (such as
+//   icon bitmaps only if the url changes from the saved information).
+// - Load existing manifest data from disk including external resources.
+// - Diff manifest data.
+// - Resolve any changes to app identity by confirming the change with the user,
+//   silently allowing them, or reverting them.
+// - Return back to the caller to schedule applying the changes back to disk.
+//
+// TODO(crbug.com/414851433): Rename this to ManifestUpdateCheckCommand and
+// remove existing ManifestUpdateCheckCommand.
+class ManifestUpdateCheckCommandV2
+    : public WebAppCommand<AppLock,
+                           ManifestUpdateCheckResult,
+                           std::unique_ptr<WebAppInstallInfo>>,
+      public content::WebContentsObserver {
+ public:
+  using CompletedCallback = base::OnceCallback<void(
+      ManifestUpdateCheckResult check_result,
+      std::unique_ptr<WebAppInstallInfo> new_install_info)>;
+
+  ManifestUpdateCheckCommandV2(
+      const GURL& url,
+      const webapps::AppId& app_id,
+      base::Time check_time,
+      base::WeakPtr<content::WebContents> web_contents,
+      CompletedCallback callback,
+      std::unique_ptr<WebAppDataRetriever> data_retriever,
+      std::unique_ptr<WebAppIconDownloader> icon_downloader);
+
+  ~ManifestUpdateCheckCommandV2() override;
+
+ protected:
+  // WebAppCommand:
+  void StartWithLock(std::unique_ptr<AppLock> lock) override;
+
+ private:
+  // Stage: Update check complete.
+  // (ManifestUpdateCheckStage::kComplete)
+  bool IsWebContentsDestroyed();
+  void CompleteCommandAndSelfDestruct(ManifestUpdateCheckResult check_result);
+
+  base::WeakPtr<ManifestUpdateCheckCommandV2> GetWeakPtr() {
+    return weak_factory_.GetWeakPtr();
+  }
+
+  // Manifest update check request parameters.
+  const GURL url_;
+  const webapps::AppId app_id_;
+  base::Time check_time_;
+
+  // Resources and helpers used to fetch manifest data.
+  std::unique_ptr<AppLock> lock_;
+  base::WeakPtr<content::WebContents> web_contents_;
+  std::unique_ptr<WebAppDataRetriever> data_retriever_;
+  std::unique_ptr<WebAppIconDownloader> icon_downloader_;
+
+  // Temporary variables stored here while the update check progresses
+  // asynchronously.
+  std::unique_ptr<WebAppInstallInfo> new_install_info_;
+
+  // Debug info.
+  ManifestUpdateCheckStage stage_ = ManifestUpdateCheckStage::kPendingAppLock;
+
+  base::WeakPtrFactory<ManifestUpdateCheckCommandV2> weak_factory_{this};
+};
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMMANDS_MANIFEST_UPDATE_CHECK_COMMAND_V2_H_
diff --git a/chrome/browser/web_applications/manifest_update_manager.cc b/chrome/browser/web_applications/manifest_update_manager.cc
index 3143ac52..d5a80f94 100644
--- a/chrome/browser/web_applications/manifest_update_manager.cc
+++ b/chrome/browser/web_applications/manifest_update_manager.cc
@@ -42,6 +42,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "content/public/common/content_features.h"
 #include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom-shared.h"
 
 #if BUILDFLAG(IS_CHROMEOS)
@@ -312,10 +313,20 @@
   if (load_finished_callback_)
     std::move(load_finished_callback_).Run();
 
-  provider_->scheduler().ScheduleManifestUpdateCheck(
-      url, app_id, check_time, web_contents,
+  auto app_window_close_await_callback =
       base::BindOnce(&ManifestUpdateManager::OnManifestCheckAwaitAppWindowClose,
-                     weak_factory_.GetWeakPtr(), web_contents, url, app_id));
+                     weak_factory_.GetWeakPtr(), web_contents, url, app_id);
+  if (base::FeatureList::IsEnabled(features::kWebAppEnableUpdateTokenParsing)) {
+    // fill in here to use the manifest_update_check_command_v2.cc or .h instead
+    // of the manifest_update_check_command.cc
+    provider_->scheduler().ScheduleManifestUpdateCheckV2(
+        url, app_id, check_time, web_contents,
+        std::move(app_window_close_await_callback));
+  } else {
+    provider_->scheduler().ScheduleManifestUpdateCheck(
+        url, app_id, check_time, web_contents,
+        std::move(app_window_close_await_callback));
+  }
 }
 
 void ManifestUpdateManager::OnManifestCheckAwaitAppWindowClose(
diff --git a/chrome/browser/web_applications/web_app_command_scheduler.cc b/chrome/browser/web_applications/web_app_command_scheduler.cc
index fe4340a..b50a575 100644
--- a/chrome/browser/web_applications/web_app_command_scheduler.cc
+++ b/chrome/browser/web_applications/web_app_command_scheduler.cc
@@ -38,6 +38,7 @@
 #include "chrome/browser/web_applications/commands/internal/callback_command.h"
 #include "chrome/browser/web_applications/commands/launch_web_app_command.h"
 #include "chrome/browser/web_applications/commands/manifest_update_check_command.h"
+#include "chrome/browser/web_applications/commands/manifest_update_check_command_v2.h"
 #include "chrome/browser/web_applications/commands/manifest_update_finalize_command.h"
 #include "chrome/browser/web_applications/commands/navigate_and_trigger_install_dialog_command.h"
 #include "chrome/browser/web_applications/commands/os_integration_synchronize_command.h"
@@ -218,6 +219,21 @@
       location);
 }
 
+void WebAppCommandScheduler::ScheduleManifestUpdateCheckV2(
+    const GURL& url,
+    const webapps::AppId& app_id,
+    base::Time check_time,
+    base::WeakPtr<content::WebContents> contents,
+    ManifestUpdateCheckCommandV2::CompletedCallback callback,
+    const base::Location& location) {
+  provider_->command_manager().ScheduleCommand(
+      std::make_unique<ManifestUpdateCheckCommandV2>(
+          url, app_id, check_time, contents, std::move(callback),
+          provider_->web_contents_manager().CreateDataRetriever(),
+          provider_->web_contents_manager().CreateIconDownloader()),
+      location);
+}
+
 void WebAppCommandScheduler::ScheduleManifestUpdateFinalize(
     const GURL& url,
     const webapps::AppId& app_id,
diff --git a/chrome/browser/web_applications/web_app_command_scheduler.h b/chrome/browser/web_applications/web_app_command_scheduler.h
index ebb3c9a9..2affcee 100644
--- a/chrome/browser/web_applications/web_app_command_scheduler.h
+++ b/chrome/browser/web_applications/web_app_command_scheduler.h
@@ -196,6 +196,19 @@
       ManifestUpdateCheckCompletedCallback callback,
       const base::Location& location = FROM_HERE);
 
+  // Schedule a command that performs fetching data from the manifest
+  // for a manifest update. This is part of the predicatable app updating
+  // algorithm that will be implemented. After implementation, this should
+  // replace the current ScheduleManifestUpdateCheck.
+  // For more details, go/predictable-app-updating-design-doc.
+  void ScheduleManifestUpdateCheckV2(
+      const GURL& url,
+      const webapps::AppId& app_id,
+      base::Time check_time,
+      base::WeakPtr<content::WebContents> contents,
+      ManifestUpdateCheckCompletedCallback callback,
+      const base::Location& location = FROM_HERE);
+
   // Schedules a command that performs the data writes into the DB for
   // completion of the manifest update. `install_info` must be non-null.
   void ScheduleManifestUpdateFinalize(
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index 856d683..2121e42 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1746034701-c3986fff43b78cdffaecce23fba8cd10a98d85ea-2d4e54256e5779cf52300e0f51e51b3cce03ec0d.profdata
+chrome-android64-main-1746044609-24b97d12ffd181c7270a89ff64582030f8202794-15f70a334873425aa887d4cdb216796f676c015a.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index f7d0ae4..c5b90f4 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1746035971-cc87b5a77f9bcc40856d76695950701912e5e589-b23738f45a2bc90b4fca6b0754754deaa3612f40.profdata
+chrome-mac-arm-main-1746050330-29bcdbb49f3e79fe3a8f9df22753151932f89e38-f56a6acf56996a56ef31a581d16665e62070b42d.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index d3a2f2c..202c165 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1746013960-3d72dfe3cb4d105abbf4d83e79fcebfbd13462f3-85c17e9abc4ed443ef6794a715b5e9430d7ab21c.profdata
+chrome-mac-main-1746035971-b05a325c069ae4e48a2924ad4bbb2138b3bca702-b23738f45a2bc90b4fca6b0754754deaa3612f40.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index b5f992e..667b77d 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1746013960-7fee52b1664f260401701c32ecd10484ec177f0a-85c17e9abc4ed443ef6794a715b5e9430d7ab21c.profdata
+chrome-win-arm64-main-1746035971-4213c9308da5133e6bb3567981d16a60b087804b-b23738f45a2bc90b4fca6b0754754deaa3612f40.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 155dffb..091f2aa 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1745020565-0275fe9aa9a2c688a86151be5e597153b33b4e4b-91dd848f4ebdc2b1931e9d89f78f1ff270c0e43a.profdata
+chrome-win32-main-1746025195-882f8772ccd05493ec80fcf6548955fc1f9bb170-ab50c042d650061c65e5a9bceae223f7647b0df9.profdata
diff --git a/chrome/release_scripts b/chrome/release_scripts
index a1c867d..6ad235a 160000
--- a/chrome/release_scripts
+++ b/chrome/release_scripts
@@ -1 +1 @@
-Subproject commit a1c867ddbae2844edbaa27f2b5c8f063d04fbbbd
+Subproject commit 6ad235a921b16b76e60316629f799e4fef593769
diff --git a/chrome/renderer/accessibility/read_anything/read_anything_app_controller.cc b/chrome/renderer/accessibility/read_anything/read_anything_app_controller.cc
index 8950f6b..59338eda 100644
--- a/chrome/renderer/accessibility/read_anything/read_anything_app_controller.cc
+++ b/chrome/renderer/accessibility/read_anything/read_anything_app_controller.cc
@@ -616,7 +616,7 @@
   post_user_entry_draw_timer_->Stop();
 
   model_.SetActiveTreeId(tree_id);
-  model_.SetUkmSourceId(ukm_source_id);
+  model_.SetUkmSourceIdForTree(tree_id, ukm_source_id);
   model_.set_is_pdf(is_pdf);
 
   if (IsReadAloudEnabled() && read_aloud_model_.speech_playing()) {
diff --git a/chrome/renderer/accessibility/read_anything/read_anything_app_controller_browsertest.cc b/chrome/renderer/accessibility/read_anything/read_anything_app_controller_browsertest.cc
index f36aef5..2dcece42c 100644
--- a/chrome/renderer/accessibility/read_anything/read_anything_app_controller_browsertest.cc
+++ b/chrome/renderer/accessibility/read_anything/read_anything_app_controller_browsertest.cc
@@ -4133,11 +4133,12 @@
   EXPECT_EQ(node_ids.size(), 1u);
 
   // Storing as a separate variable so we don't need to cast every time.
-  int segment1_length = (int)segment1.length();
-  int segment2_length = (int)segment2.length();
-  int segment3_length = (int)segment3.length();
-  int segment4_partial_length = (int)segment4.length();
-  int segment4_full_length = (int)segment4.length() + (int)node2_text.length();
+  int segment1_length = static_cast<int>(segment1.length());
+  int segment2_length = static_cast<int>(segment2.length());
+  int segment3_length = static_cast<int>(segment3.length());
+  int segment4_partial_length = static_cast<int>(segment4.length());
+  int segment4_full_length =
+      static_cast<int>(segment4.length() + node2_text.length());
 
   // For the first node in the first segment, the returned index should equal
   // the passed parameter.
diff --git a/chrome/renderer/accessibility/read_anything/read_anything_app_model.cc b/chrome/renderer/accessibility/read_anything/read_anything_app_model.cc
index 2ac2347..6e8d88c 100644
--- a/chrome/renderer/accessibility/read_anything/read_anything_app_model.cc
+++ b/chrome/renderer/accessibility/read_anything/read_anything_app_model.cc
@@ -531,6 +531,13 @@
     tree_infos_.emplace(
         tree_id, std::make_unique<AXTreeInfo>(
                      std::make_unique<ui::AXTreeManager>(std::move(new_tree))));
+    // If we previously received UKM source info for this tree_id, set the
+    // UKM source now that the tree information has been added to tree_infos_.
+    if (tree_id == active_tree_id_ && pending_ukm_sources_.count(tree_id) > 0) {
+      ukm::SourceId ukm_source_id = pending_ukm_sources_[tree_id];
+      pending_ukm_sources_.erase(tree_id);
+      SetUkmSourceId(ukm_source_id);
+    }
   }
 
   // If a tree update on the active tree is received while distillation is in
@@ -605,6 +612,21 @@
   return ukm::kInvalidSourceId;
 }
 
+void ReadAnythingAppModel::SetUkmSourceIdForTree(const ui::AXTreeID& tree,
+                                                 ukm::SourceId ukm_source_id) {
+  // We may receive an OnActiveAXTreeIDChanged event on a tree before we've
+  // received an AccessibilityEventReceived event adding the tree to
+  // tree_infos_. When this happens, we should keep track of the ukm_source_id,
+  // and later, if the tree is added to tree_infos_ while it's still active,
+  // we can try again to set the ukm source.
+  if (!base::Contains(tree_infos_, active_tree_id_)) {
+    pending_ukm_sources_[tree] = ukm_source_id;
+    return;
+  }
+
+  SetUkmSourceId(ukm_source_id);
+}
+
 void ReadAnythingAppModel::SetUkmSourceId(ukm::SourceId ukm_source_id) {
   if (!base::Contains(tree_infos_, active_tree_id_)) {
     return;
diff --git a/chrome/renderer/accessibility/read_anything/read_anything_app_model.h b/chrome/renderer/accessibility/read_anything/read_anything_app_model.h
index a6d8181..4d2c0e7 100644
--- a/chrome/renderer/accessibility/read_anything/read_anything_app_model.h
+++ b/chrome/renderer/accessibility/read_anything/read_anything_app_model.h
@@ -234,7 +234,8 @@
   void SetActiveTreeId(ui::AXTreeID active_tree_id);
 
   ukm::SourceId GetUkmSourceId() const;
-  void SetUkmSourceId(ukm::SourceId ukm_source_id);
+  void SetUkmSourceIdForTree(const ui::AXTreeID& tree,
+                             ukm::SourceId ukm_source_id);
 
   int GetNumSelections() const;
   void SetNumSelections(int num_selections);
@@ -362,6 +363,7 @@
   void OnTreeChangeTimerTriggered();
 
   void SetFontSize(double font_size, int increment = 0);
+  void SetUkmSourceId(ukm::SourceId ukm_source_id);
 
   // State.
   std::map<ui::AXTreeID, std::unique_ptr<AXTreeInfo>> tree_infos_;
@@ -466,6 +468,8 @@
 
   bool will_hide_ = false;
 
+  std::map<ui::AXTreeID, ukm::SourceId> pending_ukm_sources_;
+
   // List of observers of model state changes.
   base::ObserverList<ModelObserver, /*check_empty=*/true> observers_;
 
diff --git a/chrome/renderer/accessibility/read_anything/read_anything_app_model_browsertest.cc b/chrome/renderer/accessibility/read_anything/read_anything_app_model_browsertest.cc
index 9d976553..3b0b0f5 100644
--- a/chrome/renderer/accessibility/read_anything/read_anything_app_model_browsertest.cc
+++ b/chrome/renderer/accessibility/read_anything/read_anything_app_model_browsertest.cc
@@ -1899,3 +1899,49 @@
   model().AccessibilityEventReceived(tree_id_, updates, events, false);
   ASSERT_FALSE(model().reset_draw_timer());
 }
+
+TEST_F(ReadAnythingAppModelTest, SetUkmSourceId_TreeExists) {
+  ui::AXTreeID tree_id = ui::AXTreeID::CreateNewAXTreeID();
+  ui::AXTreeUpdate update;
+  test::SetUpdateTreeID(&update, tree_id);
+  ui::AXNodeData node1;
+  static constexpr int kId = 1;
+  node1.id = kId;
+  update.root_id = node1.id;
+  update.nodes = {std::move(node1)};
+
+  ukm::SourceId source_id = ukm::AssignNewSourceId();
+
+  // The UKM source should be invalid before the tree is made active.
+  AccessibilityEventReceived({std::move(update)});
+  EXPECT_EQ(model().GetUkmSourceId(), ukm::kInvalidSourceId);
+
+  // After the tree is made active, the UKM source should be valid.
+  model().SetActiveTreeId(tree_id);
+  model().SetUkmSourceIdForTree(tree_id, source_id);
+  EXPECT_EQ(model().GetUkmSourceId(), source_id);
+}
+
+TEST_F(ReadAnythingAppModelTest, SetUkmSourceId_TreeDoesNotExistInitially) {
+  ui::AXTreeID tree_id = ui::AXTreeID::CreateNewAXTreeID();
+  ui::AXTreeUpdate update;
+  test::SetUpdateTreeID(&update, tree_id);
+  ui::AXNodeData node1;
+  static constexpr int kId = 1;
+  node1.id = kId;
+  update.root_id = node1.id;
+  update.nodes = {std::move(node1)};
+
+  ukm::SourceId source_id = ukm::AssignNewSourceId();
+
+  // The UKM source should be invalid when the tree is made active but before
+  // a representation of it is actually stored.
+  model().SetActiveTreeId(tree_id);
+  model().SetUkmSourceIdForTree(tree_id, source_id);
+  EXPECT_EQ(model().GetUkmSourceId(), ukm::kInvalidSourceId);
+
+  // The UKM source should be valid once an accessibility event is received for
+  // the active tree.
+  AccessibilityEventReceived({std::move(update)});
+  EXPECT_EQ(model().GetUkmSourceId(), source_id);
+}
diff --git a/chrome/test/data/webui/bookmarks/reducers_test.ts b/chrome/test/data/webui/bookmarks/reducers_test.ts
index cef3923..b0fa07e 100644
--- a/chrome/test/data/webui/bookmarks/reducers_test.ts
+++ b/chrome/test/data/webui/bookmarks/reducers_test.ts
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import type {BookmarksPageState, FolderOpenState, NodeMap, SelectFolderAction, SelectionState, SelectItemsAction} from 'chrome://bookmarks/bookmarks.js';
-import {changeFolderOpen, clearSearch, createBookmark, createEmptyState, deselectItems, editBookmark, getDisplayedList, isShowingSearch, moveBookmark, reduceAction, removeBookmark, reorderChildren, selectFolder, setSearchResults, setSearchTerm, updateAnchor, updateFolderOpenState, updateNodes, updateSelectedFolder, updateSelection} from 'chrome://bookmarks/bookmarks.js';
+import type {BookmarksPageState, FolderOpenState, NodeMap, SelectionState, SelectItemsAction} from 'chrome://bookmarks/bookmarks.js';
+import {changeFolderOpen, clearSearch, createBookmark, createEmptyState, deselectItems, editBookmark, getDisplayedList, isShowingSearch, moveBookmark, reduceAction, removeBookmark, reorderChildren, selectFolder, setSearchResults, setSearchTerm, updateAnchor, updateFolderOpenState, updateNodes, updateSelection} from 'chrome://bookmarks/bookmarks.js';
 import type {Action} from 'chrome://resources/js/store.js';
 import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 
@@ -212,12 +212,13 @@
 });
 
 suite('selected folder', function() {
-  let nodes: NodeMap;
-  let selectedFolder: string;
-  let action: SelectFolderAction;
+  let state: BookmarksPageState;
+  let action: Action;
 
   setup(function() {
-    nodes = testTree(createFolder('1', [
+    // Test selected folder using a full state.
+    state = createEmptyState();
+    state.nodes = testTree(createFolder('1', [
       createFolder(
           '2',
           [
@@ -225,43 +226,42 @@
             createFolder('4', []),
           ]),
     ]));
-
-    selectedFolder = '1';
+    state.selectedFolder = '1';
   });
 
   test('updates from selectFolder action', function() {
     action = selectFolder('2')!;
-    selectedFolder = updateSelectedFolder(selectedFolder, action, nodes);
-    assertEquals('2', selectedFolder);
+    state = reduceAction(state, action);
+    assertEquals('2', state.selectedFolder);
   });
 
   test('updates when parent of selected folder is closed', function() {
     action = selectFolder('2')!;
-    selectedFolder = updateSelectedFolder(selectedFolder, action, nodes);
+    state = reduceAction(state, action);
 
     action = changeFolderOpen('1', false);
-    selectedFolder = updateSelectedFolder(selectedFolder, action, nodes);
-    assertEquals('1', selectedFolder);
+    state = reduceAction(state, action);
+    assertEquals('1', state.selectedFolder);
   });
 
   test('selects ancestor when selected folder is deleted', function() {
     action = selectFolder('3')!;
-    selectedFolder = updateSelectedFolder(selectedFolder, action, nodes);
+    state = reduceAction(state, action);
 
     // Delete the selected folder:
-    action = removeBookmark('3', '2', 0, nodes);
-    selectedFolder = updateSelectedFolder(selectedFolder, action, nodes);
+    action = removeBookmark('3', '2', 0, state.nodes);
+    state = reduceAction(state, action);
 
-    assertEquals('2', selectedFolder);
+    assertEquals('2', state.selectedFolder);
 
     action = selectFolder('4')!;
-    selectedFolder = updateSelectedFolder(selectedFolder, action, nodes);
+    state = reduceAction(state, action);
 
     // Delete an ancestor of the selected folder:
-    action = removeBookmark('2', '1', 0, nodes);
-    selectedFolder = updateSelectedFolder(selectedFolder, action, nodes);
+    action = removeBookmark('2', '1', 0, state.nodes);
+    state = reduceAction(state, action);
 
-    assertEquals('1', selectedFolder);
+    assertEquals('1', state.selectedFolder);
   });
 });
 
diff --git a/chrome/test/data/webui/glic/BUILD.gn b/chrome/test/data/webui/glic/BUILD.gn
index 56a5f1f..c6acbb1 100644
--- a/chrome/test/data/webui/glic/BUILD.gn
+++ b/chrome/test/data/webui/glic/BUILD.gn
@@ -14,6 +14,7 @@
     ":move_html",
     ":test_client_api_deps",
     ":test_client_external_files",
+    ":test_glic_deps",
   ]
   deps = [ "//components/optimization_guide/proto:optimization_guide_proto" ]
 }
@@ -36,10 +37,16 @@
   ]
   deps = [ "//chrome/browser/resources/glic:build_ts" ]
 
-  path_mappings =
-      [ "/glic/glic_api/*|" + rebase_path(
+  path_mappings = [
+    "/glic/glic_api/*|" + rebase_path(
             "$root_gen_dir/chrome/browser/resources/glic/tsc/glic_api/*",
-            target_gen_dir) ]
+            target_gen_dir),
+
+    # Not all files under glic/ are copied. See test_glic_deps.
+    "/glic/*|" +
+        rebase_path("$root_gen_dir/chrome/browser/resources/glic/tsc/*",
+                    target_gen_dir),
+  ]
   tsconfig_base = "tsconfig.base.json"
 }
 
@@ -65,6 +72,12 @@
   deps = [ "//chrome/browser/resources/glic:build_ts" ]
 }
 
+copy("test_glic_deps") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/glic/tsc/observable.js" ]
+  outputs = [ "$out_dir/{{source_file_part}}" ]
+  deps = [ "//chrome/browser/resources/glic:build_ts" ]
+}
+
 build_webui_tests("build") {
   files = [ "unit_tests/webview_test.ts" ]
 
diff --git a/chrome/test/data/webui/glic/api_test.ts b/chrome/test/data/webui/glic/api_test.ts
index 0f2c8331..8659e9d 100644
--- a/chrome/test/data/webui/glic/api_test.ts
+++ b/chrome/test/data/webui/glic/api_test.ts
@@ -8,6 +8,7 @@
 
 import {PanelStateKind, ScrollToErrorReason, WebClientMode} from '/glic/glic_api/glic_api.js';
 import type {GlicBrowserHost, GlicHostRegistry, GlicWebClient, Observable, OpenPanelInfo, PanelOpeningData, ScrollToError, Subscriber} from '/glic/glic_api/glic_api.js';
+import {ObservableValue} from '/glic/observable.js';
 
 import {createGlicHostRegistryOnLoad} from './api_boot.js';
 
@@ -71,6 +72,7 @@
   firstOpened = Promise.withResolvers<void>();
   initializedPromise = Promise.withResolvers<void>();
   onNotifyPanelWasClosed: () => void = () => {};
+  panelOpenState = ObservableValue.withValue<boolean>(false);
 
   async initialize(glicBrowserHost: GlicBrowserHost): Promise<void> {
     this.host = glicBrowserHost;
@@ -79,6 +81,7 @@
 
   async notifyPanelWillOpen(_panelOpeningData: PanelOpeningData):
       Promise<OpenPanelInfo> {
+    this.panelOpenState.assignAndSignal(true);
     this.firstOpened.resolve();
 
     const openPanelInfo: OpenPanelInfo = {
@@ -87,6 +90,11 @@
     return openPanelInfo;
   }
 
+  async notifyPanelWasClosed(): Promise<void> {
+    this.onNotifyPanelWasClosed();
+    this.panelOpenState.assignAndSignal(false);
+  }
+
   waitForFirstOpen(): Promise<void> {
     return this.firstOpened.promise;
   }
@@ -94,10 +102,6 @@
   waitForInitialize(): Promise<void> {
     return this.initializedPromise.promise;
   }
-
-  async notifyPanelWasClosed?(): Promise<void> {
-    this.onNotifyPanelWasClosed();
-  }
 }
 
 interface TestStepper {
@@ -113,13 +117,22 @@
   testParams: any;
   constructor(protected testStepper: TestStepper) {}
 
+  // Return to the C++ side, and wait for it to call ContinueJsTest() to
+  // continue execution in the JS test. Optionally, pass data to the C++ side.
+  advanceToNextStep(data?: any): Promise<void> {
+    return this.testStepper.nextStep(data);
+  }
+
   // Sets up the web client. This is called when the web contents loads,
   // before `ExecuteJsTest()`.
   async setUpClient() {
+    this.setUpWithClient(this.createWebClient());
+  }
+
+  async setUpWithClient(client: WebClient) {
     const registry = await glicHostRegistry.promise;
-    const webClient = this.createWebClient();
-    registry.registerWebClient(webClient);
-    this.clientValue = webClient;
+    this.clientValue = client;
+    await registry.registerWebClient(client);
     assertTrue(!!this.clientValue);
   }
 
@@ -151,12 +164,6 @@
     await this.client.waitForFirstOpen();
   }
 
-  // Return to the C++ side, and wait for it to call ContinueJsTest() to
-  // continue execution in the JS test. Optionally, pass data to the C++ side.
-  private advanceToNextStep(data?: any): Promise<void> {
-    return this.testStepper.nextStep(data);
-  }
-
   // WARNING: Remember to update chrome/browser/glic/host/glic_api_uitest.cc
   // if you add a new test!
 
@@ -867,10 +874,37 @@
   async testInitializeFailsAfterReload() {
     this.deferredSetUpClient();
   }
-
+  // Skips the setup entirely.
+  async testNoClientCreated() {}
+  // Skips the bootstrap as well. The test name "testNoBootstrap" is handled
+  // specially.
+  async testNoBootstrap() {}
   async testInitializeTimesOut() {
     await super.setUpClient();
   }
+
+  // Tests notifyPanelWillOpen() returning after the panel is closed and then
+  // reopened.
+  async testCloseAndOpenWhileOpening() {
+    const openSignal = Promise.withResolvers<void>();
+    class WebClientThatOpensSlowly extends WebClient {
+      override async notifyPanelWillOpen(): Promise<OpenPanelInfo> {
+        this.panelOpenState.assignAndSignal(true);
+        await openSignal.promise;
+        return {
+          startingMode: WebClientMode.TEXT,
+        };
+      }
+    }
+    await this.setUpWithClient(new WebClientThatOpensSlowly());
+    const panelOpenState = observeSequence(this.client.panelOpenState);
+    panelOpenState.waitForValue(true);
+    await this.host.closePanel!();
+    panelOpenState.waitForValue(false);
+    await this.advanceToNextStep();
+    openSignal.resolve();
+    await panelOpenState.waitForValue(true);
+  }
 }
 
 class WebClientThatOpensOnce extends WebClient {
@@ -1043,8 +1077,10 @@
 }
 
 async function main() {
-  console.info('api_test waiting for GlicHostRegistry');
-  glicHostRegistry.resolve(await createGlicHostRegistryOnLoad());
+  if (getTestName() !== 'testNoBootstrap') {
+    console.info('api_test waiting for GlicHostRegistry');
+    glicHostRegistry.resolve(await createGlicHostRegistryOnLoad());
+  }
 
   // If no test is selected, load a client that does nothing.
   // This is present because test.html is used as a dummy test client in
diff --git a/chrome/test/data/webui/lens/side_panel/error_page_test.ts b/chrome/test/data/webui/lens/side_panel/error_page_test.ts
index f41122d..96d70e3 100644
--- a/chrome/test/data/webui/lens/side_panel/error_page_test.ts
+++ b/chrome/test/data/webui/lens/side_panel/error_page_test.ts
@@ -5,6 +5,7 @@
 import 'chrome-untrusted://lens/side_panel/side_panel_app.js';
 
 import type {LensSidePanelPageRemote} from 'chrome-untrusted://lens/lens_side_panel.mojom-webui.js';
+import {SidePanelResultStatus} from 'chrome-untrusted://lens/lens_side_panel.mojom-webui.js';
 import type {LensSidePanelAppElement} from 'chrome-untrusted://lens/side_panel/side_panel_app.js';
 import {SidePanelBrowserProxyImpl} from 'chrome-untrusted://lens/side_panel/side_panel_browser_proxy.js';
 import {loadTimeData} from 'chrome-untrusted://resources/js/load_time_data.js';
@@ -42,29 +43,34 @@
   });
 
   test('ErrorPageIsVisibleAndHiddenAfterCallback', async () => {
-    callbackRouterRemote.setShowErrorPage(true);
+    callbackRouterRemote.setShowErrorPage(
+        true, SidePanelResultStatus.kErrorPageShownOffline);
     await waitAfterNextRender(lensSidePanelElement);
     assertTrue(isVisible(lensSidePanelElement.$.errorPage));
 
-    callbackRouterRemote.setShowErrorPage(false);
+    callbackRouterRemote.setShowErrorPage(
+        false, SidePanelResultStatus.kResultShown);
     await waitAfterNextRender(lensSidePanelElement);
     assertFalse(isVisible(lensSidePanelElement.$.errorPage));
   });
 
   test('ErrorPageIsNotAffectedByLoadingState', async () => {
     callbackRouterRemote.setIsLoadingResults(true);
-    callbackRouterRemote.setShowErrorPage(true);
+    callbackRouterRemote.setShowErrorPage(
+        true, SidePanelResultStatus.kErrorPageShownOffline);
     await waitAfterNextRender(lensSidePanelElement);
     assertTrue(isVisible(lensSidePanelElement.$.errorPage));
 
-    callbackRouterRemote.setShowErrorPage(false);
+    callbackRouterRemote.setShowErrorPage(
+        false, SidePanelResultStatus.kResultShown);
     await waitAfterNextRender(lensSidePanelElement);
     assertFalse(isVisible(lensSidePanelElement.$.errorPage));
   });
 
   test('ErrorPageHiddenWhenDisabled', async () => {
     loadTimeData.overrideValues({'enableErrorPage': false});
-    callbackRouterRemote.setShowErrorPage(true);
+    callbackRouterRemote.setShowErrorPage(
+        true, SidePanelResultStatus.kErrorPageShownOffline);
     await waitAfterNextRender(lensSidePanelElement);
     assertFalse(isVisible(lensSidePanelElement.$.errorPage));
   });
diff --git a/chrome/test/data/webui/print_preview/custom_margins_test.ts b/chrome/test/data/webui/print_preview/custom_margins_test.ts
index 7d8f086..791ef05b 100644
--- a/chrome/test/data/webui/print_preview/custom_margins_test.ts
+++ b/chrome/test/data/webui/print_preview/custom_margins_test.ts
@@ -5,10 +5,8 @@
 import type {MarginsSetting, PrintPreviewMarginControlContainerElement, PrintPreviewMarginControlElement, PrintPreviewModelElement, Settings} from 'chrome://print/print_preview.js';
 import {CustomMarginsOrientation, Margins, MarginsType, MeasurementSystem, MeasurementSystemUnitType, Size, State} from 'chrome://print/print_preview.js';
 import {assertNotReached} from 'chrome://resources/js/assert.js';
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
-import {fakeDataBind} from 'chrome://webui-test/polymer_test_util.js';
-import {eventToPromise} from 'chrome://webui-test/test_util.js';
+import {eventToPromise, microtasksFinished} from 'chrome://webui-test/test_util.js';
 
 suite('CustomMarginsTest', function() {
   let container: PrintPreviewMarginControlContainerElement;
@@ -56,7 +54,7 @@
 
   function getControls(): PrintPreviewMarginControlElement[] {
     return Array.from(
-        container.shadowRoot!.querySelectorAll('print-preview-margin-control'));
+        container.shadowRoot.querySelectorAll('print-preview-margin-control'));
   }
 
   /*
@@ -69,20 +67,15 @@
     // Wait for the control elements to be created before updating the state.
     container.measurementSystem = measurementSystem;
     document.body.appendChild(container);
-    const controlsAdded = eventToPromise('dom-change', container);
-    return controlsAdded.then(() => {
-      // 8.5 x 11, in pixels
-      const controls = getControls();
-      assertEquals(4, controls.length);
-      container.settings = model.settings;
-      fakeDataBind(model, container, 'settings');
+    // 8.5 x 11, in pixels
+    const controls = getControls();
+    assertEquals(4, controls.length);
 
-      container.state = State.READY;
-      container.updateClippingMask(new Size(850, 1100));
-      container.updateScaleTransform(pixelsPerInch / pointsPerInch);
-      container.previewLoaded = true;
-      flush();
-    });
+    container.state = State.READY;
+    container.updateClippingMask(new Size(850, 1100));
+    container.updateScaleTransform(pixelsPerInch / pointsPerInch);
+    container.previewLoaded = true;
+    return microtasksFinished();
   }
 
   /**
@@ -314,7 +307,6 @@
       model.set('settings.margins.value', MarginsType.CUSTOM);
       const marginValues = setupCustomMargins();
       model.notifyPath('settings.customMargins.value');
-      flush();
 
       // Validate control positions have been updated.
       controls.forEach((control, index) => {
@@ -359,7 +351,6 @@
     return finishSetup().then(() => {
       const controls = getControls();
       model.set('settings.margins.value', MarginsType.CUSTOM);
-      flush();
 
 
       // Wait for an animation frame. The position of the controls is set in
@@ -408,112 +399,105 @@
 
   // Test that setting the margin controls with their textbox inputs updates
   // the custom margins setting.
-  test(
-      'SetControlsWithTextbox', function() {
-        return finishSetup().then(() => {
-          const controls = getControls();
-          // Set a shorter delay for testing so the test doesn't take too
-          // long.
-          controls.forEach(c => {
-            c.getInput().setAttribute('data-timeout-delay', '1');
-          });
-          model.set('settings.margins.value', MarginsType.CUSTOM);
-          flush();
-
-          // Verify entering a new value updates the settings.
-          // Then verify entering an invalid value invalidates the control
-          // and does not update the settings.
-          const value1 = '1.75';  // 1.75 inches
-          const newMargin1 = Math.round(parseFloat(value1) * pointsPerInch);
-          const value2 = '.6';
-          const newMargin2 = Math.round(parseFloat(value2) * pointsPerInch);
-          const value3 = '2';  // 2 inches
-          const newMargin3 = Math.round(parseFloat(value3) * pointsPerInch);
-          const maxTopMargin = container.pageSize.height - newMargin3 -
-              72 /* MINIMUM_DISTANCE, see margin_control.js */;
-          return testAllTextboxes(controls, defaultMarginPts, value1, false)
-              .then(() => testAllTextboxes(controls, newMargin1, 'abc', true))
-              .then(
-                  () => testAllTextboxes(controls, newMargin1, '1.2abc', true))
-              .then(
-                  () => testAllTextboxes(controls, newMargin1, '1.   2', true))
-              .then(() => testAllTextboxes(controls, newMargin1, '.', true))
-              .then(() => testAllTextboxes(controls, newMargin1, value2, false))
-              .then(() => testAllTextboxes(controls, newMargin2, value3, false))
-              .then(
-                  () => testControlTextbox(
-                      controls[0]!, keys[0]!, newMargin3, '100', false,
-                      maxTopMargin))
-              .then(
-                  () => testControlTextbox(
-                      controls[0]!, keys[0]!, maxTopMargin, '1,000', false,
-                      maxTopMargin));
-        });
+  test('SetControlsWithTextbox', function() {
+    return finishSetup().then(async () => {
+      const controls = getControls();
+      // Set a shorter delay for testing so the test doesn't take too
+      // long.
+      controls.forEach(c => {
+        c.getInput().setAttribute('data-timeout-delay', '1');
       });
+      model.set('settings.margins.value', MarginsType.CUSTOM);
+      await microtasksFinished();
+
+      // Verify entering a new value updates the settings.
+      // Then verify entering an invalid value invalidates the control
+      // and does not update the settings.
+      const value1 = '1.75';  // 1.75 inches
+      const newMargin1 = Math.round(parseFloat(value1) * pointsPerInch);
+      const value2 = '.6';
+      const newMargin2 = Math.round(parseFloat(value2) * pointsPerInch);
+      const value3 = '2';  // 2 inches
+      const newMargin3 = Math.round(parseFloat(value3) * pointsPerInch);
+      const maxTopMargin = container.pageSize.height - newMargin3 -
+          72 /* MINIMUM_DISTANCE, see margin_control.js */;
+      return testAllTextboxes(controls, defaultMarginPts, value1, false)
+          .then(() => testAllTextboxes(controls, newMargin1, 'abc', true))
+          .then(() => testAllTextboxes(controls, newMargin1, '1.2abc', true))
+          .then(() => testAllTextboxes(controls, newMargin1, '1.   2', true))
+          .then(() => testAllTextboxes(controls, newMargin1, '.', true))
+          .then(() => testAllTextboxes(controls, newMargin1, value2, false))
+          .then(() => testAllTextboxes(controls, newMargin2, value3, false))
+          .then(
+              () => testControlTextbox(
+                  controls[0]!, keys[0]!, newMargin3, '100', false,
+                  maxTopMargin))
+          .then(
+              () => testControlTextbox(
+                  controls[0]!, keys[0]!, maxTopMargin, '1,000', false,
+                  maxTopMargin));
+    });
+  });
 
   // Test that setting the margin controls with their textbox inputs updates
   // the custom margins setting, using a metric measurement system with a ','
   // as the decimal delimiter and '.' as the thousands delimiter. Regression
   // test for https://crbug.com/1005816.
-  test(
-      'SetControlsWithTextboxMetric', function() {
-        measurementSystem =
-            new MeasurementSystem('.', ',', MeasurementSystemUnitType.METRIC);
-        return finishSetup().then(() => {
-          const controls = getControls();
-          // Set a shorter delay for testing so the test doesn't take too
-          // long.
-          controls.forEach(c => {
-            c.getInput().setAttribute('data-timeout-delay', '1');
-          });
-          model.set('settings.margins.value', MarginsType.CUSTOM);
-          flush();
-
-          // Verify entering a new value updates the settings.
-          // Then verify entering an invalid value invalidates the control
-          // and does not update the settings.
-          const pointsPerMM = pointsPerInch / 25.4;
-          const newMargin1 = '50,0';
-          const newMargin1Pts = Math.round(50 * pointsPerMM);
-          const newMargin2 = ',9';
-          const newMargin2Pts = Math.round(.9 * pointsPerMM);
-          const newMargin3 = '60';
-          const newMargin3Pts = Math.round(60 * pointsPerMM);
-          const maxTopMargin = container.pageSize.height - newMargin3Pts -
-              72 /* MINIMUM_DISTANCE, see margin_control.js */;
-          return testAllTextboxes(
-                     controls, defaultMarginPts, newMargin1, false,
-                     newMargin1Pts)
-              .then(
-                  () => testAllTextboxes(
-                      controls, newMargin1Pts, 'abc', true, newMargin1Pts))
-              .then(
-                  () => testAllTextboxes(
-                      controls, newMargin1Pts, '50,2abc', true, newMargin1Pts))
-              .then(
-                  () => testAllTextboxes(
-                      controls, newMargin1Pts, '10,   2', true, newMargin1Pts))
-              .then(
-                  () => testAllTextboxes(
-                      controls, newMargin1Pts, ',', true, newMargin1Pts))
-              .then(
-                  () => testAllTextboxes(
-                      controls, newMargin1Pts, newMargin2, false,
-                      newMargin2Pts))
-              .then(
-                  () => testAllTextboxes(
-                      controls, newMargin2Pts, newMargin3, false,
-                      newMargin3Pts))
-              .then(
-                  () => testControlTextbox(
-                      controls[0]!, keys[0]!, newMargin3Pts, '1.000.000', false,
-                      maxTopMargin))
-              .then(
-                  () => testControlTextbox(
-                      controls[0]!, keys[0]!, maxTopMargin, '1.000', false,
-                      maxTopMargin));
-        });
+  test('SetControlsWithTextboxMetric', function() {
+    measurementSystem =
+        new MeasurementSystem('.', ',', MeasurementSystemUnitType.METRIC);
+    return finishSetup().then(async () => {
+      const controls = getControls();
+      // Set a shorter delay for testing so the test doesn't take too
+      // long.
+      controls.forEach(c => {
+        c.getInput().setAttribute('data-timeout-delay', '1');
       });
+      model.set('settings.margins.value', MarginsType.CUSTOM);
+      await microtasksFinished();
+
+      // Verify entering a new value updates the settings.
+      // Then verify entering an invalid value invalidates the control
+      // and does not update the settings.
+      const pointsPerMM = pointsPerInch / 25.4;
+      const newMargin1 = '50,0';
+      const newMargin1Pts = Math.round(50 * pointsPerMM);
+      const newMargin2 = ',9';
+      const newMargin2Pts = Math.round(.9 * pointsPerMM);
+      const newMargin3 = '60';
+      const newMargin3Pts = Math.round(60 * pointsPerMM);
+      const maxTopMargin = container.pageSize.height - newMargin3Pts -
+          72 /* MINIMUM_DISTANCE, see margin_control.js */;
+      return testAllTextboxes(
+                 controls, defaultMarginPts, newMargin1, false, newMargin1Pts)
+          .then(
+              () => testAllTextboxes(
+                  controls, newMargin1Pts, 'abc', true, newMargin1Pts))
+          .then(
+              () => testAllTextboxes(
+                  controls, newMargin1Pts, '50,2abc', true, newMargin1Pts))
+          .then(
+              () => testAllTextboxes(
+                  controls, newMargin1Pts, '10,   2', true, newMargin1Pts))
+          .then(
+              () => testAllTextboxes(
+                  controls, newMargin1Pts, ',', true, newMargin1Pts))
+          .then(
+              () => testAllTextboxes(
+                  controls, newMargin1Pts, newMargin2, false, newMargin2Pts))
+          .then(
+              () => testAllTextboxes(
+                  controls, newMargin2Pts, newMargin3, false, newMargin3Pts))
+          .then(
+              () => testControlTextbox(
+                  controls[0]!, keys[0]!, newMargin3Pts, '1.000.000', false,
+                  maxTopMargin))
+          .then(
+              () => testControlTextbox(
+                  controls[0]!, keys[0]!, maxTopMargin, '1.000', false,
+                  maxTopMargin));
+    });
+  });
 
   // Test that if there is a custom margins sticky setting, it is restored
   // when margin setting changes.
@@ -545,42 +529,39 @@
       });
 
   // Test that if the media size changes, the custom margins are cleared.
-  test(
-      'MediaSizeClearsCustomMargins', function() {
-        return validateMarginsClearedForSetting(
-                   'mediaSize', {height_microns: 200000, width_microns: 200000})
-            .then(() => {
-              // Simulate setting custom margins again.
-              model.set('settings.margins.value', MarginsType.CUSTOM);
+  test('MediaSizeClearsCustomMargins', async function() {
+    await validateMarginsClearedForSetting(
+        'mediaSize', {height_microns: 200000, width_microns: 200000});
+    // Simulate setting custom margins again.
+    model.set('settings.margins.value', MarginsType.CUSTOM);
+    await microtasksFinished();
 
-              // Validate control positions are initialized based on the default
-              // values.
-              const controls = getControls();
-              controls.forEach((control, index) => {
-                const side = sides[index];
-                assertEquals(side, control.side);
-                assertEquals(defaultMarginPts, control.getPositionInPts());
-              });
-            });
-      });
+    // Validate control positions are initialized based on the default
+    // values.
+    const controls = getControls();
+    controls.forEach((control, index) => {
+      const side = sides[index];
+      assertEquals(side, control.side);
+      assertEquals(defaultMarginPts, control.getPositionInPts());
+    });
+  });
 
   // Test that if the orientation changes, the custom margins are cleared.
-  test(
-      'LayoutClearsCustomMargins', function() {
-        return validateMarginsClearedForSetting('layout', true).then(() => {
-          // Simulate setting custom margins again
-          model.set('settings.margins.value', MarginsType.CUSTOM);
+  test('LayoutClearsCustomMargins', async function() {
+    await validateMarginsClearedForSetting('layout', true);
+    // Simulate setting custom margins again
+    model.set('settings.margins.value', MarginsType.CUSTOM);
+    await microtasksFinished();
 
-          // Validate control positions are initialized based on the default
-          // values.
-          const controls = getControls();
-          controls.forEach((control, index) => {
-            const side = sides[index];
-            assertEquals(side, control.side);
-            assertEquals(defaultMarginPts, control.getPositionInPts());
-          });
-        });
-      });
+    // Validate control positions are initialized based on the default
+    // values.
+    const controls = getControls();
+    controls.forEach((control, index) => {
+      const side = sides[index];
+      assertEquals(side, control.side);
+      assertEquals(defaultMarginPts, control.getPositionInPts());
+    });
+  });
 
   // Test that if the margins are not available, the custom margins setting is
   // not updated based on the document margins - i.e. PDFs do not change the
@@ -608,79 +589,78 @@
 
   // Test that if the user focuses a textbox that is not visible, the
   // text-focus event is fired with the correct values to scroll by.
-  test(
-      'RequestScrollToOutOfBoundsTextbox', function() {
-        return finishSetup()
-            .then(() => {
-              // Wait for the controls to be set up, which occurs in an
-              // animation frame.
-              return whenAnimationFrameDone();
-            })
-            .then(() => {
-              const onTransitionEnd = getAllTransitions(getControls());
+  test('RequestScrollToOutOfBoundsTextbox', function() {
+    return finishSetup()
+        .then(() => {
+          // Wait for the controls to be set up, which occurs in an
+          // animation frame.
+          return whenAnimationFrameDone();
+        })
+        .then(() => {
+          const onTransitionEnd = getAllTransitions(getControls());
 
-              // Controls become visible when margin type CUSTOM is selected.
-              model.set('settings.margins.value', MarginsType.CUSTOM);
-              container.notifyPath('settings.customMargins.value');
-              flush();
-              return onTransitionEnd;
-            })
-            .then(() => {
-              // Zoom in by 2x, so that some margin controls will not be
-              // visible.
-              container.updateScaleTransform(pixelsPerInch * 2 / pointsPerInch);
-              flush();
-              return whenAnimationFrameDone();
-            })
-            .then(() => {
-              const controls = getControls();
-              assertEquals(4, controls.length);
+          // Controls become visible when margin type CUSTOM is selected.
+          model.setSetting('margins', MarginsType.CUSTOM);
+          return onTransitionEnd;
+        })
+        .then(async () => {
+          // Zoom in by 2x, so that some margin controls will not be
+          // visible.
+          container.updateScaleTransform(pixelsPerInch * 2 / pointsPerInch);
+          await microtasksFinished();
+          return whenAnimationFrameDone();
+        })
+        .then(() => {
+          const controls = getControls();
+          assertEquals(4, controls.length);
 
-              // Focus the bottom control, which is currently not visible since
-              // the viewer is showing only the top left quarter of the page.
-              const bottomControl = controls[2]!;
-              const whenEventFired =
-                  eventToPromise('text-focus-position', container);
-              bottomControl.$.input.focus();
-              // Workaround for mac so that this does not need to be an
-              // interactive test: manually fire the focus event from the
-              // control.
-              bottomControl.dispatchEvent(new CustomEvent(
-                  'text-focus', {bubbles: true, composed: true}));
-              return whenEventFired;
-            })
-            .then((args) => {
-              // Shifts left by padding of 50px to ensure that the full textbox
-              // is visible.
-              assertEquals(50, args.detail.x);
+          // Focus the bottom control, which is currently not visible since
+          // the viewer is showing only the top left quarter of the page.
+          const bottomControl = controls[2]!;
+          const whenEventFired =
+              eventToPromise('text-focus-position', container);
+          bottomControl.$.input.focus();
+          // Workaround for mac so that this does not need to be an
+          // interactive test: manually fire the focus event from the
+          // control.
+          bottomControl.dispatchEvent(
+              new CustomEvent('text-focus', {bubbles: true, composed: true}));
+          return whenEventFired;
+        })
+        .then((args) => {
+          // Shifts left by padding of 50px to ensure that the full textbox
+          // is visible.
+          assertEquals(50, args.detail.x);
 
-              // Offset top will be 2097 = 200 px/in / 72 pts/in * (794pts -
-              // 36ptx) - 9px radius of line
-              // Height of the clip box is 200 px/in * 11in = 2200px
-              // Shifts down by offsetTop = 2097 - height / 2 + padding =
-              // 1047px. This will ensure that the textbox is in the visible
-              // area.
-              assertEquals(1047, args.detail.y);
-            });
-      });
+          // Offset top will be 2097 = 200 px/in / 72 pts/in * (794pts -
+          // 36ptx) - 9px radius of line
+          // Height of the clip box is 200 px/in * 11in = 2200px
+          // Shifts down by offsetTop = 2097 - height / 2 + padding =
+          // 1047px. This will ensure that the textbox is in the visible
+          // area.
+          assertEquals(1047, args.detail.y);
+        });
+  });
 
   // Tests that the margin controls can be correctly set from the sticky
   // settings.
-  test(
-      'ControlsDisabledOnError', function() {
-        return finishSetup().then(() => {
-          // Simulate setting custom margins.
-          model.set('settings.margins.value', MarginsType.CUSTOM);
+  test('ControlsDisabledOnError', async function() {
+    await finishSetup();
 
-          const controls = getControls();
-          controls.forEach(control => assertFalse(control.disabled));
+    // Simulate setting custom margins.
+    model.set('settings.margins.value', MarginsType.CUSTOM);
+    await microtasksFinished();
 
-          container.state = State.ERROR;
-          // Validate controls are disabled.
-          controls.forEach(control => assertTrue(control.disabled));
+    const controls = getControls();
+    controls.forEach(control => assertFalse(control.disabled));
 
-          container.state = State.READY;
-          controls.forEach(control => assertFalse(control.disabled));
-        });
-      });
+    container.state = State.ERROR;
+    await microtasksFinished();
+    // Validate controls are disabled.
+    controls.forEach(control => assertTrue(control.disabled));
+
+    container.state = State.READY;
+    await microtasksFinished();
+    controls.forEach(control => assertFalse(control.disabled));
+  });
 });
diff --git a/chromeos/ash/components/boca/boca_metrics_util.cc b/chromeos/ash/components/boca/boca_metrics_util.cc
index 6593512..53061be 100644
--- a/chromeos/ash/components/boca/boca_metrics_util.cc
+++ b/chromeos/ash/components/boca/boca_metrics_util.cc
@@ -9,6 +9,7 @@
 #include "base/metrics/metrics_hashes.h"
 #include "base/metrics/user_metrics.h"
 #include "base/strings/string_util.h"
+#include "chromeos/ash/components/boca/boca_session_manager.h"
 #include "google_apis/common/api_error_codes.h"
 
 namespace ash::boca {
@@ -179,4 +180,26 @@
                            error_code);
 }
 
+void RecordPollingResult(const ::boca::Session* previous_session,
+                         const ::boca::Session* current_session) {
+  BocaSessionManager::BocaPollingResult polling_result;
+  if (!previous_session && !current_session) {
+    polling_result = BocaSessionManager::BocaPollingResult::kNoUpdate;
+  } else if (!previous_session) {
+    polling_result = BocaSessionManager::BocaPollingResult::kSessionStart;
+  } else if (!current_session) {
+    polling_result = BocaSessionManager::BocaPollingResult::kSessionEnd;
+  } else if (previous_session->SerializeAsString() !=
+             current_session->SerializeAsString()) {
+    polling_result = BocaSessionManager::BocaPollingResult::kInSessionUpdate;
+  } else {
+    polling_result = BocaSessionManager::BocaPollingResult::kNoUpdate;
+  }
+  base::UmaHistogramEnumeration(kPollingResult, polling_result);
+}
+
+void RecordTokenRetrievalIsValidation(const bool is_validation) {
+  base::UmaHistogramBoolean(kBocaTokenRetrievalIsValidation, is_validation);
+}
+
 }  // namespace ash::boca
diff --git a/chromeos/ash/components/boca/boca_metrics_util.h b/chromeos/ash/components/boca/boca_metrics_util.h
index d6f1d15..d1d871c 100644
--- a/chromeos/ash/components/boca/boca_metrics_util.h
+++ b/chromeos/ash/components/boca/boca_metrics_util.h
@@ -6,6 +6,7 @@
 #define CHROMEOS_ASH_COMPONENTS_BOCA_BOCA_METRICS_UTIL_H_
 
 #include "base/time/time.h"
+#include "chromeos/ash/components/boca/session_api/session_client_impl.h"
 #include "google_apis/common/api_error_codes.h"
 
 namespace ash::boca {
@@ -62,6 +63,9 @@
 inline constexpr char kBocaUpdateStudentActivities[] =
     "UpdateStudentActivities";
 inline constexpr char kBocaStudentHeartbeat[] = "StudentHeartbeat";
+inline static constexpr char kPollingResult[] = "Ash.Boca.PollingResult";
+inline static constexpr char kBocaTokenRetrievalIsValidation[] =
+    "Ash.Boca.TokenRetrievalIsValidation";
 inline constexpr char kBocaUploadToken[] = "UploadToken";
 
 // Records the percentage of the duration that a session was in a particular
@@ -167,6 +171,13 @@
 void RecordGoogleApiErrorCode(const std::string& name,
                               google_apis::ApiErrorCode error_code);
 
+// Records the session polling result.
+void RecordPollingResult(const ::boca::Session* previous_session,
+                         const ::boca::Session* current_session);
+
+// Records the token retrieval is validation status.
+void RecordTokenRetrievalIsValidation(const bool is_validation);
+
 }  // namespace ash::boca
 
 #endif  // CHROMEOS_ASH_COMPONENTS_BOCA_BOCA_METRICS_UTIL_H_
diff --git a/chromeos/ash/components/boca/boca_session_manager.cc b/chromeos/ash/components/boca/boca_session_manager.cc
index 6b246245..3c38be7 100644
--- a/chromeos/ash/components/boca/boca_session_manager.cc
+++ b/chromeos/ash/components/boca/boca_session_manager.cc
@@ -243,7 +243,7 @@
   }
 
   if (from_polling) {
-    RecordPollingResult(current_session_.get(), result.value().get());
+    boca::RecordPollingResult(current_session_.get(), result.value().get());
   }
 
   UpdateCurrentSession(std::move(result.value()), true);
@@ -454,25 +454,6 @@
   return previous_session->session_id() != current_session->session_id();
 }
 
-void BocaSessionManager::RecordPollingResult(
-    const ::boca::Session* previous_session,
-    const ::boca::Session* current_session) {
-  BocaPollingResult polling_result;
-  if (!previous_session && !current_session) {
-    polling_result = BocaPollingResult::kNoUpdate;
-  } else if (!previous_session) {
-    polling_result = BocaPollingResult::kSessionStart;
-  } else if (!current_session) {
-    polling_result = BocaPollingResult::kSessionEnd;
-  } else if (previous_session->SerializeAsString() !=
-             current_session->SerializeAsString()) {
-    polling_result = BocaPollingResult::kInSessionUpdate;
-  } else {
-    polling_result = BocaPollingResult::kNoUpdate;
-  }
-  base::UmaHistogramEnumeration(kPollingResultHistName, polling_result);
-}
-
 void BocaSessionManager::HandleTakeOver(
     bool dispatch_event,
     std::unique_ptr<::boca::Session> session) {
diff --git a/chromeos/ash/components/boca/boca_session_manager.h b/chromeos/ash/components/boca/boca_session_manager.h
index e5ebb4bc..16888564 100644
--- a/chromeos/ash/components/boca/boca_session_manager.h
+++ b/chromeos/ash/components/boca/boca_session_manager.h
@@ -62,8 +62,6 @@
   inline static constexpr int kLocalSessionTrackerBufferInSeconds = 60;
   inline static constexpr int kDefaultStudentHeartbeatIntervalInSeconds = 30;
   inline static constexpr int kSkipPollingBufferInSeconds = 2;
-  inline static constexpr char kPollingResultHistName[] =
-      "Ash.Boca.PollingResult";
 
   enum class BocaAction {
     kDefault = 0,
@@ -243,8 +241,6 @@
   bool IsSessionActive(const ::boca::Session* session);
   bool IsSessionTakeOver(const ::boca::Session* previous_session,
                          const ::boca::Session* current_session);
-  void RecordPollingResult(const ::boca::Session* previous_session,
-                           const ::boca::Session* current_session);
   void HandleTakeOver(bool dispatch_event,
                       std::unique_ptr<::boca::Session> session);
   void DispatchEvent();
diff --git a/chromeos/ash/components/boca/boca_session_manager_unittest.cc b/chromeos/ash/components/boca/boca_session_manager_unittest.cc
index 292ccc7..5f64d1de 100644
--- a/chromeos/ash/components/boca/boca_session_manager_unittest.cc
+++ b/chromeos/ash/components/boca/boca_session_manager_unittest.cc
@@ -21,6 +21,7 @@
 #include "base/types/expected.h"
 #include "chromeos/ash/components/boca/babelorca/soda_testing_utils.h"
 #include "chromeos/ash/components/boca/boca_app_client.h"
+#include "chromeos/ash/components/boca/boca_metrics_util.h"
 #include "chromeos/ash/components/boca/boca_role_util.h"
 #include "chromeos/ash/components/boca/proto/session.pb.h"
 #include "chromeos/ash/components/boca/session_api/constants.h"
@@ -1319,13 +1320,12 @@
   EXPECT_CALL(*observer(), OnSessionStarted(kInitialSessionId, _)).Times(1);
   task_environment()->FastForwardBy(kDefaultInSessionPollingInterval * 2 +
                                     base::Seconds(1));
-  histogram_tester.ExpectTotalCount(BocaSessionManager::kPollingResultHistName,
-                                    2);
+  histogram_tester.ExpectTotalCount(boca::kPollingResult, 2);
   histogram_tester.ExpectBucketCount(
-      BocaSessionManager::kPollingResultHistName,
-      BocaSessionManager::BocaPollingResult::kSessionEnd, 1);
+      boca::kPollingResult, BocaSessionManager::BocaPollingResult::kSessionEnd,
+      1);
   histogram_tester.ExpectBucketCount(
-      BocaSessionManager::kPollingResultHistName,
+      boca::kPollingResult,
       BocaSessionManager::BocaPollingResult::kSessionStart, 1);
 }
 
@@ -1342,11 +1342,10 @@
 
   task_environment()->FastForwardBy(kDefaultInSessionPollingInterval * 1 +
                                     base::Seconds(1));
-  histogram_tester.ExpectTotalCount(BocaSessionManager::kPollingResultHistName,
-                                    1);
+  histogram_tester.ExpectTotalCount(boca::kPollingResult, 1);
   histogram_tester.ExpectBucketCount(
-      BocaSessionManager::kPollingResultHistName,
-      BocaSessionManager::BocaPollingResult::kNoUpdate, 1);
+      boca::kPollingResult, BocaSessionManager::BocaPollingResult::kNoUpdate,
+      1);
 }
 
 TEST_F(BocaSessionManagerTest, RecordMetricsIfInSessionUpdateFromPolling) {
@@ -1373,10 +1372,9 @@
   EXPECT_CALL(*observer(), OnSessionCaptionConfigUpdated).Times(0);
   task_environment()->FastForwardBy(kDefaultInSessionPollingInterval * 1 +
                                     base::Seconds(1));
-  histogram_tester.ExpectTotalCount(BocaSessionManager::kPollingResultHistName,
-                                    1);
+  histogram_tester.ExpectTotalCount(boca::kPollingResult, 1);
   histogram_tester.ExpectBucketCount(
-      BocaSessionManager::kPollingResultHistName,
+      boca::kPollingResult,
       BocaSessionManager::BocaPollingResult::kInSessionUpdate, 1);
 }
 
diff --git a/chromeos/ash/components/boca/invalidations/fcm_handler.cc b/chromeos/ash/components/boca/invalidations/fcm_handler.cc
index 7a1b60a..1f5e69b 100644
--- a/chromeos/ash/components/boca/invalidations/fcm_handler.cc
+++ b/chromeos/ash/components/boca/invalidations/fcm_handler.cc
@@ -10,6 +10,7 @@
 #include "base/functional/callback_helpers.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
+#include "chromeos/ash/components/boca/boca_metrics_util.h"
 #include "components/gcm_driver/gcm_driver.h"
 #include "components/gcm_driver/instance_id/instance_id_driver.h"
 
@@ -148,9 +149,7 @@
                                   instance_id::InstanceID::Result result) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  if (!is_validation) {
-    // TODO(b/366316261):Add metrics for token retrival status.
-  }
+  boca::RecordTokenRetrievalIsValidation(is_validation);
 
   if (!IsListening()) {
     // After we requested the token, |StopListening| has been called. Thus,
diff --git a/chromeos/ash/components/boca/invalidations/fcm_handler_unittest.cc b/chromeos/ash/components/boca/invalidations/fcm_handler_unittest.cc
index 44eb8d10..611168a 100644
--- a/chromeos/ash/components/boca/invalidations/fcm_handler_unittest.cc
+++ b/chromeos/ash/components/boca/invalidations/fcm_handler_unittest.cc
@@ -9,7 +9,9 @@
 #include <utility>
 
 #include "base/test/gmock_callback_support.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/task_environment.h"
+#include "chromeos/ash/components/boca/boca_metrics_util.h"
 #include "components/gcm_driver/fake_gcm_driver.h"
 #include "components/gcm_driver/gcm_driver.h"
 #include "components/gcm_driver/instance_id/instance_id.h"
@@ -121,6 +123,7 @@
 };
 
 TEST_F(FCMHandlerTest, ShouldReturnValidToken) {
+  base::HistogramTester histogram_tester;
   // Check that the handler gets the token through GetToken.
   EXPECT_CALL(mock_instance_id_, GetToken)
       .WillOnce(RunOnceCallback<4>("token", InstanceID::Result::SUCCESS));
@@ -128,9 +131,14 @@
   fcm_handler_.StartListening();
 
   EXPECT_EQ("token", fcm_handler_.GetFCMRegistrationToken());
+
+  histogram_tester.ExpectTotalCount(boca::kBocaTokenRetrievalIsValidation, 1);
+  histogram_tester.ExpectBucketCount(boca::kBocaTokenRetrievalIsValidation,
+                                     false, 1);
 }
 
 TEST_F(FCMHandlerTest, ShouldPropagatePayloadToListener) {
+  base::HistogramTester histogram_tester;
   const std::string kPayloadValue = "some_payload";
   NiceMock<MockListener> mock_listener;
   fcm_handler_.AddListener(&mock_listener);
@@ -141,9 +149,11 @@
   EXPECT_CALL(mock_listener, OnInvalidationReceived(kPayloadValue));
   fcm_handler_.OnMessage(kInvalidationsAppId, gcm_message);
   fcm_handler_.RemoveListener(&mock_listener);
+  histogram_tester.ExpectTotalCount(boca::kBocaTokenRetrievalIsValidation, 0);
 }
 
 TEST_F(FCMHandlerTest, ShouldNotifyOnTokenChange) {
+  base::HistogramTester histogram_tester;
   NiceMock<MockTokenObserver> mock_token_observer;
   fcm_handler_.AddTokenObserver(&mock_token_observer);
 
@@ -156,9 +166,13 @@
   fcm_handler_.StartListening();
 
   fcm_handler_.RemoveTokenObserver(&mock_token_observer);
+  histogram_tester.ExpectTotalCount(boca::kBocaTokenRetrievalIsValidation, 1);
+  histogram_tester.ExpectBucketCount(boca::kBocaTokenRetrievalIsValidation,
+                                     false, 1);
 }
 
 TEST_F(FCMHandlerTest, ShouldScheduleTokenValidationAndActOnNewToken) {
+  base::HistogramTester histogram_tester;
   NiceMock<MockTokenObserver> mock_token_observer;
   fcm_handler_.AddTokenObserver(&mock_token_observer);
 
@@ -180,9 +194,15 @@
   task_environment_.FastForwardBy(base::Seconds(1));
 
   fcm_handler_.RemoveTokenObserver(&mock_token_observer);
+  histogram_tester.ExpectTotalCount(boca::kBocaTokenRetrievalIsValidation, 2);
+  histogram_tester.ExpectBucketCount(boca::kBocaTokenRetrievalIsValidation,
+                                     true, 1);
+  histogram_tester.ExpectBucketCount(boca::kBocaTokenRetrievalIsValidation,
+                                     false, 1);
 }
 
 TEST_F(FCMHandlerTest, ShouldScheduleTokenValidationAndNotActOnSameToken) {
+  base::HistogramTester histogram_tester;
   NiceMock<MockTokenObserver> mock_token_observer;
   fcm_handler_.AddTokenObserver(&mock_token_observer);
 
@@ -204,9 +224,15 @@
   task_environment_.FastForwardBy(base::Seconds(1));
 
   fcm_handler_.RemoveTokenObserver(&mock_token_observer);
+  histogram_tester.ExpectTotalCount(boca::kBocaTokenRetrievalIsValidation, 2);
+  histogram_tester.ExpectBucketCount(boca::kBocaTokenRetrievalIsValidation,
+                                     true, 1);
+  histogram_tester.ExpectBucketCount(boca::kBocaTokenRetrievalIsValidation,
+                                     false, 1);
 }
 
 TEST_F(FCMHandlerTest, ShouldClearTokenOnStopListeningPermanently) {
+  base::HistogramTester histogram_tester;
   // Check that the handler gets the token through GetToken.
   EXPECT_CALL(mock_instance_id_, GetToken)
       .WillOnce(RunOnceCallback<4>("token", InstanceID::Result::SUCCESS));
@@ -223,6 +249,9 @@
   EXPECT_EQ(std::nullopt, fcm_handler_.GetFCMRegistrationToken());
 
   fcm_handler_.RemoveTokenObserver(&mock_token_observer);
+  histogram_tester.ExpectTotalCount(boca::kBocaTokenRetrievalIsValidation, 1);
+  histogram_tester.ExpectBucketCount(boca::kBocaTokenRetrievalIsValidation,
+                                     false, 1);
 }
 
 }  // namespace
diff --git a/chromeos/ash/services/libassistant/BUILD.gn b/chromeos/ash/services/libassistant/BUILD.gn
deleted file mode 100644
index 8e9db6f..0000000
--- a/chromeos/ash/services/libassistant/BUILD.gn
+++ /dev/null
@@ -1,321 +0,0 @@
-# Copyright 2020 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/buildflag_header.gni")
-import("//chromeos/ash/components/assistant/assistant.gni")
-
-assert(is_chromeos, "Non ChromeOS builds must not depend on //chromeos/ash")
-assert(enable_cros_libassistant)
-
-component("constants") {
-  output_name = "libassistant_constants"
-  defines = [ "IS_LIBASSISTANT_CONSTANTS_IMPL" ]
-  deps = [
-    "//base",
-    "//build:branding_buildflags",
-  ]
-  sources = [
-    "constants.cc",
-    "constants.h",
-  ]
-}
-
-component("libassistant") {
-  sources = [
-    "libassistant_service.cc",
-    "libassistant_service.h",
-  ]
-
-  public_deps = [
-    "//chromeos/ash/services/libassistant/public/mojom",
-    "//chromeos/assistant/internal/proto:assistant",
-    "//dbus",
-  ]
-
-  deps = [
-    ":internal",
-    ":loader",
-    "//chromeos/ash/services/assistant/public/cpp",
-    "//chromeos/ash/services/libassistant/public/mojom",
-    "//chromeos/assistant/internal:libassistant_shared_headers",
-  ]
-
-  defines = [ "IS_LIBASSISTANT_SERVICE_IMPL" ]
-
-  # The default output name of this service, `libassistant_service.so`, already
-  # exists (as build target of //chromeos/ash/services/assistant), so we have to
-  # use `lib_libassistant_service.so`.
-  output_name = "lib_libassistant_service"
-}
-
-source_set("loader") {
-  defines = [ "IS_LIBASSISTANT_LOADER_IMPL" ]
-
-  sources = [
-    "libassistant_loader_impl.cc",
-    "libassistant_loader_impl.h",
-  ]
-
-  public_deps = [ "//dbus" ]
-
-  deps = [
-    ":constants",
-    "//base",
-    "//chromeos/ash/components/dbus",
-    "//chromeos/ash/components/dbus/dlcservice",
-    "//chromeos/ash/components/dbus/dlcservice:dlcservice_proto",
-    "//chromeos/ash/services/assistant/public/cpp",
-    "//chromeos/ash/services/libassistant/public/cpp:loader",
-    "//chromeos/assistant/internal:libassistant",
-    "//chromeos/assistant/internal:libassistant_shared_headers",
-    "//net",
-  ]
-}
-
-source_set("sandbox_hook") {
-  sources = [
-    "libassistant_sandbox_hook.cc",
-    "libassistant_sandbox_hook.h",
-  ]
-
-  deps = [
-    ":constants",
-    ":loader",
-    "//base",
-    "//chromeos/ash/services/assistant/public/cpp",
-    "//chromeos/ash/services/libassistant/grpc:grpc_util",
-    "//sandbox/linux:sandbox_services",
-    "//sandbox/policy",
-  ]
-}
-
-source_set("callback_utils") {
-  sources = [ "callback_utils.h" ]
-
-  deps = [ "//base" ]
-}
-
-source_set("internal") {
-  visibility = [ ":*" ]
-
-  sources = [
-    "abortable_task_list.cc",
-    "abortable_task_list.h",
-    "audio_input_controller.cc",
-    "audio_input_controller.h",
-    "chromium_api_delegate.cc",
-    "chromium_api_delegate.h",
-    "chromium_http_connection.cc",
-    "chromium_http_connection.h",
-    "conversation_controller.cc",
-    "conversation_controller.h",
-    "conversation_state_listener_impl.cc",
-    "conversation_state_listener_impl.h",
-    "device_settings_controller.cc",
-    "device_settings_controller.h",
-    "display_connection.cc",
-    "display_connection.h",
-    "display_controller.cc",
-    "display_controller.h",
-    "fake_auth_provider.cc",
-    "fake_auth_provider.h",
-    "file_provider_impl.cc",
-    "file_provider_impl.h",
-    "libassistant_factory.h",
-    "media_controller.cc",
-    "media_controller.h",
-    "network_provider_impl.cc",
-    "network_provider_impl.h",
-    "platform_api.cc",
-    "platform_api.h",
-    "power_manager_provider_impl.cc",
-    "power_manager_provider_impl.h",
-    "service_controller.cc",
-    "service_controller.h",
-    "settings_controller.cc",
-    "settings_controller.h",
-    "speaker_id_enrollment_controller.cc",
-    "speaker_id_enrollment_controller.h",
-    "system_provider_impl.cc",
-    "system_provider_impl.h",
-    "timer_controller.cc",
-    "timer_controller.h",
-    "util.cc",
-    "util.h",
-  ]
-
-  public_deps = [
-    "//chromeos/assistant/internal/proto:assistant",
-    "//chromeos/services/network_config/public/cpp",
-  ]
-
-  deps = [
-    ":audio",
-    ":callback_utils",
-    ":constants",
-    "//build/util:chromium_git_revision",
-    "//chromeos/ash/components/assistant:buildflags",
-    "//chromeos/ash/components/dbus",
-    "//chromeos/ash/resources",
-    "//chromeos/ash/services/assistant/public/cpp",
-    "//chromeos/ash/services/assistant/public/proto",
-    "//chromeos/ash/services/libassistant/grpc:assistant_client",
-    "//chromeos/ash/services/libassistant/grpc:grpc_service",
-    "//chromeos/ash/services/libassistant/grpc:grpc_util",
-    "//chromeos/ash/services/libassistant/grpc/external_services:grpc_services_initializer",
-    "//chromeos/ash/services/libassistant/grpc/external_services:grpc_services_observer",
-    "//chromeos/ash/services/libassistant/public/mojom",
-    "//chromeos/assistant/internal",
-    "//chromeos/assistant/internal:libassistant",
-    "//chromeos/assistant/internal:libassistant_shared_headers",
-    "//chromeos/assistant/internal:support",
-    "//chromeos/assistant/internal/proto:assistant",
-    "//chromeos/dbus/power",
-    "//chromeos/strings:strings_grit",
-    "//chromeos/version:version",
-    "//services/network/public/cpp",
-    "//services/network/public/mojom",
-    "//ui/base",
-  ]
-
-  defines = [ "IS_LIBASSISTANT_SERVICE_IMPL" ]
-}
-
-source_set("audio") {
-  visibility = [ ":*" ]
-
-  sources = [
-    "audio/audio_device_owner.cc",
-    "audio/audio_device_owner.h",
-    "audio/audio_input_impl.cc",
-    "audio/audio_input_impl.h",
-    "audio/audio_input_provider_impl.cc",
-    "audio/audio_input_provider_impl.h",
-    "audio/audio_input_stream.cc",
-    "audio/audio_input_stream.h",
-    "audio/audio_media_data_source.cc",
-    "audio/audio_media_data_source.h",
-    "audio/audio_output_provider_impl.cc",
-    "audio/audio_output_provider_impl.h",
-    "audio/audio_stream_handler.cc",
-    "audio/audio_stream_handler.h",
-    "audio/volume_control_impl.cc",
-    "audio/volume_control_impl.h",
-  ]
-
-  deps = [
-    ":buildflags",
-    ":fake_input_device",
-    "//ash/public/mojom",
-    "//base",
-    "//chromeos/ash/services/assistant/public/cpp",
-    "//chromeos/ash/services/libassistant/grpc:assistant_client",
-    "//chromeos/ash/services/libassistant/public/mojom",
-    "//chromeos/assistant/internal:libassistant_shared_headers",
-    "//media",
-    "//media/mojo/mojom",
-    "//services/audio/public/cpp",
-    "//services/media_session/public/mojom",
-  ]
-}
-
-source_set("fake_input_device") {
-  visibility = [ ":*" ]
-
-  sources = [
-    "audio/fake_input_device.cc",
-    "audio/fake_input_device.h",
-  ]
-
-  deps = [
-    "//base",
-    "//media",
-  ]
-}
-
-source_set("test_support") {
-  testonly = true
-
-  sources = [
-    "test_support/fake_assistant_client.cc",
-    "test_support/fake_assistant_client.h",
-    "test_support/fake_libassistant_factory.cc",
-    "test_support/fake_libassistant_factory.h",
-    "test_support/fake_platform_delegate.cc",
-    "test_support/fake_platform_delegate.h",
-    "test_support/libassistant_service_tester.cc",
-    "test_support/libassistant_service_tester.h",
-  ]
-
-  deps = [
-    ":callback_utils",
-    ":internal",
-    ":libassistant",
-    "//base/test:test_support",
-    "//chromeos/ash/services/assistant/public/cpp",
-    "//chromeos/ash/services/libassistant/grpc:assistant_client",
-    "//chromeos/ash/services/libassistant/grpc:grpc_service",
-    "//chromeos/ash/services/libassistant/public/mojom",
-    "//chromeos/assistant/internal:test_support",
-    "//chromeos/assistant/internal/proto:assistant",
-    "//services/network:test_support",
-  ]
-}
-
-source_set("unit_tests") {
-  testonly = true
-  sources = [
-    "audio/audio_output_provider_impl_unittest.cc",
-    "audio_input_controller_unittest.cc",
-    "authentication_state_observer_unittest.cc",
-    "conversation_controller_unittest.cc",
-    "conversation_observer_unittest.cc",
-    "device_settings_controller_unittest.cc",
-    "display_controller_unittest.cc",
-    "libassistant_loader_impl_unittest.cc",
-    "media_controller_unittest.cc",
-    "network_provider_impl_unittest.cc",
-    "notification_delegate_unittest.cc",
-    "power_manager_provider_impl_unittest.cc",
-    "service_controller_unittest.cc",
-    "settings_controller_unittest.cc",
-    "speaker_id_enrollment_controller_unittest.cc",
-    "speech_recognition_observer_unittest.cc",
-    "system_provider_impl_unittest.cc",
-    "timer_controller_unittest.cc",
-  ]
-
-  deps = [
-    ":audio",
-    ":internal",
-    ":libassistant",
-    ":loader",
-    ":test_support",
-    "//base",
-    "//base/test:test_support",
-    "//chromeos/ash/components/assistant/test_support:test_support",
-    "//chromeos/ash/components/dbus/dlcservice",
-    "//chromeos/ash/services/assistant/public/cpp",
-    "//chromeos/ash/services/libassistant/grpc:assistant_client",
-    "//chromeos/ash/services/libassistant/public/mojom",
-    "//chromeos/assistant/internal",
-    "//chromeos/assistant/internal:libassistant_shared_headers",
-    "//chromeos/assistant/internal:support",
-    "//chromeos/assistant/internal:test_support",
-    "//chromeos/dbus/power",
-    "//services/audio/public/cpp:test_support",
-    "//services/device/public/cpp:test_support",
-    "//services/network:test_support",
-    "//services/network/public/cpp",
-    "//testing/gmock",
-    "//testing/gtest",
-  ]
-}
-
-buildflag_header("buildflags") {
-  header = "buildflags.h"
-
-  flags =
-      [ "ENABLE_FAKE_ASSISTANT_MICROPHONE=$enable_fake_assistant_microphone" ]
-}
diff --git a/chromeos/ash/services/libassistant/abortable_task_list.cc b/chromeos/ash/services/libassistant/abortable_task_list.cc
deleted file mode 100644
index 04ef044..0000000
--- a/chromeos/ash/services/libassistant/abortable_task_list.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/abortable_task_list.h"
-
-#include <algorithm>
-
-namespace ash::libassistant {
-
-AbortableTaskList::AbortableTaskList() = default;
-AbortableTaskList::~AbortableTaskList() {
-  AbortAll();
-}
-
-void AbortableTaskList::AbortAll() {
-  // Cancel all tasks that are not finished yet.
-  for (auto& task : tasks_) {
-    if (!task->IsFinished())
-      task->Abort();
-  }
-
-  tasks_.clear();
-}
-
-AbortableTask* AbortableTaskList::GetFirstTaskForTesting() {
-  return tasks_[0].get();
-}
-
-void AbortableTaskList::AddInternal(std::unique_ptr<AbortableTask> task) {
-  // We cleanup finished tasks when a new task is added.
-  RemoveFinishedTasks();
-  tasks_.push_back(std::move(task));
-}
-
-void AbortableTaskList::RemoveFinishedTasks() {
-  tasks_.erase(std::remove_if(tasks_.begin(), tasks_.end(),
-                              [](const std::unique_ptr<AbortableTask>& task) {
-                                return task->IsFinished();
-                              }),
-               tasks_.end());
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/abortable_task_list.h b/chromeos/ash/services/libassistant/abortable_task_list.h
deleted file mode 100644
index 2aa37682..0000000
--- a/chromeos/ash/services/libassistant/abortable_task_list.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_ABORTABLE_TASK_LIST_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_ABORTABLE_TASK_LIST_H_
-
-#include <memory>
-#include <vector>
-
-namespace ash::libassistant {
-
-class AbortableTask {
- public:
-  AbortableTask() = default;
-  virtual ~AbortableTask() = default;
-
-  virtual bool IsFinished() = 0;
-  virtual void Abort() = 0;
-};
-
-// Container used when we have to wait for a task to finish.
-// Finished tasks will be removed from the list.
-// All unfinished tasks will be aborted when the task list is destroyed,
-// or when |AbortAll()| is called.
-class AbortableTaskList {
- public:
-  AbortableTaskList();
-  AbortableTaskList(const AbortableTaskList&) = delete;
-  AbortableTaskList& operator=(const AbortableTaskList&) = delete;
-  ~AbortableTaskList();
-
-  // Add the given task, and return a pointer. This method is templated so we
-  // can return a pointer of the actual type (and not |AbortableTask*|).
-  template <class ActualType>
-  ActualType* Add(std::unique_ptr<ActualType> task) {
-    ActualType* pointer = task.get();
-    AddInternal(std::move(task));
-    return pointer;
-  }
-
-  void AbortAll();
-
-  AbortableTask* GetFirstTaskForTesting();
-
- private:
-  void AddInternal(std::unique_ptr<AbortableTask> task);
-  void RemoveFinishedTasks();
-
-  std::vector<std::unique_ptr<AbortableTask>> tasks_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_ABORTABLE_TASK_LIST_H_
diff --git a/chromeos/ash/services/libassistant/audio/audio_device_owner.cc b/chromeos/ash/services/libassistant/audio/audio_device_owner.cc
deleted file mode 100644
index c1b868a..0000000
--- a/chromeos/ash/services/libassistant/audio/audio_device_owner.cc
+++ /dev/null
@@ -1,249 +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 "chromeos/ash/services/libassistant/audio/audio_device_owner.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "base/sequence_checker.h"
-#include "chromeos/ash/services/libassistant/public/mojom/audio_output_delegate.mojom.h"
-#include "media/audio/audio_device_description.h"
-#include "media/base/audio_parameters.h"
-#include "media/base/limits.h"
-#include "services/media_session/public/mojom/media_session.mojom.h"
-
-namespace ash::libassistant {
-
-// A macro which ensures we are running on the background thread.
-#define ENSURE_BACKGROUND_THREAD(method, ...)                               \
-  if (!background_task_runner_->RunsTasksInCurrentSequence()) {             \
-    background_task_runner_->PostTask(                                      \
-        FROM_HERE,                                                          \
-        base::BindOnce(method, weak_factory_.GetWeakPtr(), ##__VA_ARGS__)); \
-    return;                                                                 \
-  }
-
-namespace {
-
-// The reduced audio (the ducked track) volume level while listening to user
-// speech.
-constexpr double kDuckingVolume = 0.2;
-
-constexpr int kNumberOfBuffersPerSec = 10;
-
-int32_t GetBytesPerSample(const assistant_client::OutputStreamFormat& format) {
-  switch (format.encoding) {
-    case assistant_client::OutputStreamEncoding::STREAM_PCM_S16:
-      return 2;
-    case assistant_client::OutputStreamEncoding::STREAM_PCM_S32:
-    case assistant_client::OutputStreamEncoding::STREAM_PCM_F32:
-      return 4;
-    default:
-      break;
-  }
-  NOTREACHED();
-}
-
-int32_t GetBytesPerFrame(const assistant_client::OutputStreamFormat& format) {
-  return GetBytesPerSample(format) * format.pcm_num_channels;
-}
-
-void FillAudioFifoWithDataOfBufferFormat(
-    media::AudioBlockFifo* fifo,
-    const std::vector<uint8_t>& data,
-    const assistant_client::OutputStreamFormat& output_format,
-    int num_bytes) {
-  int bytes_per_frame = GetBytesPerFrame(output_format);
-  int bytes_per_sample = GetBytesPerSample(output_format);
-  int frames = num_bytes / bytes_per_frame;
-  fifo->Push(data.data(), frames, bytes_per_sample);
-}
-
-int32_t GetBufferSizeInBytesFromBufferFormat(
-    const assistant_client::OutputStreamFormat& format) {
-  return GetBytesPerFrame(format) * format.pcm_sample_rate /
-         kNumberOfBuffersPerSec;
-}
-
-media::AudioParameters GetAudioParametersFromBufferFormat(
-    const assistant_client::OutputStreamFormat& output_format) {
-  DCHECK(output_format.pcm_num_channels <= 2 &&
-         output_format.pcm_num_channels > 0);
-
-  return media::AudioParameters(
-      media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
-      media::ChannelLayoutConfig::Guess(output_format.pcm_num_channels),
-      output_format.pcm_sample_rate,
-      output_format.pcm_sample_rate / kNumberOfBuffersPerSec);
-}
-
-}  // namespace
-
-AudioDeviceOwner::AudioDeviceOwner(const std::string& device_id)
-    : device_id_(device_id) {}
-
-AudioDeviceOwner::~AudioDeviceOwner() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-void AudioDeviceOwner::Start(
-    mojom::AudioOutputDelegate* audio_output_delegate,
-    assistant_client::AudioOutput::Delegate* delegate,
-    mojo::PendingRemote<media::mojom::AudioStreamFactory> stream_factory,
-    const assistant_client::OutputStreamFormat& format) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(!output_device_);
-
-  base::AutoLock lock(lock_);
-
-  delegate_ = delegate;
-  format_ = format;
-  audio_param_ = GetAudioParametersFromBufferFormat(format_);
-  audio_data_.resize(GetBufferSizeInBytesFromBufferFormat(format_));
-  // |audio_fifo_| contains 8x the number of frames to render.
-  audio_fifo_ = std::make_unique<media::AudioBlockFifo>(
-      format.pcm_num_channels, audio_param_.frames_per_buffer(), 8);
-
-  // TODO(wutao): There is a bug LibAssistant sends wrong format. Do not run
-  // in this case.
-  if (format_.pcm_num_channels >
-      static_cast<int>(media::limits::kMaxChannels)) {
-    delegate_->OnEndOfStream();
-    return;
-  }
-
-  ScheduleFillLocked(base::TimeTicks::Now());
-
-  // |stream_factory| is null in unittest.
-  if (stream_factory)
-    StartDevice(std::move(stream_factory), audio_output_delegate);
-}
-
-void AudioDeviceOwner::Stop() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  output_device_.reset();
-  base::AutoLock lock(lock_);
-  if (delegate_) {
-    delegate_->OnStopped();
-    delegate_ = nullptr;
-  }
-}
-
-void AudioDeviceOwner::MediaSessionInfoChanged(
-    media_session::mojom::MediaSessionInfoPtr info) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  // We only handle media ducking case here as intended. Other media
-  // operactions, such as pausing and resuming, are handled by Libassistant
-  // |MediaManager| API in |AssistantManagerServiceImpl|.
-  const bool is_ducking =
-      info->state ==
-      media_session::mojom::MediaSessionInfo::SessionState::kDucking;
-
-  if (output_device_)
-    output_device_->SetVolume(is_ducking ? kDuckingVolume : 1.0);
-}
-
-void AudioDeviceOwner::StartDevice(
-    mojo::PendingRemote<media::mojom::AudioStreamFactory> stream_factory,
-    mojom::AudioOutputDelegate* audio_output_delegate) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  lock_.AssertAcquired();
-
-  output_device_ = std::make_unique<audio::OutputDevice>(
-      std::move(stream_factory), audio_param_, this, device_id_);
-  output_device_->Play();
-
-  audio_output_delegate->AddMediaSessionObserver(
-      session_receiver_.BindNewPipeAndPassRemote());
-}
-
-// Runs on audio renderer thread (started internally in |output_device_|).
-int AudioDeviceOwner::Render(base::TimeDelta delay,
-                             base::TimeTicks delay_timestamp,
-                             const media::AudioGlitchInfo& glitch_info,
-                             media::AudioBus* dest) {
-  base::AutoLock lock(lock_);
-
-  if (!is_filling_ && audio_fifo_->GetAvailableFrames() <= 0) {
-    if (delegate_)
-      delegate_->OnEndOfStream();
-    return 0;
-  }
-  if (audio_fifo_->GetAvailableFrames() <= 0) {
-    // Wait for the next round of filling. This should only happen at the
-    // very beginning.
-    return 0;
-  }
-
-  int available_frames = audio_fifo_->GetAvailableFrames();
-  if (available_frames < dest->frames()) {
-    // In our setting, dest->frames() == frames per block in |audio_fifo_|.
-    DCHECK_EQ(audio_fifo_->available_blocks(), 0);
-
-    int frames_to_fill = audio_param_.frames_per_buffer() - available_frames;
-
-    DCHECK_GE(frames_to_fill, 0);
-
-    // Fill up to one block with zero data so that |audio_fifo_| has 1 block
-    // to consume. This avoids DCHECK in audio_fifo_->Consume() and also
-    // prevents garbage data being copied to |dest| in production.
-    audio_fifo_->PushSilence(frames_to_fill);
-  }
-
-  audio_fifo_->Consume()->CopyTo(dest);
-
-  ScheduleFillLocked(base::TimeTicks::Now() - delay);
-  return dest->frames();
-}
-
-// Runs on audio renderer thread (started internally in |output_device_|).
-void AudioDeviceOwner::OnRenderError() {
-  DVLOG(1) << "OnRenderError()";
-  base::AutoLock lock(lock_);
-  if (delegate_)
-    delegate_->OnError(assistant_client::AudioOutput::Error::FATAL_ERROR);
-}
-
-void AudioDeviceOwner::SetDelegate(
-    assistant_client::AudioOutput::Delegate* delegate) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::AutoLock lock(lock_);
-  delegate_ = delegate;
-}
-
-// Runs on audio renderer thread (started internally in |output_device_|).
-void AudioDeviceOwner::ScheduleFillLocked(const base::TimeTicks& time) {
-  lock_.AssertAcquired();
-  if (is_filling_)
-    return;
-  is_filling_ = true;
-  // FillBuffer will not be called after delegate_->OnEndOfStream, after which
-  // AudioDeviceOwner will be destroyed. Thus |this| is valid for capture
-  // here.
-
-  if (!delegate_)
-    return;
-
-  delegate_->FillBuffer(
-      audio_data_.data(),
-      std::min(static_cast<int>(audio_data_.size()),
-               GetBytesPerFrame(format_) * audio_fifo_->GetUnfilledFrames()),
-      time.since_origin().InMicroseconds(),
-      [this](int num) { this->BufferFillDone(num); });
-}
-
-// Runs on audio renderer thread (started internally in |output_device_|).
-void AudioDeviceOwner::BufferFillDone(int num_bytes) {
-  base::AutoLock lock(lock_);
-  is_filling_ = false;
-  if (num_bytes == 0)
-    return;
-  FillAudioFifoWithDataOfBufferFormat(audio_fifo_.get(), audio_data_, format_,
-                                      num_bytes);
-  if (audio_fifo_->GetUnfilledFrames() > 0)
-    ScheduleFillLocked(base::TimeTicks::Now());
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/audio/audio_device_owner.h b/chromeos/ash/services/libassistant/audio/audio_device_owner.h
deleted file mode 100644
index 82189f3..0000000
--- a/chromeos/ash/services/libassistant/audio/audio_device_owner.h
+++ /dev/null
@@ -1,111 +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 CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_DEVICE_OWNER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_DEVICE_OWNER_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/memory/raw_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/synchronization/lock.h"
-#include "chromeos/ash/services/libassistant/public/mojom/audio_output_delegate.mojom-forward.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "media/base/audio_block_fifo.h"
-#include "media/base/audio_parameters.h"
-#include "media/base/audio_renderer_sink.h"
-#include "media/mojo/mojom/audio_stream_factory.mojom.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "services/audio/public/cpp/output_device.h"
-#include "services/media_session/public/mojom/media_session.mojom.h"
-
-namespace ash::libassistant {
-
-class AudioDeviceOwner : public media::AudioRendererSink::RenderCallback,
-                         media_session::mojom::MediaSessionObserver {
- public:
-  explicit AudioDeviceOwner(const std::string& device_id);
-
-  AudioDeviceOwner(const AudioDeviceOwner&) = delete;
-  AudioDeviceOwner& operator=(const AudioDeviceOwner&) = delete;
-
-  ~AudioDeviceOwner() override;
-
-  void Start(
-      mojom::AudioOutputDelegate* audio_output_delegate,
-      assistant_client::AudioOutput::Delegate* delegate,
-      mojo::PendingRemote<media::mojom::AudioStreamFactory> stream_factory,
-      const assistant_client::OutputStreamFormat& format);
-
-  void Stop();
-
-  // media_session::mojom::MediaSessionObserver overrides:
-  void MediaSessionInfoChanged(
-      media_session::mojom::MediaSessionInfoPtr info) override;
-  void MediaSessionMetadataChanged(
-      const std::optional<::media_session::MediaMetadata>& metadata) override {}
-  void MediaSessionActionsChanged(
-      const std::vector<media_session::mojom::MediaSessionAction>& action)
-      override {}
-  void MediaSessionImagesChanged(
-      const base::flat_map<media_session::mojom::MediaSessionImageType,
-                           std::vector<::media_session::MediaImage>>& images)
-      override {}
-  void MediaSessionPositionChanged(
-      const std::optional<::media_session::MediaPosition>& position) override {}
-
-  // media::AudioRenderSink::RenderCallback overrides:
-  int Render(base::TimeDelta delay,
-             base::TimeTicks delay_timestamp,
-             const media::AudioGlitchInfo& glitch_info,
-             media::AudioBus* dest) override;
-
-  void OnRenderError() override;
-
-  void SetDelegate(assistant_client::AudioOutput::Delegate* delegate);
-
- private:
-  void StartDevice(
-      mojo::PendingRemote<media::mojom::AudioStreamFactory> stream_factory,
-      mojom::AudioOutputDelegate* audio_output_delegate);
-
-  // Requests assistant to fill buffer with more data.
-  void ScheduleFillLocked(const base::TimeTicks& time);
-
-  // Callback for assistant to notify that it completes the filling.
-  void BufferFillDone(int num_bytes);
-
-  base::Lock lock_;
-  std::unique_ptr<media::AudioBlockFifo> audio_fifo_ GUARDED_BY(lock_);
-  // Whether assistant is filling the buffer -- delegate_->FillBuffer is called
-  // and BufferFillDone() is not called yet.
-  bool is_filling_ GUARDED_BY(lock_) = false;
-
-  media::AudioParameters audio_param_ GUARDED_BY(lock_);
-  std::vector<uint8_t> audio_data_ GUARDED_BY(lock_);
-  // Stores audio frames generated by assistant.
-  assistant_client::OutputStreamFormat format_ GUARDED_BY(lock_);
-
-  raw_ptr<assistant_client::AudioOutput::Delegate> delegate_ GUARDED_BY(lock_);
-
-  // Audio output device id used for output.
-  std::string device_id_ GUARDED_BY_CONTEXT(sequence_checker_);
-  std::unique_ptr<audio::OutputDevice> output_device_
-      GUARDED_BY_CONTEXT(sequence_checker_);
-
-  mojo::Receiver<media_session::mojom::MediaSessionObserver> session_receiver_{
-      this};
-
-  // The callbacks from |RenderCallback| are called on a different sequence,
-  // so this sequence checker prevents the other methods from being called on
-  // the render sequence.
-  SEQUENCE_CHECKER(sequence_checker_);
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_DEVICE_OWNER_H_
diff --git a/chromeos/ash/services/libassistant/audio/audio_input_impl.cc b/chromeos/ash/services/libassistant/audio/audio_input_impl.cc
deleted file mode 100644
index 11e5f06..0000000
--- a/chromeos/ash/services/libassistant/audio/audio_input_impl.cc
+++ /dev/null
@@ -1,553 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/audio/audio_input_impl.h"
-
-#include <cstdint>
-#include <optional>
-#include <utility>
-
-#include "base/command_line.h"
-#include "base/functional/bind.h"
-#include "base/logging.h"
-#include "base/memory/weak_ptr.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/strings/string_util.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "chromeos/ash/services/assistant/public/cpp/assistant_browser_delegate.h"
-#include "chromeos/ash/services/assistant/public/cpp/features.h"
-#include "chromeos/ash/services/libassistant/audio/audio_input_stream.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "media/audio/audio_device_description.h"
-#include "media/base/audio_parameters.h"
-#include "media/base/audio_sample_types.h"
-#include "media/base/channel_layout.h"
-#include "media/mojo/mojom/audio_stream_factory.mojom.h"
-#include "services/audio/public/cpp/device_factory.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-constexpr assistant_client::BufferFormat kFormatMono{
-    16000 /* sample_rate */, assistant_client::INTERLEAVED_S16, 1 /* channels */
-};
-
-constexpr assistant_client::BufferFormat kFormatStereo{
-    44100 /* sample_rate */, assistant_client::INTERLEAVED_S16, 2 /* channels */
-};
-
-assistant_client::BufferFormat g_current_format = kFormatMono;
-
-class DspHotwordStateManager : public AudioInputImpl::HotwordStateManager {
- public:
-  explicit DspHotwordStateManager(AudioInputImpl* input)
-      : AudioInputImpl::HotwordStateManager(input) {}
-
-  DspHotwordStateManager(const DspHotwordStateManager&) = delete;
-  DspHotwordStateManager& operator=(const DspHotwordStateManager&) = delete;
-
-  // HotwordStateManager overrides:
-  void OnConversationTurnStarted() override {
-    if (second_phase_timer_.IsRunning()) {
-      DCHECK(stream_state_ == StreamState::HOTWORD);
-      second_phase_timer_.Stop();
-    } else {
-      // Handles user click on mic button.
-      input_->RecreateAudioInputStream(false /* use_dsp */);
-    }
-    stream_state_ = StreamState::NORMAL;
-  }
-
-  void OnConversationTurnFinished() override {
-    if (input_->IsHotwordEnabled()) {
-      input_->RecreateAudioInputStream(true /* use_dsp */);
-      if (stream_state_ == StreamState::HOTWORD) {
-        // If |stream_state_| remains unchanged, that indicates the first stage
-        // DSP hotword detection was rejected by Libassistant.
-        RecordDspHotwordDetection(DspHotwordDetectionStatus::SOFTWARE_REJECTED);
-      }
-    }
-    stream_state_ = StreamState::HOTWORD;
-  }
-
-  void OnCaptureDataArrived() override {
-    if (stream_state_ == StreamState::HOTWORD &&
-        !second_phase_timer_.IsRunning()) {
-      RecordDspHotwordDetection(DspHotwordDetectionStatus::HARDWARE_ACCEPTED);
-      // 1s from now, if OnConversationTurnStarted is not called, we assume that
-      // libassistant has rejected the hotword supplied by DSP. Thus, we reset
-      // and reopen the device on hotword state.
-      second_phase_timer_.Start(
-          FROM_HERE, base::Seconds(1),
-          base::BindRepeating(
-              &DspHotwordStateManager::OnConversationTurnFinished,
-              base::Unretained(this)));
-    }
-  }
-
-  void RecreateAudioInputStream() override {
-    input_->RecreateAudioInputStream(stream_state_ == StreamState::HOTWORD);
-  }
-
- private:
-  enum class StreamState {
-    HOTWORD,
-    NORMAL,
-  };
-
-  // Defines possible detection states of Dsp hotword. These values are
-  // persisted to logs. Entries should not be renumbered and numeric values
-  // should never be reused. Only append to this enum is allowed if the possible
-  // source grows.
-  enum class DspHotwordDetectionStatus {
-    HARDWARE_ACCEPTED = 0,
-    SOFTWARE_REJECTED = 1,
-    kMaxValue = SOFTWARE_REJECTED
-  };
-
-  // Helper function to record UMA metrics for Dsp hotword detection.
-  void RecordDspHotwordDetection(DspHotwordDetectionStatus status) {
-    base::UmaHistogramEnumeration("Assistant.DspHotwordDetection", status);
-  }
-
-  StreamState stream_state_ = StreamState::HOTWORD;
-  base::OneShotTimer second_phase_timer_;
-};
-
-class AudioInputBufferImpl : public assistant_client::AudioBuffer {
- public:
-  AudioInputBufferImpl(std::vector<int16_t>&& data, uint32_t frame_count)
-      : data_(std::move(data)), frame_count_(frame_count) {}
-  AudioInputBufferImpl(const AudioInputBufferImpl&) = delete;
-  AudioInputBufferImpl& operator=(const AudioInputBufferImpl&) = delete;
-  AudioInputBufferImpl(AudioInputBufferImpl&&) = default;
-  AudioInputBufferImpl& operator=(AudioInputBufferImpl&&) = default;
-  ~AudioInputBufferImpl() override = default;
-
-  // assistant_client::AudioBuffer overrides:
-  assistant_client::BufferFormat GetFormat() const override {
-    return g_current_format;
-  }
-  const void* GetData() const override { return data_.data(); }
-  void* GetWritableData() override { NOTREACHED(); }
-  int GetFrameCount() const override { return frame_count_; }
-
- private:
-  std::vector<int16_t> data_;
-  int frame_count_;
-};
-
-AudioInputBufferImpl ToAudioInputBuffer(const media::AudioBus* audio_source) {
-  std::vector<int16_t> buffer(audio_source->channels() *
-                              audio_source->frames());
-  audio_source->ToInterleaved<media::SignedInt16SampleTypeTraits>(
-      audio_source->frames(), buffer.data());
-  return AudioInputBufferImpl(std::move(buffer), audio_source->frames());
-}
-
-}  // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// AudioCapturer
-////////////////////////////////////////////////////////////////////////////////
-
-// Helper class that will receive the callbacks from the audio source,
-// and forward the audio data to Libassistant.
-// Note that all callback methods in this object run on the audio service
-// thread, so this class should be treated carefully.
-// All public methods can be called from other threads, and the
-// |on_capture_callback| will be invoked on the given callback thread.
-class AudioCapturer : public media::AudioCapturerSource::CaptureCallback {
- public:
-  explicit AudioCapturer(
-      base::RepeatingCallback<void()> on_capture_callback,
-      scoped_refptr<base::SequencedTaskRunner> callback_task_runner)
-      : on_capture_callback_(on_capture_callback),
-        callback_task_runner_(callback_task_runner) {}
-  AudioCapturer(const AudioCapturer&) = delete;
-  AudioCapturer& operator=(const AudioCapturer&) = delete;
-  ~AudioCapturer() override = default;
-
-  void AddObserver(assistant_client::AudioInput::Observer* observer) {
-    base::AutoLock lock(observers_lock_);
-    observers_.push_back(observer);
-  }
-
-  void RemoveObserver(assistant_client::AudioInput::Observer* observer) {
-    base::AutoLock lock(observers_lock_);
-    std::erase(observers_, observer);
-  }
-
-  int num_observers() {
-    base::AutoLock lock(observers_lock_);
-    return observers_.size();
-  }
-
-  int captured_frames_count() { return captured_frames_count_; }
-
- private:
-  // media::AudioCapturerSource::CaptureCallback implementation:
-  // Runs on audio service thread.
-  void Capture(const media::AudioBus* audio_source,
-               base::TimeTicks audio_capture_time,
-               const media::AudioGlitchInfo& glitch_info,
-               double volume) override {
-    DCHECK_EQ(g_current_format.num_channels, audio_source->channels());
-
-    callback_task_runner_->PostTask(FROM_HERE, on_capture_callback_);
-
-    UpdateCapturedFramesCount(audio_source->frames());
-
-    AudioInputBufferImpl input_buffer(ToAudioInputBuffer(audio_source));
-    int64_t time = ToLibassistantTime(audio_capture_time);
-
-    base::AutoLock lock(observers_lock_);
-    for (auto* observer : observers_)
-      observer->OnAudioBufferAvailable(input_buffer, time);
-  }
-
-  // Runs on audio service thread.
-  void OnCaptureError(media::AudioCapturerSource::ErrorCode code,
-                      const std::string& message) override {
-    LOG(ERROR) << "Capture error " << message
-               << ", code=" << static_cast<uint32_t>(code);
-    base::AutoLock lock(observers_lock_);
-    for (auto* observer : observers_)
-      observer->OnAudioError(assistant_client::AudioInput::Error::FATAL_ERROR);
-  }
-
-  // Runs on audio service thread.
-  void OnCaptureMuted(bool is_muted) override {}
-
-  int64_t ToLibassistantTime(base::TimeTicks audio_capture_time) const {
-    // Only provide accurate timestamp when eraser is enabled, otherwise it
-    // seems break normal libassistant voice recognition.
-    if (assistant::features::IsAudioEraserEnabled())
-      return audio_capture_time.since_origin().InMicroseconds();
-    return 0;
-  }
-
-  void UpdateCapturedFramesCount(int num_arrived_frames) {
-    captured_frames_count_ += num_arrived_frames;
-    if (VLOG_IS_ON(1)) {
-      auto now = base::TimeTicks::Now();
-      if ((now - last_frame_count_report_time_) > base::Minutes(2)) {
-        VLOG(1) << "Captured frames: " << captured_frames_count_;
-        last_frame_count_report_time_ = now;
-      }
-    }
-  }
-
-  // This is the total number of frames captured during the life time of this
-  // object. We don't worry about overflow because this count is only used for
-  // logging purposes. If in the future this changes, we should re-evaluate.
-  int captured_frames_count_ = 0;
-  base::TimeTicks last_frame_count_report_time_;
-
-  base::Lock observers_lock_;
-  std::vector<assistant_client::AudioInput::Observer*> observers_
-      GUARDED_BY(observers_lock_);
-
-  // |on_capture_callback| must always be called from the main thread.
-  base::RepeatingCallback<void()> on_capture_callback_;
-  scoped_refptr<base::SequencedTaskRunner> callback_task_runner_;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// AudioInputImpl
-////////////////////////////////////////////////////////////////////////////////
-
-AudioInputImpl::HotwordStateManager::HotwordStateManager(
-    AudioInputImpl* audio_input)
-    : input_(audio_input) {}
-
-void AudioInputImpl::HotwordStateManager::RecreateAudioInputStream() {
-  input_->RecreateAudioInputStream(/*use_dsp=*/false);
-}
-
-AudioInputImpl::AudioInputImpl(const std::optional<std::string>& device_id)
-    : task_runner_(base::SequencedTaskRunner::GetCurrentDefault()),
-      preferred_device_id_(device_id),
-      weak_factory_(this) {
-  DETACH_FROM_SEQUENCE(observer_sequence_checker_);
-
-  audio_capturer_ = std::make_unique<AudioCapturer>(
-      base::BindRepeating(&AudioInputImpl::OnCaptureDataArrived,
-                          weak_factory_.GetWeakPtr()),
-      /*callback_task_runner=*/base::SequencedTaskRunner::GetCurrentDefault());
-
-  RecreateStateManager();
-  if (assistant::features::IsStereoAudioInputEnabled())
-    g_current_format = kFormatStereo;
-  else
-    g_current_format = kFormatMono;
-}
-
-AudioInputImpl::~AudioInputImpl() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  StopRecording();
-}
-
-void AudioInputImpl::RecreateStateManager() {
-  if (IsHotwordAvailable()) {
-    state_manager_ = std::make_unique<DspHotwordStateManager>(this);
-  } else {
-    state_manager_ = std::make_unique<HotwordStateManager>(this);
-  }
-}
-
-void AudioInputImpl::OnCaptureDataArrived() {
-  state_manager_->OnCaptureDataArrived();
-}
-
-void AudioInputImpl::Initialize(mojom::PlatformDelegate* platform_delegate) {
-  platform_delegate_ = platform_delegate;
-  DCHECK(platform_delegate_);
-  UpdateRecordingState();
-}
-
-// Run on LibAssistant thread.
-assistant_client::BufferFormat AudioInputImpl::GetFormat() const {
-  return g_current_format;
-}
-
-// Run on LibAssistant thread.
-void AudioInputImpl::AddObserver(
-    assistant_client::AudioInput::Observer* observer) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(observer_sequence_checker_);
-  VLOG(1) << "Add observer";
-
-  audio_capturer_->AddObserver(observer);
-
-  if (audio_capturer_->num_observers() == 1) {
-    // Post to main thread runner to start audio recording. Assistant thread
-    // does not have thread context defined in //base and will fail sequence
-    // check in AudioCapturerSource::Start().
-    task_runner_->PostTask(FROM_HERE,
-                           base::BindOnce(&AudioInputImpl::UpdateRecordingState,
-                                          weak_factory_.GetWeakPtr()));
-  }
-}
-
-// Run on LibAssistant thread.
-void AudioInputImpl::RemoveObserver(
-    assistant_client::AudioInput::Observer* observer) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(observer_sequence_checker_);
-  VLOG(1) << "Remove observer";
-
-  audio_capturer_->RemoveObserver(observer);
-
-  if (audio_capturer_->num_observers() == 0) {
-    task_runner_->PostTask(FROM_HERE,
-                           base::BindOnce(&AudioInputImpl::UpdateRecordingState,
-                                          weak_factory_.GetWeakPtr()));
-
-    // Reset the sequence checker since assistant may call from different thread
-    // after restart.
-    DETACH_FROM_SEQUENCE(observer_sequence_checker_);
-  }
-}
-
-void AudioInputImpl::SetMicState(bool mic_open) {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  if (mic_open_ == mic_open)
-    return;
-
-  mic_open_ = mic_open;
-  UpdateRecordingState();
-}
-
-void AudioInputImpl::OnConversationTurnStarted() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  state_manager_->OnConversationTurnStarted();
-}
-
-void AudioInputImpl::OnConversationTurnFinished() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  state_manager_->OnConversationTurnFinished();
-}
-
-void AudioInputImpl::OnHotwordEnabled(bool enable) {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-
-  if (hotword_enabled_ == enable)
-    return;
-
-  hotword_enabled_ = enable;
-  UpdateRecordingState();
-}
-
-void AudioInputImpl::SetDeviceId(const std::optional<std::string>& device_id) {
-  DVLOG(1) << "Set audio input preferred_device_id to "
-           << device_id.value_or("<null>");
-  auto new_device_id = device_id;
-
-  constexpr char kAssistantForceDefaultAudioInput[] =
-      "assistant-force-default-audio-input";
-  auto* command_line = base::CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(kAssistantForceDefaultAudioInput)) {
-    // Sometimes there may not be a preferred audio device,
-    // e.g. if the device does not have built-in mic and using a bluetooth
-    // microphone, in this case we do not want to open the bluetooth device by
-    // default to drain the battery; also if running linux chromeos chrome
-    // build, there won't be cras and we won't have a device id set. Force using
-    // default audio input in these cases to mimic the common Assistant hotword
-    // behaviors.
-    DVLOG(1) << "Force audio input preferred_device_id to default.";
-    new_device_id = media::AudioDeviceDescription::kDefaultDeviceId;
-  }
-
-  if (preferred_device_id_ == new_device_id)
-    return;
-
-  preferred_device_id_ = new_device_id;
-
-  UpdateRecordingState();
-  if (HasOpenAudioStream())
-    state_manager_->RecreateAudioInputStream();
-}
-
-void AudioInputImpl::SetHotwordDeviceId(
-    const std::optional<std::string>& device_id) {
-  if (hotword_device_id_ == device_id)
-    return;
-
-  hotword_device_id_ = device_id;
-  RecreateStateManager();
-  if (HasOpenAudioStream())
-    state_manager_->RecreateAudioInputStream();
-}
-
-void AudioInputImpl::OnLidStateChanged(mojom::LidState new_state) {
-  // Lid switch event still gets fired during system suspend, which enables
-  // us to stop DSP recording correctly when user closes lid after the device
-  // goes to sleep.
-  if (new_state != lid_state_) {
-    lid_state_ = new_state;
-    UpdateRecordingState();
-  }
-}
-
-void AudioInputImpl::RecreateAudioInputStream(bool use_dsp) {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  StopRecording();
-
-  open_audio_stream_ = std::make_unique<AudioInputStream>(
-      platform_delegate_, GetDeviceId(use_dsp),
-      ShouldEnableDeadStreamDetection(use_dsp), GetFormat(),
-      /*capture_callback=*/audio_capturer_.get());
-
-  VLOG(1) << open_audio_stream_->device_id() << " start recording";
-}
-
-bool AudioInputImpl::IsHotwordAvailable() const {
-  return assistant::features::IsDspHotwordEnabled() &&
-         hotword_device_id_.has_value();
-}
-
-bool AudioInputImpl::IsRecordingForTesting() const {
-  return HasOpenAudioStream();
-}
-
-bool AudioInputImpl::IsUsingHotwordDeviceForTesting() const {
-  return IsRecordingForTesting()  // IN-TEST
-         && GetOpenDeviceId() == hotword_device_id_ && IsHotwordAvailable();
-}
-
-bool AudioInputImpl::IsMicOpenForTesting() const {
-  return mic_open_;
-}
-
-std::optional<std::string> AudioInputImpl::GetOpenDeviceIdForTesting() const {
-  return GetOpenDeviceId();
-}
-
-std::optional<bool> AudioInputImpl::IsUsingDeadStreamDetectionForTesting()
-    const {
-  if (!open_audio_stream_)
-    return std::nullopt;
-  return open_audio_stream_->has_dead_stream_detection();
-}
-
-void AudioInputImpl::OnCaptureDataArrivedForTesting() {
-  OnCaptureDataArrived();
-}
-
-void AudioInputImpl::StartRecording() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(!HasOpenAudioStream());
-  RecreateAudioInputStream(IsHotwordAvailable() && IsHotwordEnabled());
-}
-
-void AudioInputImpl::StopRecording() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  if (open_audio_stream_) {
-    VLOG(1) << open_audio_stream_->device_id() << " stop recording";
-    VLOG(1) << open_audio_stream_->device_id() << " ending captured frames: "
-            << audio_capturer_->captured_frames_count();
-    open_audio_stream_.reset();
-  }
-}
-
-void AudioInputImpl::UpdateRecordingState() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-
-  bool has_observers = (audio_capturer_->num_observers() > 0);
-  bool is_lid_closed = (lid_state_ == mojom::LidState::kClosed);
-  bool should_enable_hotword =
-      hotword_enabled_ && preferred_device_id_.has_value();
-  bool has_delegate = (platform_delegate_ != nullptr);
-  bool should_start = !is_lid_closed && (should_enable_hotword || mic_open_) &&
-                      has_observers && has_delegate;
-
-  VLOG(1) << "UpdateRecordingState: "
-          << "    is_lid_closed: " << is_lid_closed << "\n"
-          << "    hotword_enabled: " << hotword_enabled_ << "\n"
-          << "    preferred_device_id: '"
-          << preferred_device_id_.value_or("<unset>") << "'\n"
-          << "    hotword_device_id: '"
-          << hotword_device_id_.value_or("<unset>") << "'\n"
-          << "    mic_open: " << mic_open_ << "\n"
-          << "    has_observers: " << has_observers << "\n"
-          << "    has_delegate: " << has_delegate << "\n"
-          << " => should_start: " << should_start;
-
-  if (!HasOpenAudioStream() && should_start)
-    StartRecording();
-  else if (HasOpenAudioStream() && !should_start)
-    StopRecording();
-}
-
-std::string AudioInputImpl::GetDeviceId(bool use_dsp) const {
-  if (use_dsp && hotword_device_id_.has_value())
-    return hotword_device_id_.value();
-  else if (preferred_device_id_.has_value())
-    return preferred_device_id_.value();
-  else
-    return media::AudioDeviceDescription::kDefaultDeviceId;
-}
-
-std::optional<std::string> AudioInputImpl::GetOpenDeviceId() const {
-  if (!open_audio_stream_)
-    return std::nullopt;
-  return open_audio_stream_->device_id();
-}
-
-bool AudioInputImpl::ShouldEnableDeadStreamDetection(bool use_dsp) const {
-  if (use_dsp && hotword_device_id_.has_value()) {
-    // The DSP device won't provide data until it detects a hotword, so
-    // we disable its the dead stream detection.
-    return false;
-  }
-  return true;
-}
-
-bool AudioInputImpl::HasOpenAudioStream() const {
-  return open_audio_stream_ != nullptr;
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/audio/audio_input_impl.h b/chromeos/ash/services/libassistant/audio/audio_input_impl.h
deleted file mode 100644
index 0706277..0000000
--- a/chromeos/ash/services/libassistant/audio/audio_input_impl.h
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_INPUT_IMPL_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_INPUT_IMPL_H_
-
-#include <memory>
-#include <optional>
-#include <string>
-#include <vector>
-
-#include "base/memory/raw_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/synchronization/lock.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/assistant/public/cpp/assistant_service.h"
-#include "chromeos/ash/services/libassistant/public/mojom/audio_input_controller.mojom.h"
-#include "chromeos/ash/services/libassistant/public/mojom/platform_delegate.mojom.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "media/base/audio_capturer_source.h"
-#include "mojo/public/cpp/bindings/remote.h"
-
-namespace ash::libassistant {
-
-class AudioInputStream;
-class AudioCapturer;
-
-// AudioInputImpl automatically falls back to libassistant based hotword
-// detection if DSP device id is not available.
-// TODO(b/242776750): Remove this behavior if possible to simplify
-// AudioInputImpl.
-class AudioInputImpl : public assistant_client::AudioInput {
- public:
-  explicit AudioInputImpl(const std::optional<std::string>& device_id);
-  AudioInputImpl(const AudioInputImpl&) = delete;
-  AudioInputImpl& operator=(const AudioInputImpl&) = delete;
-  ~AudioInputImpl() override;
-
-  class HotwordStateManager {
-   public:
-    explicit HotwordStateManager(AudioInputImpl* audio_input_);
-    HotwordStateManager(const HotwordStateManager&) = delete;
-    HotwordStateManager& operator=(const HotwordStateManager&) = delete;
-    virtual ~HotwordStateManager() = default;
-
-    virtual void OnConversationTurnStarted() {}
-    virtual void OnConversationTurnFinished() {}
-    virtual void OnCaptureDataArrived() {}
-    virtual void RecreateAudioInputStream();
-
-   protected:
-    raw_ptr<AudioInputImpl> input_;
-  };
-
-  void Initialize(mojom::PlatformDelegate* platform_delegate);
-
-  // assistant_client::AudioInput overrides. These function are called by
-  // assistant from assistant thread, for which we should not assume any
-  // //base related thread context to be in place.
-  assistant_client::BufferFormat GetFormat() const override;
-  void AddObserver(assistant_client::AudioInput::Observer* observer) override;
-  void RemoveObserver(
-      assistant_client::AudioInput::Observer* observer) override;
-
-  // Called when the mic state associated with the interaction is changed.
-  void SetMicState(bool mic_open);
-  void OnConversationTurnStarted();
-  void OnConversationTurnFinished();
-
-  // Called when hotword enabled status changed.
-  void OnHotwordEnabled(bool enable);
-
-  void SetDeviceId(const std::optional<std::string>& device_id);
-  void SetHotwordDeviceId(const std::optional<std::string>& device_id);
-
-  // Called when the user opens/closes the lid.
-  void OnLidStateChanged(mojom::LidState new_state);
-
-  void RecreateAudioInputStream(bool use_dsp);
-
-  bool IsHotwordAvailable() const;
-  bool IsHotwordEnabled() const { return hotword_enabled_; }
-
-  // Returns the recording state used in unittests.
-  bool IsRecordingForTesting() const;
-  // Returns if the hotword device is used for recording now.
-  bool IsUsingHotwordDeviceForTesting() const;
-  // Returns if the state of device's microphone is currently open.
-  bool IsMicOpenForTesting() const;
-  // Returns the id of the device that is currently recording audio.
-  // Returns nullopt if no audio is being recorded.
-  std::optional<std::string> GetOpenDeviceIdForTesting() const;
-  // Returns if dead stream detection is being used for the current audio
-  // recording. Returns nullopt if no audio is being recorded.
-  std::optional<bool> IsUsingDeadStreamDetectionForTesting() const;
-  // Calls |OnCaptureDataArrived| to simulate audio input.
-  void OnCaptureDataArrivedForTesting();
-
- private:
-  void RecreateStateManager();
-  void OnCaptureDataArrived();
-
-  void StartRecording();
-  void StopRecording();
-  void UpdateRecordingState();
-
-  std::string GetDeviceId(bool use_dsp) const;
-  std::optional<std::string> GetOpenDeviceId() const;
-  bool ShouldEnableDeadStreamDetection(bool use_dsp) const;
-  bool HasOpenAudioStream() const;
-
-  // User explicitly requested to open microphone.
-  bool mic_open_ = false;
-
-  // Whether hotword is currently enabled.
-  bool hotword_enabled_ = true;
-
-  // To be initialized on assistant thread the first call to AddObserver.
-  // It ensures that AddObserver / RemoveObserver are called on the same
-  // sequence.
-  SEQUENCE_CHECKER(observer_sequence_checker_);
-
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
-
-  std::unique_ptr<HotwordStateManager> state_manager_;
-  std::unique_ptr<AudioCapturer> audio_capturer_;
-
-  // Owned by |LibassistantService|.
-  raw_ptr<mojom::PlatformDelegate> platform_delegate_ = nullptr;
-
-  // Preferred audio input device which will be used for capture.
-  std::optional<std::string> preferred_device_id_;
-  // Hotword input device used for hardware based hotword detection.
-  std::optional<std::string> hotword_device_id_;
-
-  // Currently open audio stream. nullptr if no audio stream is open.
-  std::unique_ptr<AudioInputStream> open_audio_stream_;
-
-  // Start with lidstate |kClosed| so we do not open the microphone before we
-  // know if the lid is open or closed.
-  mojom::LidState lid_state_ = mojom::LidState ::kClosed;
-
-  base::WeakPtrFactory<AudioInputImpl> weak_factory_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_INPUT_IMPL_H_
diff --git a/chromeos/ash/services/libassistant/audio/audio_input_provider_impl.cc b/chromeos/ash/services/libassistant/audio/audio_input_provider_impl.cc
deleted file mode 100644
index f4df5398..0000000
--- a/chromeos/ash/services/libassistant/audio/audio_input_provider_impl.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/audio/audio_input_provider_impl.h"
-
-#include "base/time/time.h"
-#include "chromeos/ash/services/assistant/public/cpp/features.h"
-
-namespace ash::libassistant {
-
-AudioInputProviderImpl::AudioInputProviderImpl()
-    : audio_input_(/*device_id=*/std::nullopt) {}
-
-AudioInputProviderImpl::~AudioInputProviderImpl() = default;
-
-AudioInputImpl& AudioInputProviderImpl::GetAudioInput() {
-  return audio_input_;
-}
-
-int64_t AudioInputProviderImpl::GetCurrentAudioTime() {
-  if (assistant::features::IsAudioEraserEnabled())
-    return base::TimeTicks::Now().since_origin().InMicroseconds();
-
-  return 0;
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/audio/audio_input_provider_impl.h b/chromeos/ash/services/libassistant/audio/audio_input_provider_impl.h
deleted file mode 100644
index c56402a..0000000
--- a/chromeos/ash/services/libassistant/audio/audio_input_provider_impl.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_INPUT_PROVIDER_IMPL_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_INPUT_PROVIDER_IMPL_H_
-
-#include <cstdint>
-
-#include "chromeos/ash/services/libassistant/audio/audio_input_impl.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-
-namespace ash::libassistant {
-
-class AudioInputProviderImpl : public assistant_client::AudioInputProvider {
- public:
-  AudioInputProviderImpl();
-  AudioInputProviderImpl(const AudioInputProviderImpl&) = delete;
-  AudioInputProviderImpl& operator=(const AudioInputProviderImpl&) = delete;
-  ~AudioInputProviderImpl() override;
-
-  // assistant_client::AudioInputProvider overrides:
-  AudioInputImpl& GetAudioInput() override;
-  int64_t GetCurrentAudioTime() override;
-
- private:
-  AudioInputImpl audio_input_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_INPUT_PROVIDER_IMPL_H_
diff --git a/chromeos/ash/services/libassistant/audio/audio_input_stream.cc b/chromeos/ash/services/libassistant/audio/audio_input_stream.cc
deleted file mode 100644
index 9116576..0000000
--- a/chromeos/ash/services/libassistant/audio/audio_input_stream.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/audio/audio_input_stream.h"
-
-#include "base/notreached.h"
-#include "chromeos/ash/services/libassistant/buildflags.h"
-#include "chromeos/ash/services/libassistant/public/mojom/audio_input_controller.mojom.h"
-#include "chromeos/ash/services/libassistant/public/mojom/platform_delegate.mojom.h"
-
-#if BUILDFLAG(ENABLE_FAKE_ASSISTANT_MICROPHONE)
-#include "chromeos/ash/services/libassistant/audio/fake_input_device.h"
-#endif  // BUILDFLAG(ENABLE_FAKE_ASSISTANT_MICROPHONE)
-
-namespace ash::libassistant {
-
-namespace {
-
-#if !BUILDFLAG(ENABLE_FAKE_ASSISTANT_MICROPHONE)
-audio::DeadStreamDetection ToDeadStreamDetection(bool detect_dead_stream) {
-  return detect_dead_stream ? audio::DeadStreamDetection::kEnabled
-                            : audio::DeadStreamDetection::kDisabled;
-}
-#endif  // !BUILDFLAG(ENABLE_FAKE_ASSISTANT_MICROPHONE)
-
-}  // namespace
-
-AudioInputStream::AudioInputStream(
-    mojom::PlatformDelegate* delegate,
-    const std::string& device_id,
-    bool detect_dead_stream,
-    assistant_client::BufferFormat buffer_format,
-    media::AudioCapturerSource::CaptureCallback* capture_callback)
-    : device_id_(device_id),
-      detect_dead_stream_(detect_dead_stream),
-      buffer_format_(buffer_format),
-      delegate_(delegate),
-      capture_callback_(capture_callback) {
-  Start();
-}
-
-AudioInputStream::~AudioInputStream() {
-  Stop();
-}
-
-void AudioInputStream::Start() {
-  mojo::PendingRemote<media::mojom::AudioStreamFactory> audio_stream_factory;
-  delegate_->BindAudioStreamFactory(
-      audio_stream_factory.InitWithNewPipeAndPassReceiver());
-
-#if BUILDFLAG(ENABLE_FAKE_ASSISTANT_MICROPHONE)
-  source_ = CreateFakeInputDevice();
-#else
-  source_ =
-      audio::CreateInputDevice(std::move(audio_stream_factory), device_id(),
-                               ToDeadStreamDetection(detect_dead_stream_));
-#endif  // BUILDFLAG(ENABLE_FAKE_ASSISTANT_MICROPHONE)
-
-  source_->Initialize(GetAudioParameters(), capture_callback_);
-  source_->Start();
-}
-
-void AudioInputStream::Stop() {
-  if (source_) {
-    source_->Stop();
-    source_.reset();
-  }
-}
-
-media::AudioParameters AudioInputStream::GetAudioParameters() const {
-  // AUDIO_PCM_LINEAR and AUDIO_PCM_LOW_LATENCY are the same on CRAS.
-  auto result = media::AudioParameters(
-      media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
-      media::ChannelLayoutConfig::Guess(buffer_format_.num_channels),
-      buffer_format_.sample_rate,
-      buffer_format_.sample_rate / 10 /* buffer size for 100 ms */);
-
-  // Set the HOTWORD mask so CRAS knows the device is used for HOTWORD purpose
-  // and is able to conduct the tuning specifically for the scenario. Whether
-  // the HOTWORD is conducted by a hotword device or other devices like
-  // internal mic will be determined by the device_id passed to CRAS.
-  result.set_effects(media::AudioParameters::PlatformEffectsMask::HOTWORD);
-
-  return result;
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/audio/audio_input_stream.h b/chromeos/ash/services/libassistant/audio/audio_input_stream.h
deleted file mode 100644
index 5cc6f2f..0000000
--- a/chromeos/ash/services/libassistant/audio/audio_input_stream.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_INPUT_STREAM_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_INPUT_STREAM_H_
-
-#include <string>
-
-#include "base/memory/raw_ptr.h"
-#include "base/memory/scoped_refptr.h"
-#include "chromeos/ash/services/libassistant/public/mojom/audio_input_controller.mojom-forward.h"
-#include "chromeos/ash/services/libassistant/public/mojom/platform_delegate.mojom-forward.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "media/base/audio_capturer_source.h"
-#include "media/mojo/mojom/audio_stream_factory.mojom.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/audio/public/cpp/device_factory.h"
-
-namespace ash::libassistant {
-
-// A single audio stream. All captured packets will be sent to the given
-// capture callback.
-// The audio stream will be opened as soon as this class is created, and
-// will be closed in the destructor.
-class AudioInputStream {
- public:
-  AudioInputStream(
-      mojom::PlatformDelegate* delegate,
-      const std::string& device_id,
-      bool detect_dead_stream,
-      assistant_client::BufferFormat buffer_format,
-      media::AudioCapturerSource::CaptureCallback* capture_callback);
-  AudioInputStream(AudioInputStream&) = delete;
-  AudioInputStream& operator=(AudioInputStream&) = delete;
-  ~AudioInputStream();
-
-  const std::string& device_id() const { return device_id_; }
-
-  bool has_dead_stream_detection() const { return detect_dead_stream_; }
-
- private:
-  void Start();
-  void Stop();
-
-  media::AudioParameters GetAudioParameters() const;
-
-  // Device used for recording.
-  std::string device_id_;
-  bool detect_dead_stream_;
-  assistant_client::BufferFormat buffer_format_;
-  const raw_ptr<mojom::PlatformDelegate> delegate_;
-  const raw_ptr<media::AudioCapturerSource::CaptureCallback> capture_callback_;
-  scoped_refptr<media::AudioCapturerSource> source_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_INPUT_STREAM_H_
diff --git a/chromeos/ash/services/libassistant/audio/audio_media_data_source.cc b/chromeos/ash/services/libassistant/audio/audio_media_data_source.cc
deleted file mode 100644
index a611962..0000000
--- a/chromeos/ash/services/libassistant/audio/audio_media_data_source.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/audio/audio_media_data_source.h"
-
-#include <algorithm>
-
-#include "base/functional/bind.h"
-#include "base/functional/callback_helpers.h"
-#include "base/sequence_checker.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/time/time.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-// The maximum number of bytes to decode on each iteration.
-// 512 was chosen to make sure decoding does not block for long.
-constexpr uint32_t kMaxBytesToDecode = 512;
-
-}  // namespace
-
-AudioMediaDataSource::AudioMediaDataSource(
-    mojo::PendingReceiver<AssistantMediaDataSource> receiver)
-    : receiver_(this, std::move(receiver)),
-      task_runner_(base::SequencedTaskRunner::GetCurrentDefault()),
-      weak_factory_(this) {}
-
-AudioMediaDataSource::~AudioMediaDataSource() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (read_callback_) {
-    // During shutdown, it is possible we received a call to |Read()| but have
-    // not received the data from Libassistant yet. In that case we must still
-    // call the |read_callback_| to satisfy the mojom API contract.
-    OnFillBuffer(0);
-  }
-}
-
-void AudioMediaDataSource::Read(uint32_t size, ReadCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  // Note: mojom calls are sequenced, so we should not receive a second call to
-  // Read() before we consumed the previous |read_callback_|.
-  DCHECK(!read_callback_);
-  read_callback_ = std::move(callback);
-
-  if (!delegate_) {
-    OnFillBuffer(0);
-    return;
-  }
-
-  size = std::min(size, kMaxBytesToDecode);
-  source_buffer_.resize(size);
-
-  delegate_->FillBuffer(
-      source_buffer_.data(), source_buffer_.size(),
-      // TODO(wutao): This should be a future time that these buffers would be
-      // played.
-      base::TimeTicks::Now().since_origin().InMicroseconds(),
-      [task_runner = task_runner_,
-       weak_ptr = weak_factory_.GetWeakPtr()](int bytes_available) {
-        task_runner->PostTask(
-            FROM_HERE, base::BindOnce(&AudioMediaDataSource::OnFillBuffer,
-                                      weak_ptr, bytes_available));
-      });
-}
-
-void AudioMediaDataSource::OnFillBuffer(int bytes_filled) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(read_callback_);
-  source_buffer_.resize(bytes_filled);
-  std::move(read_callback_).Run(source_buffer_);
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/audio/audio_media_data_source.h b/chromeos/ash/services/libassistant/audio/audio_media_data_source.h
deleted file mode 100644
index 1d91329..0000000
--- a/chromeos/ash/services/libassistant/audio/audio_media_data_source.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_MEDIA_DATA_SOURCE_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_MEDIA_DATA_SOURCE_H_
-
-#include <vector>
-
-#include "base/memory/raw_ptr.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/task/single_thread_task_runner.h"
-#include "chromeos/ash/services/assistant/public/mojom/assistant_audio_decoder.mojom.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-
-namespace ash::libassistant {
-
-// Class to provide media data source for audio stream decoder.
-// Internally it will read media data from |delegate_|.
-class AudioMediaDataSource : public assistant::mojom::AssistantMediaDataSource {
- public:
-  explicit AudioMediaDataSource(
-      mojo::PendingReceiver<assistant::mojom::AssistantMediaDataSource>
-          receiver);
-
-  AudioMediaDataSource(const AudioMediaDataSource&) = delete;
-  AudioMediaDataSource& operator=(const AudioMediaDataSource&) = delete;
-
-  ~AudioMediaDataSource() override;
-
-  // assistant::mojom::MediaDataSource implementation.
-  // Must be called after |set_delegate()|.
-  // The caller must wait for callback to finish before issuing the next read.
-  void Read(uint32_t size, ReadCallback callback) override;
-
-  void set_delegate(assistant_client::AudioOutput::Delegate* delegate) {
-    delegate_ = delegate;
-  }
-
- private:
-  void OnFillBuffer(int bytes_filled);
-
-  mojo::Receiver<AssistantMediaDataSource> receiver_;
-
-  // The callback from |delegate_| runs on a different sequence, so this
-  // sequence checker prevents the other methods from being called on the wrong
-  // sequence.
-  SEQUENCE_CHECKER(sequence_checker_);
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
-
-  raw_ptr<assistant_client::AudioOutput::Delegate> delegate_ = nullptr;
-
-  std::vector<uint8_t> source_buffer_;
-
-  ReadCallback read_callback_;
-
-  base::WeakPtrFactory<AudioMediaDataSource> weak_factory_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_MEDIA_DATA_SOURCE_H_
diff --git a/chromeos/ash/services/libassistant/audio/audio_output_provider_impl.cc b/chromeos/ash/services/libassistant/audio/audio_output_provider_impl.cc
deleted file mode 100644
index 3b4e223..0000000
--- a/chromeos/ash/services/libassistant/audio/audio_output_provider_impl.cc
+++ /dev/null
@@ -1,312 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/audio/audio_output_provider_impl.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "ash/constants/ash_features.h"
-#include "base/functional/bind.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/assistant/public/mojom/assistant_audio_decoder.mojom.h"
-#include "chromeos/ash/services/libassistant/audio/audio_stream_handler.h"
-#include "chromeos/ash/services/libassistant/public/mojom/platform_delegate.mojom.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "media/audio/audio_device_description.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-bool IsEncodedFormat(const assistant_client::OutputStreamFormat& format) {
-  return format.encoding ==
-             assistant_client::OutputStreamEncoding::STREAM_MP3 ||
-         format.encoding ==
-             assistant_client::OutputStreamEncoding::STREAM_OPUS_IN_OGG;
-}
-
-// Instances of this class will be owned by Libassistant, so any public method
-// (including the constructor and destructor) can and will be called from other
-// threads.
-class AudioOutputImpl : public assistant_client::AudioOutput {
- public:
-  AudioOutputImpl(
-      AudioOutputProviderImpl* audio_output_provider_impl,
-      mojo::PendingRemote<media::mojom::AudioStreamFactory> stream_factory,
-      scoped_refptr<base::SequencedTaskRunner> main_task_runner,
-      mojom::AudioOutputDelegate* audio_output_delegate,
-      assistant_client::OutputStreamType type,
-      assistant_client::OutputStreamFormat format,
-      const std::string& device_id)
-      : audio_output_provider_impl_(audio_output_provider_impl),
-        main_task_runner_(main_task_runner),
-        stream_factory_(std::move(stream_factory)),
-        audio_output_delegate_(audio_output_delegate),
-        stream_type_(type),
-        format_(format) {
-    // The constructor runs on the Libassistant thread, so we need to detach the
-    // main sequence checker.
-    DETACH_FROM_SEQUENCE(main_sequence_checker_);
-    main_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&AudioOutputImpl::InitializeOnMainThread,
-                                  weak_ptr_factory_.GetWeakPtr(), device_id));
-  }
-
-  AudioOutputImpl(const AudioOutputImpl&) = delete;
-  AudioOutputImpl& operator=(const AudioOutputImpl&) = delete;
-
-  ~AudioOutputImpl() override {
-    main_task_runner_->ReleaseSoon(FROM_HERE,
-                                   std::move(audio_decoder_factory_manager_));
-    main_task_runner_->DeleteSoon(FROM_HERE, device_owner_.release());
-    main_task_runner_->DeleteSoon(FROM_HERE, audio_stream_handler_.release());
-  }
-
-  // assistant_client::AudioOutput overrides:
-  assistant_client::OutputStreamType GetType() override { return stream_type_; }
-
-  void Start(assistant_client::AudioOutput::Delegate* delegate) override {
-    main_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&AudioOutputImpl::StartOnMainThread,
-                                  weak_ptr_factory_.GetWeakPtr(), delegate));
-  }
-
-  void Stop() override {
-    main_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&AudioOutputImpl::StopOnMainThread,
-                                  weak_ptr_factory_.GetWeakPtr()));
-  }
-
- private:
-  void InitializeOnMainThread(const std::string& device_id) {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
-
-    audio_stream_handler_ = std::make_unique<AudioStreamHandler>();
-    device_owner_ = std::make_unique<AudioDeviceOwner>(device_id);
-  }
-
-  void StartOnMainThread(assistant_client::AudioOutput::Delegate* delegate) {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
-
-    // TODO(llin): Remove getting audio focus here after libassistant handles
-    // acquiring audio focus for the internal media player.
-    if (stream_type_ == assistant_client::OutputStreamType::STREAM_MEDIA) {
-      audio_output_delegate_->RequestAudioFocus(
-          mojom::AudioOutputStreamType::kMediaStream);
-    }
-
-    if (IsEncodedFormat(format_)) {
-      if (!audio_decoder_factory_manager_) {
-        audio_decoder_factory_manager_ =
-            audio_output_provider_impl_
-                ->GetOrCreateAudioDecoderFactoryManager();
-      }
-
-      audio_stream_handler_->StartAudioDecoder(
-          audio_decoder_factory_manager_->GetAudioDecoderFactory(), delegate,
-          base::BindOnce(&AudioDeviceOwner::Start,
-                         base::Unretained(device_owner_.get()),
-                         audio_output_delegate_, audio_stream_handler_.get(),
-                         std::move(stream_factory_)));
-    } else {
-      device_owner_->Start(audio_output_delegate_, delegate,
-                           std::move(stream_factory_), format_);
-    }
-  }
-
-  void StopOnMainThread() {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
-
-    // TODO(llin): Remove abandoning audio focus here after libassistant handles
-    // abandoning audio focus for the internal media player.
-    if (stream_type_ == assistant_client::OutputStreamType::STREAM_MEDIA) {
-      audio_output_delegate_->AbandonAudioFocusIfNeeded();
-    }
-
-    if (IsEncodedFormat(format_)) {
-      device_owner_->SetDelegate(nullptr);
-      audio_stream_handler_->OnStopped();
-    } else {
-      device_owner_->Stop();
-    }
-  }
-
-  raw_ptr<AudioOutputProviderImpl> audio_output_provider_impl_
-      GUARDED_BY_CONTEXT(main_sequence_checker_);
-  scoped_refptr<AudioOutputProviderImpl::AudioDecoderFactoryManager>
-      audio_decoder_factory_manager_ GUARDED_BY_CONTEXT(main_sequence_checker_);
-
-  scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
-
-  mojo::PendingRemote<media::mojom::AudioStreamFactory> stream_factory_
-      GUARDED_BY_CONTEXT(main_sequence_checker_);
-  const raw_ptr<mojom::AudioOutputDelegate> audio_output_delegate_
-      GUARDED_BY_CONTEXT(main_sequence_checker_);
-
-  // Accessed from both Libassistant and main sequence, so should remain
-  // |const|.
-  const assistant_client::OutputStreamType stream_type_;
-
-  assistant_client::OutputStreamFormat format_
-      GUARDED_BY_CONTEXT(main_sequence_checker_);
-
-  std::unique_ptr<AudioStreamHandler> audio_stream_handler_
-      GUARDED_BY_CONTEXT(main_sequence_checker_);
-  std::unique_ptr<AudioDeviceOwner> device_owner_
-      GUARDED_BY_CONTEXT(main_sequence_checker_);
-
-  // This class is used both from the Libassistant and main thread.
-  SEQUENCE_CHECKER(main_sequence_checker_);
-
-  base::WeakPtrFactory<AudioOutputImpl> weak_ptr_factory_{this};
-};
-
-class AudioDecoderFactoryManagerImpl
-    : public AudioOutputProviderImpl::AudioDecoderFactoryManager {
- public:
-  explicit AudioDecoderFactoryManagerImpl(
-      mojom::PlatformDelegate* platform_delegate) {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
-
-    platform_delegate->BindAudioDecoderFactory(
-        audio_decoder_factory_.BindNewPipeAndPassReceiver());
-  }
-
-  assistant::mojom::AssistantAudioDecoderFactory* GetAudioDecoderFactory()
-      override {
-    return audio_decoder_factory_.get();
-  }
-
-  base::WeakPtr<AudioDecoderFactoryManager> GetWeakPtr() {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
-
-    return weak_ptr_factory_.GetWeakPtr();
-  }
-
- protected:
-  ~AudioDecoderFactoryManagerImpl() override {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
-
-    audio_decoder_factory_.reset();
-  }
-
- private:
-  mojo::Remote<assistant::mojom::AssistantAudioDecoderFactory>
-      audio_decoder_factory_;
-
-  SEQUENCE_CHECKER(main_sequence_checker_);
-
-  base::WeakPtrFactory<AudioDecoderFactoryManagerImpl> weak_ptr_factory_{this};
-};
-
-}  // namespace
-
-AudioOutputProviderImpl::AudioOutputProviderImpl(const std::string& device_id)
-    : loop_back_input_(media::AudioDeviceDescription::kLoopbackInputDeviceId),
-      volume_control_impl_(),
-      main_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()),
-      device_id_(device_id) {}
-
-void AudioOutputProviderImpl::Bind(
-    mojo::PendingRemote<mojom::AudioOutputDelegate> audio_output_delegate,
-    mojom::PlatformDelegate* platform_delegate) {
-  platform_delegate_ = platform_delegate;
-
-  audio_output_delegate_.Bind(std::move(audio_output_delegate));
-
-  volume_control_impl_.Initialize(audio_output_delegate_.get(),
-                                  platform_delegate);
-  loop_back_input_.Initialize(platform_delegate);
-}
-
-AudioOutputProviderImpl::~AudioOutputProviderImpl() = default;
-
-// Called from the Libassistant thread.
-assistant_client::AudioOutput* AudioOutputProviderImpl::CreateAudioOutput(
-    assistant_client::OutputStreamMetadata metadata) {
-  return CreateAudioOutputInternal(metadata.type,
-                                   metadata.buffer_stream_format);
-}
-
-// Called from the Libassistant thread.
-std::vector<assistant_client::OutputStreamEncoding>
-AudioOutputProviderImpl::GetSupportedStreamEncodings() {
-  return std::vector<assistant_client::OutputStreamEncoding>{
-      assistant_client::OutputStreamEncoding::STREAM_PCM_S16,
-      assistant_client::OutputStreamEncoding::STREAM_PCM_S32,
-      assistant_client::OutputStreamEncoding::STREAM_PCM_F32,
-      assistant_client::OutputStreamEncoding::STREAM_MP3,
-      assistant_client::OutputStreamEncoding::STREAM_OPUS_IN_OGG,
-  };
-}
-
-// Called from the Libassistant thread.
-assistant_client::AudioInput* AudioOutputProviderImpl::GetReferenceInput() {
-  return &loop_back_input_;
-}
-
-// Called from the Libassistant thread.
-bool AudioOutputProviderImpl::SupportsPlaybackTimestamp() const {
-  // TODO(muyuanli): implement.
-  return false;
-}
-
-// Called from the Libassistant thread.
-assistant_client::VolumeControl& AudioOutputProviderImpl::GetVolumeControl() {
-  return volume_control_impl_;
-}
-
-// Called from the Libassistant thread.
-void AudioOutputProviderImpl::RegisterAudioEmittingStateCallback(
-    AudioEmittingStateCallback callback) {
-  // TODO(muyuanli): implement.
-}
-
-scoped_refptr<AudioOutputProviderImpl::AudioDecoderFactoryManager>
-AudioOutputProviderImpl::GetOrCreateAudioDecoderFactoryManager() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
-
-  if (audio_decoder_factory_manager_) {
-    return base::WrapRefCounted<
-        AudioOutputProviderImpl::AudioDecoderFactoryManager>(
-        audio_decoder_factory_manager_.get());
-  }
-
-  auto impl =
-      base::MakeRefCounted<AudioDecoderFactoryManagerImpl>(platform_delegate_);
-  audio_decoder_factory_manager_ = impl->GetWeakPtr();
-  return std::move(impl);
-}
-
-void AudioOutputProviderImpl::BindStreamFactory(
-    mojo::PendingReceiver<media::mojom::AudioStreamFactory> receiver) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
-
-  platform_delegate_->BindAudioStreamFactory(std::move(receiver));
-}
-
-// Called from the Libassistant thread.
-assistant_client::AudioOutput*
-AudioOutputProviderImpl::CreateAudioOutputInternal(
-    assistant_client::OutputStreamType type,
-    const assistant_client::OutputStreamFormat& stream_format) {
-  mojo::PendingRemote<media::mojom::AudioStreamFactory> stream_factory;
-  main_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&AudioOutputProviderImpl::BindStreamFactory,
-                     weak_ptr_factory_.GetWeakPtr(),
-                     stream_factory.InitWithNewPipeAndPassReceiver()));
-
-  // Owned by one arbitrary thread inside libassistant. It will be destroyed
-  // once assistant_client::AudioOutput::Delegate::OnStopped() is called.
-  return new AudioOutputImpl(this, std::move(stream_factory), main_task_runner_,
-                             audio_output_delegate_.get(), type, stream_format,
-                             device_id_);
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/audio/audio_output_provider_impl.h b/chromeos/ash/services/libassistant/audio/audio_output_provider_impl.h
deleted file mode 100644
index 872059c..0000000
--- a/chromeos/ash/services/libassistant/audio/audio_output_provider_impl.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_OUTPUT_PROVIDER_IMPL_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_OUTPUT_PROVIDER_IMPL_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/component_export.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/task/single_thread_task_runner.h"
-#include "chromeos/ash/services/assistant/public/cpp/assistant_service.h"
-#include "chromeos/ash/services/assistant/public/mojom/assistant_audio_decoder.mojom.h"
-#include "chromeos/ash/services/libassistant/audio/audio_device_owner.h"
-#include "chromeos/ash/services/libassistant/audio/audio_input_impl.h"
-#include "chromeos/ash/services/libassistant/audio/volume_control_impl.h"
-#include "chromeos/ash/services/libassistant/public/mojom/audio_output_delegate.mojom.h"
-#include "chromeos/ash/services/libassistant/public/mojom/platform_delegate.mojom-forward.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "media/mojo/mojom/audio_stream_factory.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
-
-namespace ash::libassistant {
-
-class AudioOutputProviderImpl : public assistant_client::AudioOutputProvider {
- public:
-  // |AudioDecoderFactoryManager| is responsible for managing life time of
-  // AssistantAudioDecoder service. |AudioOutputImpl| will hold a ref counted
-  // object of |AudioDecoderFactoryManager|. |AudioDecoderFactoryManager| will
-  // be destructed when all of ref counted objects of
-  // |AudioDecoderFactoryManager| are destructed, i.e. All of |AudioOutputImpl|
-  // are destructed.
-  //
-  // Define |AudioDecoderFactoryManager| here as we want to reference it from
-  // |AudioOutputProviderImpl|.
-  class AudioDecoderFactoryManager
-      : public base::RefCounted<AudioDecoderFactoryManager> {
-   public:
-    virtual assistant::mojom::AssistantAudioDecoderFactory*
-    GetAudioDecoderFactory() = 0;
-
-    AudioDecoderFactoryManager() = default;
-    AudioDecoderFactoryManager(const AudioDecoderFactoryManager&) = delete;
-    AudioDecoderFactoryManager& operator=(const AudioDecoderFactoryManager&) =
-        delete;
-
-   protected:
-    friend class base::RefCounted<AudioDecoderFactoryManager>;
-    virtual ~AudioDecoderFactoryManager() = default;
-  };
-
-  explicit AudioOutputProviderImpl(const std::string& device_id);
-
-  AudioOutputProviderImpl(const AudioOutputProviderImpl&) = delete;
-  AudioOutputProviderImpl& operator=(const AudioOutputProviderImpl&) = delete;
-
-  ~AudioOutputProviderImpl() override;
-
-  void Bind(
-      mojo::PendingRemote<mojom::AudioOutputDelegate> audio_output_delegate,
-      mojom::PlatformDelegate* platform_delegate);
-
-  // assistant_client::AudioOutputProvider overrides:
-  assistant_client::AudioOutput* CreateAudioOutput(
-      assistant_client::OutputStreamMetadata metadata) override;
-  std::vector<assistant_client::OutputStreamEncoding>
-  GetSupportedStreamEncodings() override;
-  assistant_client::AudioInput* GetReferenceInput() override;
-  bool SupportsPlaybackTimestamp() const override;
-  assistant_client::VolumeControl& GetVolumeControl() override;
-  void RegisterAudioEmittingStateCallback(
-      AudioEmittingStateCallback callback) override;
-
-  scoped_refptr<AudioDecoderFactoryManager>
-  GetOrCreateAudioDecoderFactoryManager();
-
- private:
-  void BindStreamFactory(
-      mojo::PendingReceiver<media::mojom::AudioStreamFactory> receiver);
-
-  assistant_client::AudioOutput* CreateAudioOutputInternal(
-      assistant_client::OutputStreamType type,
-      const assistant_client::OutputStreamFormat& stream_format);
-
-  // Owned by |AssistantManagerServiceImpl|.
-  raw_ptr<mojom::PlatformDelegate> platform_delegate_ = nullptr;
-
-  mojo::Remote<mojom::AudioOutputDelegate> audio_output_delegate_;
-
-  AudioInputImpl loop_back_input_;
-  VolumeControlImpl volume_control_impl_;
-  scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
-  std::string device_id_;
-
-  // Life time of |AudioDecoderFactoryManager| is managed by |AudioOutput|
-  // instances. |AudioOutputImpl| will hold a ref counted object of
-  // |AudioDecoderFactoryManager|.
-  base::WeakPtr<AudioDecoderFactoryManager> audio_decoder_factory_manager_
-      GUARDED_BY_CONTEXT(main_sequence_checker_);
-
-  SEQUENCE_CHECKER(main_sequence_checker_);
-
-  base::WeakPtrFactory<AudioOutputProviderImpl> weak_ptr_factory_{this};
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_OUTPUT_PROVIDER_IMPL_H_
diff --git a/chromeos/ash/services/libassistant/audio/audio_output_provider_impl_unittest.cc b/chromeos/ash/services/libassistant/audio/audio_output_provider_impl_unittest.cc
deleted file mode 100644
index e3efc176..0000000
--- a/chromeos/ash/services/libassistant/audio/audio_output_provider_impl_unittest.cc
+++ /dev/null
@@ -1,298 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/audio/audio_output_provider_impl.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/compiler_specific.h"
-#include "base/functional/bind.h"
-#include "base/functional/callback.h"
-#include "base/run_loop.h"
-#include "base/task/bind_post_task.h"
-#include "base/test/bind.h"
-#include "base/test/task_environment.h"
-#include "base/threading/thread.h"
-#include "base/time/time.h"
-#include "chromeos/ash/services/libassistant/test_support/fake_platform_delegate.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "media/base/audio_bus.h"
-#include "media/base/audio_glitch_info.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::libassistant {
-namespace {
-using assistant::FakePlatformDelegate;
-using assistant::mojom::AssistantAudioDecoderFactory;
-using ::assistant_client::OutputStreamMetadata;
-using ::base::test::SingleThreadTaskEnvironment;
-
-constexpr char kFakeDeviceId[] = "device_id";
-}  // namespace
-
-class FakeAudioOutputDelegate : public assistant_client::AudioOutput::Delegate {
- public:
-  FakeAudioOutputDelegate() : thread_("assistant") { thread_.Start(); }
-
-  FakeAudioOutputDelegate(const FakeAudioOutputDelegate&) = delete;
-  FakeAudioOutputDelegate& operator=(const FakeAudioOutputDelegate&) = delete;
-
-  ~FakeAudioOutputDelegate() override = default;
-
-  // assistant_client::AudioOutput::Delegate overrides:
-  void FillBuffer(void* buffer,
-                  int buffer_size,
-                  int64_t playback_timestamp,
-                  assistant_client::Callback1<int> done_cb) override {
-    // Fill some arbitrary stuff.
-    UNSAFE_TODO(
-        memset(reinterpret_cast<uint8_t*>(buffer), '1', num_bytes_to_fill_));
-    int filled_bytes = num_bytes_to_fill_;
-    num_bytes_to_fill_ = 0;
-
-    // We'll need to maintain the multi-threaded async semantics as the real
-    // assistant. Otherwise, it'll cause re-entrance of locks.
-    thread_.task_runner()->PostTask(
-        FROM_HERE, base::BindOnce(&FakeAudioOutputDelegate::FillBufferDone,
-                                  base::Unretained(this), std::move(done_cb),
-                                  filled_bytes));
-  }
-
-  void OnEndOfStream() override { end_of_stream_ = true; }
-
-  void OnError(assistant_client::AudioOutput::Error error) override {}
-
-  void OnStopped() override {}
-
-  void FillBufferDone(assistant_client::Callback1<int> cb, int num_bytes) {
-    cb(num_bytes);
-
-    // AudioDeviceOwner::ScheduleFillLocked() will be called repeatedlly until
-    // the |num_bytes| is 0. Only call QuitClosure() at the last call to unblock
-    // in the test.
-    // Otherwise, the |run_loop_| may not block because the QuitClosure() is
-    // called before Run(), right after it is created in Reset(), which will
-    // cause timing issue in the test.
-    if (num_bytes == 0) {
-      quit_closure_.Run();
-    }
-  }
-
-  bool end_of_stream() { return end_of_stream_; }
-
-  void set_num_of_bytes_to_fill(int bytes) { num_bytes_to_fill_ = bytes; }
-
-  void Reset() {
-    run_loop_ = std::make_unique<base::RunLoop>();
-    quit_closure_ =
-        base::BindPostTaskToCurrentDefault(run_loop_->QuitClosure());
-  }
-
-  void Wait() { run_loop_->Run(); }
-
- private:
-  base::Thread thread_;
-  base::RepeatingClosure quit_closure_;
-  std::unique_ptr<base::RunLoop> run_loop_;
-  int num_bytes_to_fill_ = 0;
-  bool end_of_stream_ = false;
-};
-
-class FakeAudioOutputDelegateMojom : public mojom::AudioOutputDelegate {
- public:
-  FakeAudioOutputDelegateMojom() = default;
-  FakeAudioOutputDelegateMojom(const FakeAudioOutputDelegateMojom&) = delete;
-  FakeAudioOutputDelegateMojom& operator=(const FakeAudioOutputDelegateMojom&) =
-      delete;
-  ~FakeAudioOutputDelegateMojom() override = default;
-
-  // libassistant::mojom::AudioOutputDelegate implementation:
-  void RequestAudioFocus(mojom::AudioOutputStreamType stream_type) override {}
-  void AbandonAudioFocusIfNeeded() override {}
-  void AddMediaSessionObserver(
-      mojo::PendingRemote<::media_session::mojom::MediaSessionObserver>
-          observer) override {}
-};
-
-class FakeAssistantAudioDecoderFactory : public AssistantAudioDecoderFactory {
- public:
-  FakeAssistantAudioDecoderFactory() = default;
-
-  void CreateAssistantAudioDecoder(
-      ::mojo::PendingReceiver<::ash::assistant::mojom::AssistantAudioDecoder>
-          audio_decoder,
-      ::mojo::PendingRemote<
-          ::ash::assistant::mojom::AssistantAudioDecoderClient> client,
-      ::mojo::PendingRemote<::ash::assistant::mojom::AssistantMediaDataSource>
-          data_source) override {}
-};
-
-class AssistantAudioDeviceOwnerTest : public testing::Test {
- public:
-  AssistantAudioDeviceOwnerTest()
-      : task_env_(
-            base::test::TaskEnvironment::MainThreadType::DEFAULT,
-            base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED) {}
-
-  AssistantAudioDeviceOwnerTest(const AssistantAudioDeviceOwnerTest&) = delete;
-  AssistantAudioDeviceOwnerTest& operator=(
-      const AssistantAudioDeviceOwnerTest&) = delete;
-
-  ~AssistantAudioDeviceOwnerTest() override { task_env_.RunUntilIdle(); }
-
- private:
-  base::test::TaskEnvironment task_env_;
-};
-
-TEST(AudioOutputProviderImplTest, StartDecoderServiceOnDemand) {
-  SingleThreadTaskEnvironment task_environment;
-
-  auto provider = std::make_unique<AudioOutputProviderImpl>(kFakeDeviceId);
-
-  FakePlatformDelegate platform_delegate;
-  mojo::PendingRemote<mojom::AudioOutputDelegate> audio_output_delegate;
-  { auto unused = audio_output_delegate.InitWithNewPipeAndPassReceiver(); }
-  provider->Bind(std::move(audio_output_delegate), &platform_delegate);
-
-  // Set encoding format to MP3 as we use AudioDecoder only if it's in encoded
-  // format.
-  OutputStreamMetadata metadata = {
-      .buffer_stream_format = {
-          .encoding = assistant_client::OutputStreamEncoding::STREAM_MP3,
-      }};
-
-  std::unique_ptr<assistant_client::AudioOutput> first_output(
-      provider->CreateAudioOutput(metadata));
-  FakeAudioOutputDelegate first_fake_audio_output_delegate;
-  first_output->Start(&first_fake_audio_output_delegate);
-  task_environment.RunUntilIdle();
-
-  FakeAssistantAudioDecoderFactory fake_assistant_audio_decoder_factory;
-  auto receiver =
-      std::make_unique<mojo::Receiver<AssistantAudioDecoderFactory>>(
-          &fake_assistant_audio_decoder_factory,
-          platform_delegate.audio_decoder_factory_receiver());
-
-  // Confirm that AudioDecoderFactory is now bound after Start call.
-  EXPECT_TRUE(receiver->is_bound());
-
-  // Create/Start another output as |second_output|.
-  std::unique_ptr<assistant_client::AudioOutput> second_output(
-      provider->CreateAudioOutput(metadata));
-  FakeAudioOutputDelegate second_fake_audio_output_delegate;
-  second_output->Start(&second_fake_audio_output_delegate);
-  task_environment.RunUntilIdle();
-
-  bool disconnected = false;
-  receiver->set_disconnect_handler(
-      base::BindLambdaForTesting([&]() { disconnected = true; }));
-
-  // Delete the first output and confirm that the connection is not disconnected
-  // as we still have the second output.
-  first_output.reset();
-  task_environment.RunUntilIdle();
-  EXPECT_TRUE(receiver->is_bound());
-  EXPECT_FALSE(disconnected);
-
-  second_output.reset();
-  task_environment.RunUntilIdle();
-  // Confirm that AudioDecoderFactory is disconnected once all outputs got
-  // deleted.
-  EXPECT_TRUE(disconnected);
-
-  // Create another one and confirm that it still works correctly.
-  std::unique_ptr<assistant_client::AudioOutput> third_output(
-      provider->CreateAudioOutput(metadata));
-  FakeAudioOutputDelegate third_fake_audio_output_delegate;
-  third_output->Start(&third_fake_audio_output_delegate);
-  task_environment.RunUntilIdle();
-
-  receiver = std::make_unique<mojo::Receiver<AssistantAudioDecoderFactory>>(
-      &fake_assistant_audio_decoder_factory,
-      platform_delegate.audio_decoder_factory_receiver());
-  EXPECT_TRUE(receiver->is_bound());
-  disconnected = false;
-  receiver->set_disconnect_handler(
-      base::BindLambdaForTesting([&]() { disconnected = true; }));
-
-  third_output.reset();
-  task_environment.RunUntilIdle();
-  EXPECT_TRUE(disconnected);
-}
-
-// We do not use AssistantAudioDecoder if audio format is in raw format.
-TEST(AudioOutputProviderImplTest, DoNotStartAudioServiceForRawFormat) {
-  SingleThreadTaskEnvironment task_environment;
-  FakeAssistantAudioDecoderFactory fake_assistant_audio_decoder_factory;
-
-  auto provider = std::make_unique<AudioOutputProviderImpl>(kFakeDeviceId);
-
-  FakePlatformDelegate platform_delegate;
-  mojo::PendingRemote<mojom::AudioOutputDelegate> audio_output_delegate;
-  { auto unused = audio_output_delegate.InitWithNewPipeAndPassReceiver(); }
-  provider->Bind(std::move(audio_output_delegate), &platform_delegate);
-
-  OutputStreamMetadata metadata = {
-      .buffer_stream_format = {
-          .encoding = assistant_client::OutputStreamEncoding::STREAM_PCM_S16,
-          .pcm_sample_rate = 44800,
-          .pcm_num_channels = 2,
-      }};
-
-  std::unique_ptr<assistant_client::AudioOutput> output(
-      provider->CreateAudioOutput(metadata));
-  FakeAudioOutputDelegate fake_audio_output_delegate;
-  output->Start(&fake_audio_output_delegate);
-  fake_audio_output_delegate.Reset();
-  fake_audio_output_delegate.Wait();
-  task_environment.RunUntilIdle();
-
-  // Confirm that AudioDecoderFactory is not bound even after Start call if it's
-  // in raw format.
-  EXPECT_FALSE(platform_delegate.audio_decoder_factory_receiver().is_valid());
-
-  output.reset();
-  task_environment.RunUntilIdle();
-}
-
-// TODO(b/234874756): Move AssistantAudioDeviceOwner test under
-// audio_device_owner_unittest.cc
-TEST_F(AssistantAudioDeviceOwnerTest, BufferFilling) {
-  FakeAudioOutputDelegateMojom audio_output_delegate_mojom;
-  FakeAudioOutputDelegate audio_output_delegate;
-  auto audio_bus = media::AudioBus::Create(2, 4480);
-  assistant_client::OutputStreamFormat format{
-      assistant_client::OutputStreamEncoding::STREAM_PCM_S16,
-      44800,  // pcm_sample rate.
-      2       // pcm_num_channels,
-  };
-
-  audio_output_delegate.set_num_of_bytes_to_fill(200);
-  audio_output_delegate.Reset();
-
-  auto owner = std::make_unique<AudioDeviceOwner>(kFakeDeviceId);
-  // Upon start, it will start to fill the buffer. The fill should stop after
-  // Wait().
-  owner->Start(&audio_output_delegate_mojom, &audio_output_delegate,
-               mojo::NullRemote(), format);
-  audio_output_delegate.Wait();
-
-  audio_output_delegate.Reset();
-  audio_bus->Zero();
-  // On first render, it will push the data to |audio_bus|.
-  owner->Render(base::Microseconds(0), base::TimeTicks::Now(), {},
-                audio_bus.get());
-  audio_output_delegate.Wait();
-  EXPECT_FALSE(audio_bus->AreFramesZero());
-  EXPECT_FALSE(audio_output_delegate.end_of_stream());
-
-  // The subsequent Render call will detect no data available and notify
-  // delegate for OnEndOfStream().
-  owner->Render(base::Microseconds(0), base::TimeTicks::Now(), {},
-                audio_bus.get());
-  EXPECT_TRUE(audio_output_delegate.end_of_stream());
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/audio/audio_stream_handler.cc b/chromeos/ash/services/libassistant/audio/audio_stream_handler.cc
deleted file mode 100644
index 071e5faa..0000000
--- a/chromeos/ash/services/libassistant/audio/audio_stream_handler.cc
+++ /dev/null
@@ -1,206 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
-#include "chromeos/ash/services/libassistant/audio/audio_stream_handler.h"
-
-#include "base/functional/bind.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/libassistant/audio/audio_media_data_source.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-
-namespace ash::libassistant {
-
-AudioStreamHandler::AudioStreamHandler()
-    : main_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()),
-      weak_factory_(this) {}
-
-AudioStreamHandler::~AudioStreamHandler() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-void AudioStreamHandler::StartAudioDecoder(
-    assistant::mojom::AssistantAudioDecoderFactory* audio_decoder_factory,
-    assistant_client::AudioOutput::Delegate* delegate,
-    InitCB on_inited) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  mojo::PendingRemote<AssistantAudioDecoderClient> client;
-  client_receiver_.Bind(client.InitWithNewPipeAndPassReceiver());
-
-  mojo::PendingRemote<assistant::mojom::AssistantMediaDataSource> data_source;
-  media_data_source_ = std::make_unique<AudioMediaDataSource>(
-      data_source.InitWithNewPipeAndPassReceiver());
-
-  audio_decoder_factory->CreateAssistantAudioDecoder(
-      audio_decoder_.BindNewPipeAndPassReceiver(), std::move(client),
-      std::move(data_source));
-
-  delegate_ = delegate;
-  media_data_source_->set_delegate(delegate_);
-  start_device_owner_on_main_thread_ = std::move(on_inited);
-  audio_decoder_->OpenDecoder(base::BindOnce(
-      &AudioStreamHandler::OnDecoderInitialized, weak_factory_.GetWeakPtr()));
-}
-
-void AudioStreamHandler::OnNewBuffers(
-    const std::vector<std::vector<uint8_t>>& buffers) {
-  if (buffers.size() == 0)
-    no_more_data_ = true;
-
-  for (const auto& buffer : buffers)
-    decoded_data_.emplace_back(buffer);
-
-  is_decoding_ = false;
-  FillDecodedBuffer(buffer_to_copy_, size_to_copy_);
-}
-
-// TODO(wutao): Needs to pass |playback_timestamp| to LibAssistant.
-// Called from the Libassistant thread.
-void AudioStreamHandler::FillBuffer(
-    void* buffer,
-    int buffer_size,
-    int64_t playback_timestamp,
-    assistant_client::Callback1<int> on_filled) {
-  DCHECK(!on_filled_);
-
-  main_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&AudioStreamHandler::FillBufferOnMainThread,
-                                weak_factory_.GetWeakPtr(), buffer, buffer_size,
-                                std::move(on_filled)));
-}
-
-void AudioStreamHandler::FillBufferOnMainThread(
-    void* buffer,
-    int buffer_size,
-    assistant_client::Callback1<int> on_filled) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  on_filled_ = std::move(on_filled);
-  buffer_to_copy_ = buffer;
-  size_to_copy_ = buffer_size;
-
-  FillDecodedBuffer(buffer, buffer_size);
-}
-
-// Called from the Libassistant thread.
-void AudioStreamHandler::OnEndOfStream() {
-  if (delegate_)
-    delegate_->OnEndOfStream();
-}
-
-// Called from the Libassistant thread.
-void AudioStreamHandler::OnError(assistant_client::AudioOutput::Error error) {
-  if (delegate_)
-    delegate_->OnError(error);
-}
-
-// Called from the Libassistant thread.
-void AudioStreamHandler::OnStopped() {
-  stopped_ = true;
-
-  // Do not provide more source data.
-  media_data_source_->set_delegate(nullptr);
-
-  // Call |delegate_->OnStopped()| will delete |this|. Call |CloseDecoder| to
-  // clean up first.
-  audio_decoder_->CloseDecoder(base::BindOnce(&AudioStreamHandler::StopDelegate,
-                                              weak_factory_.GetWeakPtr()));
-}
-
-void AudioStreamHandler::OnDecoderInitialized(bool success,
-                                              uint32_t bytes_per_sample,
-                                              uint32_t samples_per_second,
-                                              uint32_t channels) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (!success) {
-    // In the case that both |OpenDecoder()| and |CloseDecoder()| were called,
-    // there is no need to call |OnError()|, since we are going to call
-    // |OnStopped()| soon.
-    if (!stopped_)
-      OnError(assistant_client::AudioOutput::Error::FATAL_ERROR);
-
-    start_device_owner_on_main_thread_.Reset();
-    return;
-  }
-
-  DCHECK(bytes_per_sample == 2 || bytes_per_sample == 4);
-  const assistant_client::OutputStreamFormat format = {
-      bytes_per_sample == 2
-          ? assistant_client::OutputStreamEncoding::STREAM_PCM_S16
-          : assistant_client::OutputStreamEncoding::STREAM_PCM_S32,
-      /*pcm_sample_rate=*/static_cast<int>(samples_per_second),
-      /*pcm_num_channels=*/static_cast<int>(channels)};
-  if (start_device_owner_on_main_thread_) {
-    DCHECK(!on_filled_);
-    std::move(start_device_owner_on_main_thread_).Run(format);
-  }
-}
-
-void AudioStreamHandler::StopDelegate() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  delegate_->OnStopped();
-  delegate_ = nullptr;
-}
-
-void AudioStreamHandler::FillDecodedBuffer(void* buffer, int buffer_size) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (on_filled_ && (decoded_data_.size() > 0 || no_more_data_)) {
-    int size_copied = 0;
-    // Fill buffer with data not more than requested.
-    while (!decoded_data_.empty() && size_copied < buffer_size) {
-      std::vector<uint8_t>& data = decoded_data_.front();
-      int audio_buffer_size = static_cast<int>(data.size());
-      if (size_copied + audio_buffer_size > buffer_size)
-        audio_buffer_size = buffer_size - size_copied;
-
-      memcpy(reinterpret_cast<uint8_t*>(buffer) + size_copied, data.data(),
-             audio_buffer_size);
-      size_copied += audio_buffer_size;
-      if (audio_buffer_size < static_cast<int>(data.size()))
-        data.erase(data.begin(), data.begin() + audio_buffer_size);
-      else
-        decoded_data_.pop_front();
-    }
-
-    main_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&AudioStreamHandler::OnFillBuffer,
-                                  weak_factory_.GetWeakPtr(),
-                                  std::move(on_filled_), size_copied));
-  }
-
-  if (decoded_data_.empty() && !no_more_data_) {
-    main_task_runner_->PostTask(FROM_HERE,
-                                base::BindOnce(&AudioStreamHandler::Decode,
-                                               weak_factory_.GetWeakPtr()));
-  }
-}
-
-void AudioStreamHandler::OnFillBuffer(
-    assistant_client::Callback1<int> on_filled,
-    int num_bytes) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  on_filled(num_bytes);
-}
-
-void AudioStreamHandler::Decode() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (is_decoding_)
-    return;
-
-  is_decoding_ = true;
-  audio_decoder_->Decode();
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/audio/audio_stream_handler.h b/chromeos/ash/services/libassistant/audio/audio_stream_handler.h
deleted file mode 100644
index 1819077..0000000
--- a/chromeos/ash/services/libassistant/audio/audio_stream_handler.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_STREAM_HANDLER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_STREAM_HANDLER_H_
-
-#include "base/memory/raw_ptr.h"
-#include "base/synchronization/lock.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/task/single_thread_task_runner.h"
-#include "chromeos/ash/services/assistant/public/mojom/assistant_audio_decoder.mojom.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
-
-namespace ash::libassistant {
-
-class AudioMediaDataSource;
-
-class AudioStreamHandler : public assistant::mojom::AssistantAudioDecoderClient,
-                           public assistant_client::AudioOutput::Delegate {
- public:
-  using InitCB =
-      base::OnceCallback<void(const assistant_client::OutputStreamFormat&)>;
-
-  AudioStreamHandler();
-
-  AudioStreamHandler(const AudioStreamHandler&) = delete;
-  AudioStreamHandler& operator=(const AudioStreamHandler&) = delete;
-
-  ~AudioStreamHandler() override;
-
-  void StartAudioDecoder(
-      assistant::mojom::AssistantAudioDecoderFactory* audio_decoder_factory,
-      assistant_client::AudioOutput::Delegate* delegate,
-      InitCB start_device_owner_on_main_thread);
-
-  // assistant::mojom::AssistantAudioDecoderClient overrides:
-  void OnNewBuffers(const std::vector<std::vector<uint8_t>>& buffers) override;
-
-  // assistant_client::AudioOutput::Delegate overrides:
-  void FillBuffer(void* buffer,
-                  int buffer_size,
-                  int64_t playback_timestamp,
-                  assistant_client::Callback1<int> on_decoded) override;
-  void OnEndOfStream() override;
-  void OnError(assistant_client::AudioOutput::Error error) override;
-  void OnStopped() override;
-
- private:
-  void OnDecoderInitialized(bool success,
-                            uint32_t bytes_per_sample,
-                            uint32_t samples_per_second,
-                            uint32_t channels);
-  void StopDelegate();
-
-  void FillBufferOnMainThread(void* buffer,
-                              int buffer_size,
-                              assistant_client::Callback1<int> on_filled);
-
-  // Called by |FillBufferOnMainThread()| to fill available data. If no
-  // available data, it will call |Decode()| to get more data.
-  void FillDecodedBuffer(void* buffer, int buffer_size);
-
-  void OnFillBuffer(assistant_client::Callback1<int> on_decoded, int num_bytes);
-
-  void Decode();
-
-  scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
-  raw_ptr<assistant_client::AudioOutput::Delegate> delegate_;
-
-  mojo::Receiver<AssistantAudioDecoderClient> client_receiver_{this};
-  std::unique_ptr<AudioMediaDataSource> media_data_source_;
-  mojo::Remote<assistant::mojom::AssistantAudioDecoder> audio_decoder_;
-
-  // True when there is more decoded data.
-  bool no_more_data_ = false;
-  // True if |Decode()| called and not all decoded buffers are received, e.g.
-  // |buffers_to_receive_| != 0.
-  bool is_decoding_ = false;
-  // True after |OnStopped()| called.
-  bool stopped_ = false;
-
-  // Temporary storage of |buffer| passed by |FillBuffer|.
-  raw_ptr<void> buffer_to_copy_ = nullptr;
-  // Temporary storage of |buffer_size| passed by |FillBuffer|.
-  int size_to_copy_ = 0;
-  // Temporary storage of |on_filled| passed by |FillBuffer|.
-  assistant_client::Callback1<int> on_filled_;
-
-  InitCB start_device_owner_on_main_thread_;
-
-  base::circular_deque<std::vector<uint8_t>> decoded_data_;
-
-  // The callbacks from Libassistant are called on a different sequence,
-  // so this sequence checker ensures that no other methods are called on the
-  // libassistant sequence.
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  base::WeakPtrFactory<AudioStreamHandler> weak_factory_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_STREAM_HANDLER_H_
diff --git a/chromeos/ash/services/libassistant/audio/fake_input_device.cc b/chromeos/ash/services/libassistant/audio/fake_input_device.cc
deleted file mode 100644
index c4e7383..0000000
--- a/chromeos/ash/services/libassistant/audio/fake_input_device.cc
+++ /dev/null
@@ -1,225 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/audio/fake_input_device.h"
-
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/files/file.h"
-#include "base/functional/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/raw_ptr.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/task/task_traits.h"
-#include "base/task/thread_pool.h"
-#include "base/time/time.h"
-#include "media/base/audio_block_fifo.h"
-#include "media/base/audio_capturer_source.h"
-#include "media/base/audio_glitch_info.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-constexpr const char kFakeAudioFile[] = "/tmp/fake_audio.pcm";
-
-std::vector<uint8_t> ReadFileData(base::File* file) {
-  const std::vector<uint8_t>::size_type file_size = file->GetLength();
-  std::vector<uint8_t> result(file_size);
-
-  bool success = file->ReadAtCurrentPosAndCheck(result);
-  DCHECK(success) << "Failed to read input file";
-  return result;
-}
-
-// Does integer division and rounds the result up.
-// Example:
-//     1 / 5  --> 1
-//     5 / 5  --> 1
-//     7 / 5  --> 2
-int DivideAndRoundUp(int dividend, int divisor) {
-  return (dividend + divisor - 1) / divisor;
-}
-
-}  // namespace
-
-// A fake audio input device (also known as a microphone).
-// This fake device will wait until the `kFakeAudioFile` exists,
-// and it will then forward its data as microphone input.
-// Finally it will remove `kFakeAudioFile` (so we do not keep responding the
-// same thing over and over again).
-class FakeInputDevice {
- public:
-  FakeInputDevice() = default;
-  ~FakeInputDevice() = default;
-
-  // AudioCapturerSource implementation.
-  void Initialize(const media::AudioParameters& params,
-                  media::AudioCapturerSource::CaptureCallback* callback) {
-    audio_parameters_ = params;
-    callback_ = callback;
-  }
-
-  void Start() {
-    LOG(INFO) << "Starting fake input device";
-    PostDelayedTask(FROM_HERE,
-                    base::BindOnce(&FakeInputDevice::WaitForAudioFile,
-                                   weak_factory_.GetWeakPtr()),
-                    base::Milliseconds(100));
-  }
-
-  void Stop() {
-    LOG(INFO) << "Stopping fake input device";
-    callback_ = nullptr;
-  }
-
-  scoped_refptr<base::SequencedTaskRunner> task_runner() {
-    return task_runner_;
-  }
-
- private:
-  void WaitForAudioFile() {
-    DCHECK(RunsTasksInCurrentSequence(task_runner_));
-
-    base::FilePath path{kFakeAudioFile};
-    base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ |
-                              base::File::FLAG_DELETE_ON_CLOSE);
-    if (!file.IsValid()) {
-      SendSilence();
-      return;
-    }
-
-    LOG(INFO) << "Opening audio file " << kFakeAudioFile;
-    ReadAudioFile(&file);
-    file.Close();
-    SendAudio();
-  }
-
-  void ReadAudioFile(base::File* file) {
-    DCHECK(RunsTasksInCurrentSequence(task_runner_));
-
-    // Some stats about the audio file.
-    const media::SampleFormat sample_format = media::kSampleFormatS16;
-    const int bytes_per_frame =
-        audio_parameters_.GetBytesPerFrame(sample_format);
-    const int frame_count = file->GetLength() / bytes_per_frame;
-    const int blocks_count =
-        DivideAndRoundUp(frame_count, audio_parameters_.frames_per_buffer());
-
-    // Read the file in memory
-    std::vector<uint8_t> data = ReadFileData(file);
-
-    // Convert it to a list of blocks of the requested size.
-    audio_blocks_ = std::make_unique<media::AudioBlockFifo>(
-        audio_parameters_.channels(), audio_parameters_.frames_per_buffer(),
-        blocks_count);
-    audio_blocks_->Push(data.data(), frame_count, bytes_per_frame);
-    // Add silence so the last block is also complete.
-    audio_blocks_->PushSilence(audio_blocks_->GetUnfilledFrames());
-  }
-
-  void SendAudio() {
-    // Send the blocks to the callback
-    if (audio_blocks_->available_blocks() <= 0) {
-      audio_blocks_.reset();
-      SendSilence();
-      return;
-    }
-
-    const media::AudioBus* block = audio_blocks_->Consume();
-    auto delay_in_microseconds =
-        audio_parameters_.GetMicrosecondsPerFrame() * block->frames();
-    PostDelayedTask(
-        FROM_HERE,
-        base::BindOnce(&FakeInputDevice::SendAudio, weak_factory_.GetWeakPtr()),
-        base::Microseconds(delay_in_microseconds));
-
-    DVLOG(2) << "Send " << block->frames() << " audio frames";
-    const base::TimeTicks time = base::TimeTicks::Now();
-    if (callback_)
-      callback_->Capture(block, time, {}, /*volume=*/0.5);
-  }
-
-  // LibAssistant doesn't expect the microphone to stop sending data.
-  // Instead, it will check for a long pause to decide the query is finished.
-  // This sends this long pause.
-  void SendSilence() {
-    DCHECK(RunsTasksInCurrentSequence(task_runner_));
-
-    auto audio_packet = media::AudioBus::Create(audio_parameters_);
-    auto delay_in_microseconds =
-        audio_parameters_.GetMicrosecondsPerFrame() * audio_packet->frames();
-    const base::TimeTicks time = base::TimeTicks::Now();
-    if (callback_) {
-      callback_->Capture(audio_packet.get(), time, {}, /*volume=*/0.5);
-    }
-
-    PostDelayedTask(FROM_HERE,
-                    base::BindOnce(&FakeInputDevice::WaitForAudioFile,
-                                   weak_factory_.GetWeakPtr()),
-                    base::Microseconds(delay_in_microseconds));
-  }
-
-  void PostDelayedTask(const base::Location& from_here,
-                       base::OnceClosure task,
-                       base::TimeDelta delay) {
-    task_runner_->PostDelayedTask(from_here, std::move(task), delay);
-  }
-
-  bool RunsTasksInCurrentSequence(
-      scoped_refptr<base::SequencedTaskRunner> runner) {
-    return runner->RunsTasksInCurrentSequence();
-  }
-
-  media::AudioParameters audio_parameters_;
-  raw_ptr<media::AudioCapturerSource::CaptureCallback> callback_;
-  std::unique_ptr<media::AudioBlockFifo> audio_blocks_;
-
-  scoped_refptr<base::SequencedTaskRunner> task_runner_ =
-      base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});
-
-  base::WeakPtrFactory<FakeInputDevice> weak_factory_{this};
-};
-
-// This wrapper class runs on the caller sequence, `FakeInputDevice` runs on a
-// separate background sequence. This wrapper manages the life cycle of
-// `FakeInputDevice` and makes sure it's deleted on the right sequence.
-class FakeInputDeviceWrapper : public media::AudioCapturerSource {
- public:
-  FakeInputDeviceWrapper()
-      : fake_input_device_(std::make_unique<FakeInputDevice>()) {}
-
-  // AudioCapturerSource implementation.
-  void Initialize(const media::AudioParameters& params,
-                  CaptureCallback* callback) override {
-    fake_input_device_->Initialize(params, callback);
-  }
-
-  void Start() override { fake_input_device_->Start(); }
-
-  void Stop() override { fake_input_device_->Stop(); }
-
-  void SetVolume(double volume) override {}
-  void SetAutomaticGainControl(bool enabled) override {}
-  void SetOutputDeviceForAec(const std::string& output_device_id) override {}
-
- private:
-  ~FakeInputDeviceWrapper() override {
-    fake_input_device_->task_runner()->DeleteSoon(
-        FROM_HERE, std::move(fake_input_device_));
-  }
-
-  std::unique_ptr<FakeInputDevice> fake_input_device_;
-};
-
-scoped_refptr<media::AudioCapturerSource> CreateFakeInputDevice() {
-  return base::MakeRefCounted<FakeInputDeviceWrapper>();
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/audio/fake_input_device.h b/chromeos/ash/services/libassistant/audio/fake_input_device.h
deleted file mode 100644
index 9195714..0000000
--- a/chromeos/ash/services/libassistant/audio/fake_input_device.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_FAKE_INPUT_DEVICE_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_FAKE_INPUT_DEVICE_H_
-
-#include "base/memory/scoped_refptr.h"
-
-namespace media {
-class AudioCapturerSource;
-}  // namespace media
-
-namespace ash::libassistant {
-
-// Create a fake input device. When asked to record input, it will read the
-// input from an audio file generated by the
-// chromeos/ash/components/assistant/send-audio.sh script.
-scoped_refptr<media::AudioCapturerSource> CreateFakeInputDevice();
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_FAKE_INPUT_DEVICE_H_
diff --git a/chromeos/ash/services/libassistant/audio/volume_control_impl.cc b/chromeos/ash/services/libassistant/audio/volume_control_impl.cc
deleted file mode 100644
index 0e4d3881..0000000
--- a/chromeos/ash/services/libassistant/audio/volume_control_impl.cc
+++ /dev/null
@@ -1,121 +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 "chromeos/ash/services/libassistant/audio/volume_control_impl.h"
-
-#include <utility>
-
-#include "ash/public/mojom/assistant_volume_control.mojom.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/libassistant/public/mojom/platform_delegate.mojom.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "mojo/public/cpp/bindings/type_converter.h"
-
-using ::ash::libassistant::mojom::AudioOutputStreamType;
-
-namespace mojo {
-template <>
-struct TypeConverter<AudioOutputStreamType,
-                     assistant_client::OutputStreamType> {
-  static AudioOutputStreamType Convert(
-      const assistant_client::OutputStreamType& input) {
-    using assistant_client::OutputStreamType;
-    switch (input) {
-      case OutputStreamType::STREAM_ALARM:
-        return AudioOutputStreamType::kAlarmStream;
-      case OutputStreamType::STREAM_TTS:
-        return AudioOutputStreamType::kTtsStream;
-      case OutputStreamType::STREAM_MEDIA:
-        return AudioOutputStreamType::kMediaStream;
-    }
-  }
-};
-
-}  // namespace mojo
-
-namespace ash::libassistant {
-
-VolumeControlImpl::VolumeControlImpl()
-    : main_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()),
-      weak_factory_(this) {}
-
-void VolumeControlImpl::Initialize(
-    mojom::AudioOutputDelegate* audio_output_delegate,
-    mojom::PlatformDelegate* platform_delegate) {
-  audio_output_delegate_ = audio_output_delegate;
-  platform_delegate->BindAssistantVolumeControl(
-      volume_control_.BindNewPipeAndPassReceiver());
-  mojo::PendingRemote<ash::mojom::VolumeObserver> observer;
-  receiver_.Bind(observer.InitWithNewPipeAndPassReceiver());
-  volume_control_->AddVolumeObserver(std::move(observer));
-}
-
-VolumeControlImpl::~VolumeControlImpl() = default;
-
-void VolumeControlImpl::SetAudioFocus(
-    assistant_client::OutputStreamType focused_stream) {
-  main_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&VolumeControlImpl::SetAudioFocusOnMainThread,
-                                weak_factory_.GetWeakPtr(), focused_stream));
-}
-
-float VolumeControlImpl::GetSystemVolume() {
-  return volume_ * 1.0 / 100.0;
-}
-
-void VolumeControlImpl::SetSystemVolume(float new_volume, bool user_initiated) {
-  main_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&VolumeControlImpl::SetSystemVolumeOnMainThread,
-                     weak_factory_.GetWeakPtr(), new_volume, user_initiated));
-}
-
-float VolumeControlImpl::GetAlarmVolume() {
-  // TODO(muyuanli): implement.
-  return 1.0f;
-}
-
-void VolumeControlImpl::SetAlarmVolume(float new_volume, bool user_initiated) {
-  // TODO(muyuanli): implement.
-}
-
-bool VolumeControlImpl::IsSystemMuted() {
-  return mute_;
-}
-
-void VolumeControlImpl::SetSystemMuted(bool muted) {
-  main_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&VolumeControlImpl::SetSystemMutedOnMainThread,
-                                weak_factory_.GetWeakPtr(), muted));
-}
-
-void VolumeControlImpl::OnVolumeChanged(int volume) {
-  volume_ = volume;
-}
-
-void VolumeControlImpl::OnMuteStateChanged(bool mute) {
-  mute_ = mute;
-}
-
-void VolumeControlImpl::SetAudioFocusOnMainThread(
-    assistant_client::OutputStreamType focused_stream) {
-  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
-  audio_output_delegate_->RequestAudioFocus(
-      mojo::ConvertTo<AudioOutputStreamType>(focused_stream));
-}
-
-void VolumeControlImpl::SetSystemVolumeOnMainThread(float new_volume,
-                                                    bool user_initiated) {
-  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
-  volume_control_->SetVolume(new_volume * 100.0, user_initiated);
-}
-
-void VolumeControlImpl::SetSystemMutedOnMainThread(bool muted) {
-  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
-  volume_control_->SetMuted(muted);
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/audio/volume_control_impl.h b/chromeos/ash/services/libassistant/audio/volume_control_impl.h
deleted file mode 100644
index 983c79d0..0000000
--- a/chromeos/ash/services/libassistant/audio/volume_control_impl.h
+++ /dev/null
@@ -1,66 +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 CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_VOLUME_CONTROL_IMPL_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_VOLUME_CONTROL_IMPL_H_
-
-#include "ash/public/mojom/assistant_volume_control.mojom.h"
-#include "base/memory/raw_ptr.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/libassistant/public/mojom/audio_output_delegate.mojom.h"
-#include "chromeos/ash/services/libassistant/public/mojom/platform_delegate.mojom-forward.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
-
-namespace ash::libassistant {
-
-class VolumeControlImpl : public assistant_client::VolumeControl,
-                          public ash::mojom::VolumeObserver {
- public:
-  VolumeControlImpl();
-
-  VolumeControlImpl(const VolumeControlImpl&) = delete;
-  VolumeControlImpl& operator=(const VolumeControlImpl&) = delete;
-
-  ~VolumeControlImpl() override;
-
-  void Initialize(mojom::AudioOutputDelegate* audio_output_delegate,
-                  mojom::PlatformDelegate* platform_delegate);
-
-  // assistant_client::VolumeControl overrides:
-  void SetAudioFocus(
-      assistant_client::OutputStreamType focused_stream) override;
-  float GetSystemVolume() override;
-  void SetSystemVolume(float new_volume, bool user_initiated) override;
-  float GetAlarmVolume() override;
-  void SetAlarmVolume(float new_volume, bool user_initiated) override;
-  bool IsSystemMuted() override;
-  void SetSystemMuted(bool muted) override;
-
-  // ash::mojom::VolumeObserver overrides:
-  void OnVolumeChanged(int volume) override;
-  void OnMuteStateChanged(bool mute) override;
-
- private:
-  void SetAudioFocusOnMainThread(
-      assistant_client::OutputStreamType focused_stream);
-  void SetSystemVolumeOnMainThread(float new_volume, bool user_initiated);
-  void SetSystemMutedOnMainThread(bool muted);
-
-  // Owned by |AudioOutputProviderImpl|.
-  raw_ptr<mojom::AudioOutputDelegate> audio_output_delegate_ = nullptr;
-  mojo::Remote<ash::mojom::AssistantVolumeControl> volume_control_;
-  mojo::Receiver<ash::mojom::VolumeObserver> receiver_{this};
-  scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
-
-  int volume_ = 100;
-  bool mute_ = false;
-
-  base::WeakPtrFactory<VolumeControlImpl> weak_factory_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_VOLUME_CONTROL_IMPL_H_
diff --git a/chromeos/ash/services/libassistant/audio_input_controller.cc b/chromeos/ash/services/libassistant/audio_input_controller.cc
deleted file mode 100644
index fdeb3fa..0000000
--- a/chromeos/ash/services/libassistant/audio_input_controller.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/audio_input_controller.h"
-
-#include "base/notreached.h"
-
-namespace ash::libassistant {
-
-AudioInputController::AudioInputController() = default;
-
-AudioInputController::~AudioInputController() = default;
-
-void AudioInputController::Bind(
-    mojo::PendingReceiver<mojom::AudioInputController> receiver,
-    mojom::PlatformDelegate* platform_delegate) {
-  receiver_.Bind(std::move(receiver));
-  audio_input().Initialize(platform_delegate);
-}
-
-void AudioInputController::SetMicOpen(bool mic_open) {
-  audio_input().SetMicState(mic_open);
-}
-
-void AudioInputController::SetHotwordEnabled(bool enable) {
-  audio_input().OnHotwordEnabled(enable);
-}
-
-void AudioInputController::SetDeviceId(
-    const std::optional<std::string>& device_id) {
-  DCHECK(device_id != "");
-  audio_input().SetDeviceId(device_id);
-}
-
-void AudioInputController::SetHotwordDeviceId(
-    const std::optional<std::string>& device_id) {
-  DCHECK(device_id != "");
-  audio_input().SetHotwordDeviceId(device_id);
-}
-
-void AudioInputController::SetLidState(mojom::LidState new_state) {
-  audio_input().OnLidStateChanged(new_state);
-}
-
-void AudioInputController::OnConversationTurnStarted() {
-  audio_input().OnConversationTurnStarted();
-}
-
-void AudioInputController::OnInteractionFinished(Resolution resolution) {
-  // TODO(b/179924068): Find a better way to handle the edge cases.
-  if (resolution != Resolution::NORMAL_WITH_FOLLOW_ON &&
-      resolution != Resolution::CANCELLED &&
-      resolution != Resolution::BARGE_IN) {
-    SetMicOpen(false);
-  }
-
-  audio_input().OnConversationTurnFinished();
-}
-
-AudioInputImpl& AudioInputController::audio_input() {
-  return audio_input_provider().GetAudioInput();
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/audio_input_controller.h b/chromeos/ash/services/libassistant/audio_input_controller.h
deleted file mode 100644
index 6b5cc2b..0000000
--- a/chromeos/ash/services/libassistant/audio_input_controller.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_INPUT_CONTROLLER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_INPUT_CONTROLLER_H_
-
-#include "chromeos/ash/services/libassistant/audio/audio_input_provider_impl.h"
-#include "chromeos/ash/services/libassistant/conversation_state_listener_impl.h"
-#include "chromeos/ash/services/libassistant/public/mojom/audio_input_controller.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-
-namespace ash::libassistant {
-
-// Implementation of |mojom::AudioInputController| that will forward all calls
-// to a Libassistant V1 |assistant_client::AudioInputProvider| implementation.
-class COMPONENT_EXPORT(LIBASSISTANT_SERVICE) AudioInputController
-    : public mojom::AudioInputController {
- public:
-  using Resolution = assistant_client::ConversationStateListener::Resolution;
-
-  AudioInputController();
-  AudioInputController(AudioInputController&) = delete;
-  AudioInputController& operator=(AudioInputController&) = delete;
-  ~AudioInputController() override;
-
-  void Bind(mojo::PendingReceiver<mojom::AudioInputController> receiver,
-            mojom::PlatformDelegate* platform_delegate);
-
-  // mojom::AudioInputController implementation:
-  void SetMicOpen(bool mic_open) override;
-  void SetHotwordEnabled(bool enable) override;
-  void SetDeviceId(const std::optional<std::string>& device_id) override;
-  void SetHotwordDeviceId(const std::optional<std::string>& device_id) override;
-  void SetLidState(mojom::LidState new_state) override;
-  void OnConversationTurnStarted() override;
-
-  // Invoked when the current conversation turn has finished.
-  void OnInteractionFinished(Resolution resolution);
-
-  AudioInputProviderImpl& audio_input_provider() {
-    return audio_input_provider_;
-  }
-
- private:
-  AudioInputImpl& audio_input();
-
-  mojo::Receiver<mojom::AudioInputController> receiver_{this};
-  AudioInputProviderImpl audio_input_provider_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_INPUT_CONTROLLER_H_
diff --git a/chromeos/ash/services/libassistant/audio_input_controller_unittest.cc b/chromeos/ash/services/libassistant/audio_input_controller_unittest.cc
deleted file mode 100644
index 919a3cb..0000000
--- a/chromeos/ash/services/libassistant/audio_input_controller_unittest.cc
+++ /dev/null
@@ -1,593 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/audio_input_controller.h"
-
-#include <optional>
-
-#include "base/test/gtest_util.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/test/task_environment.h"
-#include "base/time/time.h"
-#include "chromeos/ash/services/assistant/public/cpp/features.h"
-#include "chromeos/ash/services/libassistant/audio/audio_input_impl.h"
-#include "chromeos/ash/services/libassistant/audio/audio_input_stream.h"
-#include "chromeos/ash/services/libassistant/public/mojom/audio_input_controller.mojom.h"
-#include "chromeos/ash/services/libassistant/test_support/fake_platform_delegate.h"
-#include "media/audio/audio_device_description.h"
-#include "media/mojo/mojom/audio_data_pipe.mojom.h"
-#include "media/mojo/mojom/audio_stream_factory.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "services/audio/public/cpp/fake_stream_factory.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::libassistant {
-
-namespace {
-using mojom::LidState;
-using testing::_;
-using Resolution = assistant_client::ConversationStateListener::Resolution;
-
-constexpr char kNormalDeviceId[] = "normal-device-id";
-constexpr char kHotwordDeviceId[] = "hotword-device-id";
-constexpr char kSkipForNonDspMessage[] = "This test case is for DSP";
-
-class MockStreamFactory : public audio::FakeStreamFactory {
- public:
-  MOCK_METHOD(
-      void,
-      CreateInputStream,
-      (mojo::PendingReceiver<::media::mojom::AudioInputStream> stream_receiver,
-       mojo::PendingRemote<media::mojom::AudioInputStreamClient> client,
-       mojo::PendingRemote<::media::mojom::AudioInputStreamObserver> observer,
-       mojo::PendingRemote<::media::mojom::AudioLog> log,
-       const std::string& device_id,
-       const media::AudioParameters& params,
-       uint32_t shared_memory_count,
-       bool enable_agc,
-       media::mojom::AudioProcessingConfigPtr processing_config,
-       CreateInputStreamCallback callback),
-      (override));
-};
-
-class FakeAudioInputObserver : public assistant_client::AudioInput::Observer {
- public:
-  FakeAudioInputObserver() = default;
-  FakeAudioInputObserver(FakeAudioInputObserver&) = delete;
-  FakeAudioInputObserver& operator=(FakeAudioInputObserver&) = delete;
-  ~FakeAudioInputObserver() override = default;
-
-  // assistant_client::AudioInput::Observer implementation:
-  void OnAudioBufferAvailable(const assistant_client::AudioBuffer& buffer,
-                              int64_t timestamp) override {}
-  void OnAudioError(assistant_client::AudioInput::Error error) override {}
-  void OnAudioStopped() override {}
-};
-
-class AssistantAudioInputControllerTest : public testing::TestWithParam<bool> {
- public:
-  AssistantAudioInputControllerTest() : enable_dsp_(GetParam()), controller_() {
-    controller_.Bind(client_.BindNewPipeAndPassReceiver(), &platform_delegate_);
-
-    if (enable_dsp_) {
-      // Enable DSP feature flag.
-      scoped_feature_list_.InitAndEnableFeature(
-          assistant::features::kEnableDspHotword);
-    }
-  }
-
-  void TearDown() override {
-    if (IsSkipped()) {
-      return;
-    }
-
-    EXPECT_TRUE(pre_condition_checked_)
-        << "You must call AssertHotwordAvailableState or MarkPreconditionMet "
-           "to confirm that you are testing the expected environment";
-  }
-
-  // Hotword test requires some set up. AudioInputImpl automatically falls back
-  // to non-DSP hotword if it doesn't meet the condition. This function checks
-  // whether the test is exercising the expected environment.
-  void AssertHotwordAvailableState() {
-    ASSERT_EQ(enable_dsp_, audio_input().IsHotwordAvailable());
-    pre_condition_checked_ = true;
-  }
-
-  // Some test cases exercises non-DSP behavior even for DSP available variant.
-  // Call this function at the end of its test body to mark that the test is
-  // intentionally exercising that scenario.
-  void MarkPreconditionMet() {
-    ASSERT_FALSE(pre_condition_checked_) << "Pre-condition is already checked.";
-    pre_condition_checked_ = true;
-  }
-
-  // See |InitializeForTestOfType| for an explanation of this enum.
-  enum TestType {
-    kLidStateTest,
-    kAudioInputObserverTest,
-    kDeviceIdTest,
-    kHotwordDeviceIdTest,
-    kHotwordEnabledTest,
-  };
-
-  // To successfully start recording audio, a lot of requirements must be met
-  // (we need a device-id, an audio-input-observer, the lid must be open, and so
-  // on).
-  // This method will ensure all these requirements are met *except* the ones
-  // that we're testing. So for example if you call
-  // InitializeForTestOfType(kLidState) then this will ensure all requirements
-  // are set but not the lid state (which is left in its initial value).
-  //
-  // TODO(b/242776750): Set up in test body instead of using this utility method
-  // to make it clear what set up the test is testing.
-  void InitializeForTestOfType(TestType type) {
-    if (type != kLidStateTest)
-      SetLidState(LidState::kOpen);
-
-    if (type != kAudioInputObserverTest)
-      AddAudioInputObserver();
-
-    if (type != kDeviceIdTest)
-      SetDeviceId(kNormalDeviceId);
-
-    if (type != kHotwordEnabledTest)
-      SetHotwordEnabled(true);
-
-    if (type != kHotwordDeviceIdTest && enable_dsp_)
-      SetHotwordDeviceId(kHotwordDeviceId);
-  }
-
-  mojo::Remote<mojom::AudioInputController>& client() { return client_; }
-
-  AudioInputController& controller() { return controller_; }
-
-  AudioInputImpl& audio_input() {
-    return controller().audio_input_provider().GetAudioInput();
-  }
-
-  bool IsEnableDspFlagOn() { return enable_dsp_; }
-
-  // TODO(b/242776750): Change this to NotRecordingAudio. If we test that it's
-  // recording, we should test expected channel (query or hotword) as well with
-  // using IsRecordingForQuery or IsRecordingHotword.
-  bool IsRecordingAudio() { return audio_input().IsRecordingForTesting(); }
-
-  // TODO(b/242776750): Make this a custom matcher to provide better error
-  // message.
-  bool IsRecordingForQuery() {
-    return audio_input().IsRecordingForTesting() &&
-           audio_input().IsMicOpenForTesting() &&
-           audio_input().GetOpenDeviceIdForTesting() == kNormalDeviceId;
-  }
-
-  bool IsRecordingHotword() {
-    if (enable_dsp_) {
-      return audio_input().IsRecordingForTesting() &&
-             !audio_input().IsMicOpenForTesting() &&
-             audio_input().GetOpenDeviceIdForTesting() == kHotwordDeviceId;
-    } else {
-      return audio_input().IsRecordingForTesting() &&
-             !audio_input().IsMicOpenForTesting() &&
-             audio_input().GetOpenDeviceIdForTesting() == kNormalDeviceId;
-    }
-  }
-
-  bool IsUsingDeadStreamDetection() {
-    return audio_input().IsUsingDeadStreamDetectionForTesting().value_or(false);
-  }
-
-  bool HasCreateInputStreamCalled(MockStreamFactory* mock_stream_factory) {
-    EXPECT_CALL(*mock_stream_factory,
-                CreateInputStream(_, _, _, _, _, _, _, _, _, _))
-        .WillOnce(testing::Invoke(
-            [](testing::Unused, testing::Unused, testing::Unused,
-               testing::Unused, testing::Unused, testing::Unused,
-               testing::Unused, testing::Unused, testing::Unused,
-               media::mojom::AudioStreamFactory::CreateInputStreamCallback
-                   callback) {
-              // Invoke the callback as it becomes error if the callback never
-              // gets invoked.
-              std::move(callback).Run(nullptr, false, std::nullopt);
-            }));
-
-    mojo::PendingReceiver<media::mojom::AudioStreamFactory> pending_receiver =
-        platform_delegate_.stream_factory_receiver();
-    EXPECT_TRUE(pending_receiver.is_valid());
-    mock_stream_factory->receiver_.Bind(std::move(pending_receiver));
-    mock_stream_factory->receiver_.FlushForTesting();
-
-    return testing::Mock::VerifyAndClearExpectations(mock_stream_factory);
-  }
-
-  std::string GetOpenDeviceId() {
-    return audio_input().GetOpenDeviceIdForTesting().value_or("<none>");
-  }
-
-  void SetLidState(LidState new_state) {
-    client()->SetLidState(new_state);
-    client().FlushForTesting();
-  }
-
-  void SetDeviceId(const std::optional<std::string>& value) {
-    client()->SetDeviceId(value);
-    client().FlushForTesting();
-  }
-
-  void SetHotwordDeviceId(const std::optional<std::string>& value) {
-    client()->SetHotwordDeviceId(value);
-    client().FlushForTesting();
-  }
-
-  void SetHotwordEnabled(bool value) {
-    client()->SetHotwordEnabled(value);
-    client().FlushForTesting();
-  }
-
-  void SetMicOpen(bool mic_open) {
-    client()->SetMicOpen(mic_open);
-    client().FlushForTesting();
-  }
-
-  void AddAudioInputObserver() {
-    audio_input().AddObserver(&audio_input_observer_);
-  }
-
-  void OnConversationTurnStarted() { controller().OnConversationTurnStarted(); }
-
-  void OnConversationTurnFinished(Resolution resolution = Resolution::NORMAL) {
-    controller().OnInteractionFinished(resolution);
-  }
-
- protected:
-  base::test::TaskEnvironment environment_{
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
-
- private:
-  const bool enable_dsp_;
-  bool pre_condition_checked_ = false;
-  base::test::ScopedFeatureList scoped_feature_list_;
-  mojo::Remote<mojom::AudioInputController> client_;
-  AudioInputController controller_;
-  FakeAudioInputObserver audio_input_observer_;
-  assistant::FakePlatformDelegate platform_delegate_;
-};
-
-INSTANTIATE_TEST_SUITE_P(Assistant,
-                         AssistantAudioInputControllerTest,
-                         testing::Bool(),
-                         [](const testing::TestParamInfo<bool>& param) {
-                           return param.param ? "DSP" : "NonDSP";
-                         });
-
-}  // namespace
-
-TEST_P(AssistantAudioInputControllerTest, ShouldOnlyRecordWhenLidIsOpen) {
-  InitializeForTestOfType(kLidStateTest);
-  AssertHotwordAvailableState();
-
-  // Initially the lid is considered closed.
-  EXPECT_FALSE(IsRecordingAudio());
-
-  SetLidState(LidState::kOpen);
-  EXPECT_TRUE(IsRecordingAudio());
-
-  SetLidState(LidState::kClosed);
-  EXPECT_FALSE(IsRecordingAudio());
-}
-
-TEST_P(AssistantAudioInputControllerTest, ShouldOnlyRecordWhenDeviceIdIsSet) {
-  InitializeForTestOfType(kDeviceIdTest);
-
-  // Initially there is no device id.
-  EXPECT_FALSE(IsRecordingAudio());
-
-  SetDeviceId(kNormalDeviceId);
-  AssertHotwordAvailableState();
-  EXPECT_TRUE(IsRecordingHotword());
-
-  SetDeviceId(std::nullopt);
-  EXPECT_FALSE(IsRecordingAudio());
-}
-
-TEST_P(AssistantAudioInputControllerTest, StopOnlyRecordWhenHotwordIsEnabled) {
-  InitializeForTestOfType(kHotwordEnabledTest);
-  AssertHotwordAvailableState();
-
-  // Hotword is enabled by InitializeForTestOfType.
-  EXPECT_TRUE(IsRecordingHotword());
-
-  SetHotwordEnabled(false);
-  EXPECT_FALSE(IsRecordingHotword());
-  // Double check that AudioInputImpl is not recording any other type of audio.
-  EXPECT_FALSE(IsRecordingAudio());
-
-  SetHotwordEnabled(true);
-  EXPECT_TRUE(IsRecordingHotword());
-}
-
-TEST_P(AssistantAudioInputControllerTest,
-       StartRecordingWhenDisableHotwordAndForceOpenMic) {
-  InitializeForTestOfType(kHotwordEnabledTest);
-  SetHotwordEnabled(false);
-  AssertHotwordAvailableState();
-
-  EXPECT_FALSE(IsRecordingAudio());
-
-  // Force open mic should start recording.
-  // This is exercising a corner case. OnConversationTurnStarted() should be
-  // called if mic gets opened.
-  // TODO(b/242776750): Change the query recording condition as mic open +
-  // OnConversationTurnStarted, i.e. do not record for a query if
-  // OnConversationTurnStarted not called.
-  SetMicOpen(true);
-  EXPECT_TRUE(IsRecordingForQuery());
-
-  SetMicOpen(false);
-  EXPECT_FALSE(IsRecordingAudio());
-}
-
-TEST_P(AssistantAudioInputControllerTest, ShouldUseProvidedDeviceId) {
-  InitializeForTestOfType(kDeviceIdTest);
-  SetDeviceId("the-expected-device-id");
-  AssertHotwordAvailableState();
-
-  SetMicOpen(true);
-  OnConversationTurnStarted();
-  EXPECT_TRUE(IsRecordingAudio());
-  EXPECT_EQ("the-expected-device-id", GetOpenDeviceId());
-}
-
-TEST_P(AssistantAudioInputControllerTest,
-       ShouldSwitchToHotwordDeviceIdWhenSet) {
-  if (!IsEnableDspFlagOn()) {
-    GTEST_SKIP() << kSkipForNonDspMessage;
-  }
-
-  InitializeForTestOfType(kHotwordDeviceIdTest);
-
-  SetDeviceId(kNormalDeviceId);
-  EXPECT_TRUE(IsRecordingAudio());
-  EXPECT_EQ(kNormalDeviceId, GetOpenDeviceId());
-
-  SetHotwordDeviceId(kHotwordDeviceId);
-  AssertHotwordAvailableState();
-  EXPECT_TRUE(IsRecordingAudio());
-  EXPECT_EQ(kHotwordDeviceId, GetOpenDeviceId());
-}
-
-TEST_P(AssistantAudioInputControllerTest,
-       ShouldKeepUsingHotwordDeviceIdWhenDeviceIdChanges) {
-  if (!IsEnableDspFlagOn()) {
-    GTEST_SKIP() << kSkipForNonDspMessage;
-  }
-
-  InitializeForTestOfType(kHotwordDeviceIdTest);
-
-  SetDeviceId(kNormalDeviceId);
-  SetHotwordDeviceId(kHotwordDeviceId);
-  AssertHotwordAvailableState();
-
-  EXPECT_TRUE(IsRecordingAudio());
-  EXPECT_EQ(kHotwordDeviceId, GetOpenDeviceId());
-
-  SetDeviceId("new-normal-device-id");
-  EXPECT_TRUE(IsRecordingAudio());
-  EXPECT_EQ(kHotwordDeviceId, GetOpenDeviceId());
-}
-
-TEST_P(AssistantAudioInputControllerTest,
-       ShouldUseDefaultDeviceIdIfNoDeviceIdIsSet) {
-  InitializeForTestOfType(kDeviceIdTest);
-
-  // Mic must be open, otherwise we will not start recording audio if the
-  // device id is not set.
-  SetMicOpen(true);
-  SetDeviceId(std::nullopt);
-  SetHotwordDeviceId(std::nullopt);
-
-  EXPECT_TRUE(IsRecordingAudio());
-  EXPECT_EQ(media::AudioDeviceDescription::kDefaultDeviceId, GetOpenDeviceId());
-
-  MarkPreconditionMet();
-}
-
-TEST_P(AssistantAudioInputControllerTest,
-       DeadStreamDetectionShouldBeDisabledWhenUsingHotwordDevice) {
-  if (!IsEnableDspFlagOn()) {
-    GTEST_SKIP() << kSkipForNonDspMessage;
-  }
-
-  InitializeForTestOfType(kHotwordDeviceIdTest);
-
-  SetHotwordDeviceId(std::nullopt);
-  EXPECT_TRUE(IsUsingDeadStreamDetection());
-
-  SetHotwordDeviceId(kHotwordDeviceId);
-  AssertHotwordAvailableState();
-  EXPECT_FALSE(IsUsingDeadStreamDetection());
-}
-
-TEST_P(AssistantAudioInputControllerTest,
-       ShouldSwitchToNormalAudioDeviceWhenConversationTurnStarts) {
-  if (!IsEnableDspFlagOn()) {
-    GTEST_SKIP() << kSkipForNonDspMessage;
-  }
-
-  InitializeForTestOfType(kDeviceIdTest);
-  SetDeviceId("normal-device-id");
-  SetHotwordDeviceId("hotword-device-id");
-  AssertHotwordAvailableState();
-
-  // While checking for hotword we should be using the hotword device.
-  EXPECT_EQ("hotword-device-id", GetOpenDeviceId());
-
-  // But once the conversation starts we should be using the normal audio
-  // device.
-  OnConversationTurnStarted();
-  EXPECT_EQ("normal-device-id", GetOpenDeviceId());
-}
-
-TEST_P(AssistantAudioInputControllerTest,
-       ShouldSwitchToHotwordAudioDeviceWhenConversationIsFinished) {
-  if (!IsEnableDspFlagOn()) {
-    GTEST_SKIP() << kSkipForNonDspMessage;
-  }
-
-  InitializeForTestOfType(kDeviceIdTest);
-  SetDeviceId("normal-device-id");
-  SetHotwordDeviceId("hotword-device-id");
-  AssertHotwordAvailableState();
-
-  // During the conversation we should be using the normal audio device.
-  OnConversationTurnStarted();
-  EXPECT_EQ("normal-device-id", GetOpenDeviceId());
-
-  // But once the conversation finishes, we should check for hotwords using the
-  // hotword device.
-  OnConversationTurnFinished();
-  EXPECT_EQ("hotword-device-id", GetOpenDeviceId());
-}
-
-TEST_P(AssistantAudioInputControllerTest,
-       ShouldCloseMicWhenConversationIsFinishedNormally) {
-  InitializeForTestOfType(kDeviceIdTest);
-  SetMicOpen(true);
-  SetDeviceId(kNormalDeviceId);
-  SetHotwordDeviceId(kHotwordDeviceId);
-  AssertHotwordAvailableState();
-
-  // Mic should keep opened during the conversation.
-  OnConversationTurnStarted();
-  EXPECT_TRUE(IsRecordingForQuery());
-
-  // Once the conversation has finished normally without needing mic to keep
-  // opened, we should close it.
-  OnConversationTurnFinished();
-  EXPECT_TRUE(IsRecordingHotword());
-}
-
-TEST_P(AssistantAudioInputControllerTest,
-       ShouldKeepMicOpenedIfNeededWhenConversationIsFinished) {
-  InitializeForTestOfType(kDeviceIdTest);
-  SetMicOpen(true);
-  SetDeviceId(kNormalDeviceId);
-  SetHotwordDeviceId(kHotwordDeviceId);
-  AssertHotwordAvailableState();
-
-  // Mic should keep opened during the conversation.
-  OnConversationTurnStarted();
-  EXPECT_EQ(true, IsRecordingForQuery());
-
-  // If the conversation is finished where mic should still be kept opened
-  // (i.e. there's a follow-up interaction), we should keep mic opened.
-  OnConversationTurnFinished(Resolution::NORMAL_WITH_FOLLOW_ON);
-
-  // TODO(b/242776750): MicOpen=true doesn't mean that AudioInputImpl is
-  // recording. Double check that whether it's expected behavior, i.e. whether
-  // this expects that IsRecordingForQuery=true or not.
-  EXPECT_EQ(true, audio_input().IsMicOpenForTesting());
-}
-
-TEST_P(AssistantAudioInputControllerTest,
-       ShouldCloseMicWhenConversationIsFinishedNormallyHotwordOff) {
-  InitializeForTestOfType(kDeviceIdTest);
-  SetDeviceId(kNormalDeviceId);
-  SetHotwordDeviceId(kHotwordDeviceId);
-  SetHotwordEnabled(false);
-  AssertHotwordAvailableState();
-  ASSERT_EQ(false, IsRecordingAudio());
-
-  SetMicOpen(true);
-  OnConversationTurnStarted();
-  EXPECT_EQ(true, IsRecordingForQuery());
-
-  OnConversationTurnFinished();
-  EXPECT_EQ(false, IsRecordingAudio());
-}
-
-TEST_P(AssistantAudioInputControllerTest, DSPTrigger) {
-  if (!IsEnableDspFlagOn()) {
-    GTEST_SKIP() << kSkipForNonDspMessage;
-  }
-
-  InitializeForTestOfType(kHotwordDeviceIdTest);
-  SetHotwordDeviceId(kHotwordDeviceId);
-  SetHotwordEnabled(true);
-  AssertHotwordAvailableState();
-  ASSERT_EQ(true, IsRecordingHotword());
-
-  MockStreamFactory mock_stream_factory;
-  EXPECT_TRUE(HasCreateInputStreamCalled(&mock_stream_factory));
-
-  // Until the conversation ends, no new input stream should be created.
-  EXPECT_CALL(mock_stream_factory,
-              CreateInputStream(_, _, _, _, _, _, _, _, _, _))
-      .Times(0);
-
-  // Simulate DSP hotword activation. When DSP detects a hotword, it starts
-  // sending audio data until the channel gets closed.
-  audio_input().OnCaptureDataArrivedForTesting();
-  EXPECT_EQ(GetOpenDeviceId(), kHotwordDeviceId);
-
-  // |OnConversationTurnStarted| gets called once libassistant also detects a
-  // hotword in the stream.
-  OnConversationTurnStarted();
-
-  // Forward 3 seconds to make sure that software rejection timer is already
-  // cancelled.
-  environment_.FastForwardBy(base::Seconds(3));
-  environment_.RunUntilIdle();
-
-  // During the conversation, an audio stream used for detecting the hotword
-  // should be used.
-  EXPECT_TRUE(IsRecordingHotword());
-
-  testing::Mock::VerifyAndClearExpectations(&mock_stream_factory);
-  OnConversationTurnFinished();
-
-  // Once the converstation ends, the old audio stream will get closed and a new
-  // one should be created.
-  mock_stream_factory.ResetReceiver();
-  EXPECT_TRUE(HasCreateInputStreamCalled(&mock_stream_factory));
-  EXPECT_TRUE(IsRecordingHotword());
-  EXPECT_EQ(GetOpenDeviceId(), kHotwordDeviceId);
-}
-
-TEST_P(AssistantAudioInputControllerTest, DSPTriggerredButSoftwareRejection) {
-  if (!IsEnableDspFlagOn()) {
-    GTEST_SKIP() << kSkipForNonDspMessage;
-  }
-
-  InitializeForTestOfType(kHotwordDeviceIdTest);
-  SetHotwordDeviceId(kHotwordDeviceId);
-  SetHotwordEnabled(true);
-  AssertHotwordAvailableState();
-  ASSERT_EQ(true, IsRecordingHotword());
-
-  MockStreamFactory mock_stream_factory;
-  EXPECT_TRUE(HasCreateInputStreamCalled(&mock_stream_factory));
-
-  // Simulate DSP hotword activation. When DSP detects a hotword, it starts
-  // sending audio data until the channel gets closed.
-  audio_input().OnCaptureDataArrivedForTesting();
-  EXPECT_EQ(GetOpenDeviceId(), kHotwordDeviceId);
-
-  // If libassistant does not detect a hotword in the audio stream, it will not
-  // call |OnConversationTurnStarted|. |DspHotwordStateManager| considers that
-  // the hotword gets rejected if it doesn't get the callback in 1 second.
-  environment_.FastForwardBy(base::Seconds(1));
-  environment_.RunUntilIdle();
-
-  // If it's rejected by libassistant, DSP audio stream should be re-created.
-  mock_stream_factory.ResetReceiver();
-  EXPECT_TRUE(HasCreateInputStreamCalled(&mock_stream_factory));
-  EXPECT_TRUE(IsRecordingHotword());
-  EXPECT_EQ(GetOpenDeviceId(), kHotwordDeviceId);
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/authentication_state_observer_unittest.cc b/chromeos/ash/services/libassistant/authentication_state_observer_unittest.cc
deleted file mode 100644
index 3a06084c..0000000
--- a/chromeos/ash/services/libassistant/authentication_state_observer_unittest.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/test/task_environment.h"
-#include "chromeos/ash/services/libassistant/libassistant_service.h"
-#include "chromeos/ash/services/libassistant/public/mojom/authentication_state_observer.mojom.h"
-#include "chromeos/ash/services/libassistant/test_support/libassistant_service_tester.h"
-#include "chromeos/assistant/internal/internal_util.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-class AuthenticationStateObserverMock
-    : public mojom::AuthenticationStateObserver {
- public:
-  AuthenticationStateObserverMock() = default;
-  AuthenticationStateObserverMock(const AuthenticationStateObserverMock&) =
-      delete;
-  AuthenticationStateObserverMock& operator=(
-      const AuthenticationStateObserverMock&) = delete;
-  ~AuthenticationStateObserverMock() override = default;
-
-  // mojom::AuthenticationStateObserver implementation:
-  MOCK_METHOD(void, OnAuthenticationError, ());
-
-  mojo::PendingRemote<mojom::AuthenticationStateObserver>
-  BindNewPipeAndPassRemote() {
-    return receiver_.BindNewPipeAndPassRemote();
-  }
-
-  void FlushForTesting() { receiver_.FlushForTesting(); }
-
- private:
-  mojo::Receiver<mojom::AuthenticationStateObserver> receiver_{this};
-};
-
-}  // namespace
-
-class AuthenticationStateObserverTest : public ::testing::Test {
- public:
-  AuthenticationStateObserverTest() = default;
-  AuthenticationStateObserverTest(const AuthenticationStateObserverTest&) =
-      delete;
-  AuthenticationStateObserverTest& operator=(
-      const AuthenticationStateObserverTest&) = delete;
-  ~AuthenticationStateObserverTest() override = default;
-
-  void SetUp() override {
-    service_tester_.service().AddAuthenticationStateObserver(
-        observer_mock_.BindNewPipeAndPassRemote());
-
-    service_tester_.Start();
-
-    service_tester_.service()
-        .conversation_controller()
-        .OnAssistantClientRunning(&service_tester_.assistant_client());
-  }
-
-  AuthenticationStateObserverMock& observer_mock() { return observer_mock_; }
-
-  void FlushMojomPipes() { service_tester_.FlushForTesting(); }
-
-  void OnCommunicationError() {
-    ::assistant::api::OnDeviceStateEventRequest request;
-    auto* communication_error =
-        request.mutable_event()->mutable_on_communication_error();
-    communication_error->set_error_code(
-        ::assistant::api::events::DeviceStateEvent::OnCommunicationError::
-            AUTH_TOKEN_FAIL);
-
-    service_tester_.service().conversation_controller().OnGrpcMessageForTesting(
-        request);
-  }
-
- private:
-  base::test::SingleThreadTaskEnvironment environment_;
-  ::testing::StrictMock<AuthenticationStateObserverMock> observer_mock_;
-  LibassistantServiceTester service_tester_;
-};
-
-TEST_F(AuthenticationStateObserverTest, ShouldReportAuthenticationErrors) {
-  EXPECT_CALL(observer_mock(), OnAuthenticationError());
-  OnCommunicationError();
-
-  FlushMojomPipes();
-  ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&observer_mock()))
-      << "Failure to receive Auth error.";
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/callback_utils.h b/chromeos/ash/services/libassistant/callback_utils.h
deleted file mode 100644
index 2f0a24b..0000000
--- a/chromeos/ash/services/libassistant/callback_utils.h
+++ /dev/null
@@ -1,167 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_CALLBACK_UTILS_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_CALLBACK_UTILS_H_
-
-#include <functional>
-#include <utility>
-
-#include "base/functional/bind.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/task/sequenced_task_runner.h"
-
-namespace ash::libassistant {
-
-namespace internal {
-
-template <typename CALLBACK_TYPE>
-class RefCountedCallback
-    : public base::RefCountedThreadSafe<RefCountedCallback<CALLBACK_TYPE>> {
- public:
-  RefCountedCallback(CALLBACK_TYPE callback) : callback_(std::move(callback)) {}
-  RefCountedCallback(const RefCountedCallback&) = delete;
-  RefCountedCallback& operator=(const RefCountedCallback&) = delete;
-
-  CALLBACK_TYPE& callback() { return callback_; }
-
- private:
-  friend class base::RefCountedThreadSafe<RefCountedCallback<CALLBACK_TYPE>>;
-
-  ~RefCountedCallback() = default;
-  CALLBACK_TYPE callback_;
-};
-
-}  // namespace internal
-
-// Wrapper around a |base::OnceCallback| that converts it to a std::function.
-// Crashes if called more than once.
-template <typename... Args>
-std::function<void(Args...)> ToStdFunction(
-    base::OnceCallback<void(Args...)> once_callback) {
-  // Note we need to wrap the move-only once callback,
-  // as std::function must always be copyable.
-  using CallbackType = base::OnceCallback<void(Args...)>;
-  using RefCountedCallbackType = internal::RefCountedCallback<CallbackType>;
-
-  return [callback_ref = base::MakeRefCounted<RefCountedCallbackType>(
-              std::move(once_callback))](Args... args) {
-    std::move(callback_ref->callback()).Run(std::forward<Args>(args)...);
-  };
-}
-
-// Wrapper around a |base::RepeatingCallback| that converts it to a
-// std::function.
-template <typename... Args>
-std::function<void(Args...)> ToStdFunctionRepeating(
-    base::RepeatingCallback<void(Args...)> repeating_callback) {
-  return [callback = repeating_callback](Args... args) {
-    callback.Run(std::forward<Args>(args)...);
-  };
-}
-
-// Wraps a |base::OnceCallback| callback1<Args1> that changes its argument to
-// Args2, where Args2 is transformed from Args1 applying the |transformer| rule.
-template <typename... Args1, typename... Args2, typename Functor>
-base::OnceCallback<void(Args1...)> AdaptCallback(
-    base::OnceCallback<void(Args2...)> once_callback,
-    Functor&& transformer) {
-  return base::BindOnce(
-      [](base::OnceCallback<void(Args2...)> callback, Functor&& transformer,
-         Args1&&... args) {
-        std::move(callback).Run(transformer(std::forward<Args1>(args)...));
-      },
-      std::move(once_callback), std::forward<Functor>(transformer));
-}
-
-// Binds a method call to the current sequence, meaning we ensure |callback|
-// will always be called from the current sequence. If the call comes from a
-// different sequence it will be posted to the correct one.
-template <typename... Args>
-base::OnceCallback<void(Args...)> BindToCurrentSequence(
-    base::OnceCallback<void(Args...)> callback) {
-  return base::BindOnce(
-      [](base::OnceCallback<void(Args...)> callback,
-         scoped_refptr<base::SequencedTaskRunner> sequence_runner,
-         Args&&... args) {
-        // Invoke the callback on the original sequence.
-        if (sequence_runner->RunsTasksInCurrentSequence()) {
-          std::move(callback).Run(std::forward<Args>(args)...);
-        } else {
-          sequence_runner->PostTask(
-              FROM_HERE,
-              base::BindOnce(std::move(callback), std::forward<Args>(args)...));
-        }
-      },
-      std::move(callback), base::SequencedTaskRunner::GetCurrentDefault());
-}
-
-// Binds a method call to the current sequence, meaning we ensure |callback|
-// will always be called from the current sequence. If the call comes from a
-// different sequence it will be posted to the correct one.
-template <typename... Args>
-base::RepeatingCallback<void(Args...)> BindToCurrentSequenceRepeating(
-    base::RepeatingCallback<void(Args...)> callback) {
-  return base::BindRepeating(
-      [](base::RepeatingCallback<void(Args...)> callback,
-         scoped_refptr<base::SequencedTaskRunner> sequence_runner,
-         Args&&... args) {
-        // Invoke the callback on the original sequence.
-        if (sequence_runner->RunsTasksInCurrentSequence()) {
-          callback.Run(std::forward<Args>(args)...);
-        } else {
-          sequence_runner->PostTask(
-              FROM_HERE,
-              base::BindRepeating(callback, std::forward<Args>(args)...));
-        }
-      },
-      callback, base::SequencedTaskRunner::GetCurrentDefault());
-}
-
-// Binds a method call to the current sequence.
-// This is a convenience version, that allows you to easily wrap a callback
-// and change the arguments.
-//
-// This allows you to type
-//
-//      BindToCurrentSequence(
-//         [](CallbackType callback, const ResultType& result) (
-//             OtherType other_type = ConvertResultToOtherType(result);
-//             std::move(callback).Run(other_type);
-//         ),
-//         std::move(callback)
-//      );
-//
-// instead of
-//
-//      BindToCurrentSequence(
-//          base::BindOnce(
-//              [](CallbackType callback, const ResultType& result) (
-//                  OtherType other_type = ConvertResultToOtherType(result);
-//                  std::move(callback).Run(other_type);
-//              ),
-//              std::move(callback)
-//          )
-//      );
-//
-template <typename Functor, typename... Args>
-auto BindToCurrentSequence(Functor&& functor, Args&&... args) {
-  auto callback = base::BindOnce(std::forward<Functor>(functor),
-                                 std::forward<Args>(args)...);
-  return BindToCurrentSequence(std::move(callback));
-}
-
-// Binds a repeating callback to the current sequence.
-// This is a convenience version, that allows you to use the same simplified
-// style noted above on a repeating callback.
-template <typename Functor, typename... Args>
-auto BindToCurrentSequenceRepeating(Functor&& functor, Args&&... args) {
-  auto callback = base::BindRepeating(std::forward<Functor>(functor),
-                                      std::forward<Args>(args)...);
-  return BindToCurrentSequenceRepeating(callback);
-}
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_CALLBACK_UTILS_H_
diff --git a/chromeos/ash/services/libassistant/chromium_api_delegate.cc b/chromeos/ash/services/libassistant/chromium_api_delegate.cc
deleted file mode 100644
index 64f6972..0000000
--- a/chromeos/ash/services/libassistant/chromium_api_delegate.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/chromium_api_delegate.h"
-
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-
-namespace ash::libassistant {
-
-ChromiumApiDelegate::ChromiumApiDelegate(
-    std::unique_ptr<network::PendingSharedURLLoaderFactory>
-        pending_url_loader_factory)
-    : http_connection_factory_(std::move(pending_url_loader_factory)) {}
-
-ChromiumApiDelegate::~ChromiumApiDelegate() = default;
-
-assistant_client::HttpConnectionFactory*
-ChromiumApiDelegate::GetHttpConnectionFactory() {
-  return &http_connection_factory_;
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/chromium_api_delegate.h b/chromeos/ash/services/libassistant/chromium_api_delegate.h
deleted file mode 100644
index f2fdfbd..0000000
--- a/chromeos/ash/services/libassistant/chromium_api_delegate.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_CHROMIUM_API_DELEGATE_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_CHROMIUM_API_DELEGATE_H_
-
-#include <memory>
-
-#include "chromeos/ash/services/libassistant/chromium_http_connection.h"
-
-namespace ash::libassistant {
-
-class ChromiumHttpConnectionFactory;
-
-class ChromiumApiDelegate {
- public:
-  explicit ChromiumApiDelegate(
-      std::unique_ptr<network::PendingSharedURLLoaderFactory>
-          pending_url_loader_factory);
-
-  ChromiumApiDelegate(const ChromiumApiDelegate&) = delete;
-  ChromiumApiDelegate& operator=(const ChromiumApiDelegate&) = delete;
-
-  ~ChromiumApiDelegate();
-
-  assistant_client::HttpConnectionFactory* GetHttpConnectionFactory();
-
- private:
-  ChromiumHttpConnectionFactory http_connection_factory_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_CHROMIUM_API_DELEGATE_H_
diff --git a/chromeos/ash/services/libassistant/chromium_http_connection.cc b/chromeos/ash/services/libassistant/chromium_http_connection.cc
deleted file mode 100644
index 5225be1..0000000
--- a/chromeos/ash/services/libassistant/chromium_http_connection.cc
+++ /dev/null
@@ -1,419 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// The file comes from Google Home(cast) implementation.
-
-#include "chromeos/ash/services/libassistant/chromium_http_connection.h"
-
-#include <algorithm>
-#include <memory>
-#include <string_view>
-#include <utility>
-
-#include "base/containers/span.h"
-#include "base/logging.h"
-#include "base/task/thread_pool.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "net/base/load_flags.h"
-#include "services/network/public/cpp/header_util.h"
-#include "services/network/public/cpp/resource_request.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "services/network/public/cpp/simple_url_loader.h"
-#include "services/network/public/mojom/url_response_head.mojom.h"
-
-using assistant_client::HttpConnection;
-using network::PendingSharedURLLoaderFactory;
-using network::SharedURLLoaderFactory;
-
-// A macro which ensures we are running in |task_runner_|'s sequence.
-#define ENSURE_IN_SEQUENCE(method, ...)                                  \
-  if (!task_runner_->RunsTasksInCurrentSequence()) {                     \
-    task_runner_->PostTask(FROM_HERE,                                    \
-                           base::BindOnce(method, this, ##__VA_ARGS__)); \
-    return;                                                              \
-  }
-
-namespace ash::libassistant {
-
-namespace {
-
-// Invalid/Unknown HTTP response code.
-constexpr int kResponseCodeInvalid = -1;
-
-}  // namespace
-
-ChromiumHttpConnection::ChromiumHttpConnection(
-    std::unique_ptr<PendingSharedURLLoaderFactory> pending_url_loader_factory,
-    Delegate* delegate)
-    : delegate_(delegate),
-      task_runner_(base::ThreadPool::CreateSequencedTaskRunner({})),
-      pending_url_loader_factory_(std::move(pending_url_loader_factory)) {
-  DCHECK(delegate_);
-  DCHECK(pending_url_loader_factory_);
-
-  // Add a reference, so |this| cannot go away until Close() is called.
-  AddRef();
-}
-
-ChromiumHttpConnection::~ChromiumHttpConnection() {
-  // The destructor may be called on another sequence when the connection
-  // is cancelled early, for example due to a reconfigure event.
-  DCHECK_EQ(state_, State::DESTROYED);
-}
-
-void ChromiumHttpConnection::SetRequest(const std::string& url, Method method) {
-  ENSURE_IN_SEQUENCE(&ChromiumHttpConnection::SetRequest, url, method);
-  DCHECK_EQ(state_, State::NEW);
-  url_ = GURL(url);
-  method_ = method;
-}
-
-void ChromiumHttpConnection::AddHeader(const std::string& name,
-                                       const std::string& value) {
-  ENSURE_IN_SEQUENCE(&ChromiumHttpConnection::AddHeader, name, value);
-  DCHECK_EQ(state_, State::NEW);
-
-  if (!network::IsRequestHeaderSafe(name, value)) {
-    VLOG(2) << "Ignoring unsafe request header: " << name;
-    return;
-  }
-
-  // From https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2:
-  // "Multiple message-header fields with the same field-name MAY be present in
-  // a message if and only if the entire field-value for that header field is
-  // defined as a comma-separated list [i.e., #(values)]. It MUST be possible to
-  // combine the multiple header fields into one "field-name: field-value" pair,
-  // without changing the semantics of the message, by appending each subsequent
-  // field-value to the first, each separated by a comma."
-  std::optional<std::string> existing_value = headers_.GetHeader(name);
-  if (existing_value) {
-    headers_.SetHeader(name, *existing_value + ',' + value);
-  } else {
-    headers_.SetHeader(name, value);
-  }
-}
-
-void ChromiumHttpConnection::SetUploadContent(const std::string& content,
-                                              const std::string& content_type) {
-  ENSURE_IN_SEQUENCE(&ChromiumHttpConnection::SetUploadContent, content,
-                     content_type);
-  DCHECK_EQ(state_, State::NEW);
-  upload_content_ = content;
-  upload_content_type_ = content_type;
-  chunked_upload_content_type_ = "";
-}
-
-void ChromiumHttpConnection::SetChunkedUploadContentType(
-    const std::string& content_type) {
-  ENSURE_IN_SEQUENCE(&ChromiumHttpConnection::SetChunkedUploadContentType,
-                     content_type);
-  DCHECK_EQ(state_, State::NEW);
-  upload_content_ = "";
-  upload_content_type_ = "";
-  chunked_upload_content_type_ = content_type;
-  AddHeader(::net::HttpRequestHeaders::kContentType, content_type);
-}
-
-void ChromiumHttpConnection::EnableHeaderResponse() {
-  ENSURE_IN_SEQUENCE(&ChromiumHttpConnection::EnableHeaderResponse)
-  enable_header_response_ = true;
-}
-
-void ChromiumHttpConnection::EnablePartialResults() {
-  ENSURE_IN_SEQUENCE(&ChromiumHttpConnection::EnablePartialResults);
-  DCHECK_EQ(state_, State::NEW);
-  handle_partial_response_ = true;
-}
-
-void ChromiumHttpConnection::Start() {
-  ENSURE_IN_SEQUENCE(&ChromiumHttpConnection::Start);
-  DCHECK_EQ(state_, State::NEW);
-  state_ = State::STARTED;
-
-  if (!url_.is_valid()) {
-    state_ = State::COMPLETED;
-    VLOG(2) << "Completing connection with invalid URL";
-    delegate_->OnNetworkError(kResponseCodeInvalid, "Invalid GURL");
-    return;
-  }
-
-  auto resource_request = std::make_unique<network::ResourceRequest>();
-  resource_request->url = url_;
-  resource_request->headers = headers_;
-  switch (method_) {
-    case Method::GET:
-      resource_request->method = "GET";
-      break;
-    case Method::POST:
-      resource_request->method = "POST";
-      break;
-    case Method::HEAD:
-      resource_request->method = "HEAD";
-      break;
-    case Method::PATCH:
-      resource_request->method = "PATCH";
-      break;
-    case Method::PUT:
-      resource_request->method = "PUT";
-      break;
-    case Method::DELETE:
-      resource_request->method = "DELETE";
-      break;
-  }
-  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
-
-  const bool chunked_upload =
-      !chunked_upload_content_type_.empty() && method_ == Method::POST;
-  if (chunked_upload) {
-    // Attach a chunked upload body.
-    mojo::PendingRemote<network::mojom::ChunkedDataPipeGetter> data_remote;
-    receiver_set_.Add(this, data_remote.InitWithNewPipeAndPassReceiver());
-    resource_request->request_body = new network::ResourceRequestBody();
-    resource_request->request_body->SetToChunkedDataPipe(
-        std::move(data_remote),
-        network::ResourceRequestBody::ReadOnlyOnce(false));
-  }
-
-  url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
-                                                 NO_TRAFFIC_ANNOTATION_YET);
-  url_loader_->SetRetryOptions(
-      /*max_retries=*/0, network::SimpleURLLoader::RETRY_NEVER);
-  if (!upload_content_type_.empty())
-    url_loader_->AttachStringForUpload(upload_content_, upload_content_type_);
-
-  auto factory =
-      SharedURLLoaderFactory::Create(std::move(pending_url_loader_factory_));
-
-  if (handle_partial_response_) {
-    url_loader_->SetOnResponseStartedCallback(
-        base::BindOnce(&ChromiumHttpConnection::OnResponseStarted, this));
-    url_loader_->DownloadAsStream(factory.get(), this);
-  } else {
-    url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
-        factory.get(),
-        base::BindOnce(&ChromiumHttpConnection::OnURLLoadComplete, this));
-  }
-}
-
-void ChromiumHttpConnection::Pause() {
-  ENSURE_IN_SEQUENCE(&ChromiumHttpConnection::Pause);
-  is_paused_ = true;
-}
-
-void ChromiumHttpConnection::Resume() {
-  ENSURE_IN_SEQUENCE(&ChromiumHttpConnection::Resume);
-  is_paused_ = false;
-
-  if (!partial_response_cache_.empty()) {
-    delegate_->OnPartialResponse(partial_response_cache_);
-    partial_response_cache_.clear();
-  }
-
-  if (on_resume_callback_)
-    std::move(on_resume_callback_).Run();
-}
-
-void ChromiumHttpConnection::Close() {
-  ENSURE_IN_SEQUENCE(&ChromiumHttpConnection::Close);
-  if (state_ == State::DESTROYED)
-    return;
-
-  state_ = State::DESTROYED;
-  url_loader_.reset();
-
-  delegate_->OnConnectionDestroyed();
-
-  Release();
-}
-
-void ChromiumHttpConnection::UploadData(const std::string& data,
-                                        bool is_last_chunk) {
-  ENSURE_IN_SEQUENCE(&ChromiumHttpConnection::UploadData, data, is_last_chunk);
-  if (state_ != State::STARTED)
-    return;
-
-  upload_body_ += data;
-
-  upload_body_size_ += data.size();
-  if (is_last_chunk) {
-    // Send size before the rest of the body. While it doesn't matter much, if
-    // the other side receives the size before the last chunk, which Mojo does
-    // not guarantee, some protocols can merge the data and the last chunk
-    // itself into a single frame.
-    has_last_chunk_ = is_last_chunk;
-    if (get_size_callback_)
-      std::move(get_size_callback_).Run(net::OK, upload_body_size_);
-  }
-
-  SendData();
-}
-
-void ChromiumHttpConnection::GetSize(GetSizeCallback get_size_callback) {
-  if (has_last_chunk_)
-    std::move(get_size_callback).Run(net::OK, upload_body_size_);
-  else
-    get_size_callback_ = std::move(get_size_callback);
-}
-
-void ChromiumHttpConnection::StartReading(
-    mojo::ScopedDataPipeProducerHandle pipe) {
-  // Delete any existing pipe, if any.
-  upload_pipe_watcher_.reset();
-  upload_pipe_ = std::move(pipe);
-  upload_pipe_watcher_ = std::make_unique<mojo::SimpleWatcher>(
-      FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL);
-  upload_pipe_watcher_->Watch(
-      upload_pipe_.get(), MOJO_HANDLE_SIGNAL_WRITABLE,
-      base::BindRepeating(&ChromiumHttpConnection::OnUploadPipeWriteable,
-                          base::Unretained(this)));
-
-  // Will attempt to start sending the request body, if any data is available.
-  SendData();
-}
-
-void ChromiumHttpConnection::OnDataReceived(std::string_view string_piece,
-                                            base::OnceClosure resume) {
-  DCHECK(handle_partial_response_);
-
-  if (is_paused_) {
-    // If the connection is paused, stop sending |OnPartialResponse|
-    // notification to the delegate and cache the response part.
-    on_resume_callback_ = std::move(resume);
-    DCHECK(partial_response_cache_.empty());
-    partial_response_cache_ = std::string(string_piece);
-  } else {
-    DCHECK(partial_response_cache_.empty());
-    delegate_->OnPartialResponse(std::string(string_piece));
-    std::move(resume).Run();
-  }
-}
-
-void ChromiumHttpConnection::OnComplete(bool success) {
-  DCHECK(handle_partial_response_);
-
-  if (state_ != State::STARTED)
-    return;
-
-  state_ = State::COMPLETED;
-
-  int response_code = kResponseCodeInvalid;
-  std::string raw_headers;
-  if (url_loader_->ResponseInfo() && url_loader_->ResponseInfo()->headers) {
-    raw_headers = url_loader_->ResponseInfo()->headers->raw_headers();
-    response_code = url_loader_->ResponseInfo()->headers->response_code();
-  }
-
-  if (response_code != kResponseCodeInvalid) {
-    delegate_->OnCompleteResponse(response_code, raw_headers, /*response=*/"");
-    return;
-  }
-
-  const std::string message = net::ErrorToString(url_loader_->NetError());
-  VLOG(3) << "ChromiumHttpConnection completed with network error="
-          << url_loader_->NetError() << ": " << message;
-  delegate_->OnNetworkError(url_loader_->NetError(), message);
-}
-
-void ChromiumHttpConnection::OnRetry(base::OnceClosure start_retry) {
-  DCHECK(handle_partial_response_);
-  // Retries are not enabled for these requests.
-  NOTREACHED();
-}
-
-// Attempts to send more of the upload body, if more data is available, and
-// |upload_pipe_| is valid.
-void ChromiumHttpConnection::SendData() {
-  if (!upload_pipe_.is_valid() || upload_body_.empty()) {
-    return;
-  }
-
-  size_t bytes_written = 0;
-  MojoResult result =
-      upload_pipe_->WriteData(base::as_byte_span(upload_body_),
-                              MOJO_WRITE_DATA_FLAG_NONE, bytes_written);
-
-  if (result == MOJO_RESULT_SHOULD_WAIT) {
-    // Wait for the pipe to have more capacity available.
-    upload_pipe_watcher_->ArmOrNotify();
-    return;
-  }
-
-  // Depend on |url_loader_| to notice the other pipes being closed on error.
-  if (result != MOJO_RESULT_OK)
-    return;
-
-  upload_body_.erase(0, bytes_written);
-
-  // If more data is available, arm the watcher again. Don't write again in a
-  // loop, even if WriteData would allow it, to avoid blocking the current
-  // thread.
-  if (!upload_body_.empty()) {
-    upload_pipe_watcher_->ArmOrNotify();
-  }
-}
-
-void ChromiumHttpConnection::OnUploadPipeWriteable(MojoResult unused) {
-  SendData();
-}
-
-void ChromiumHttpConnection::OnURLLoadComplete(
-    std::unique_ptr<std::string> response_body) {
-  DCHECK(!handle_partial_response_);
-
-  if (state_ != State::STARTED)
-    return;
-
-  state_ = State::COMPLETED;
-
-  if (url_loader_->NetError() != net::OK) {
-    delegate_->OnNetworkError(kResponseCodeInvalid,
-                              net::ErrorToString(url_loader_->NetError()));
-    return;
-  }
-
-  int response_code = kResponseCodeInvalid;
-  std::string raw_headers;
-  if (url_loader_->ResponseInfo() && url_loader_->ResponseInfo()->headers) {
-    raw_headers = url_loader_->ResponseInfo()->headers->raw_headers();
-    response_code = url_loader_->ResponseInfo()->headers->response_code();
-  }
-
-  if (response_code == kResponseCodeInvalid) {
-    std::string message = net::ErrorToString(url_loader_->NetError());
-
-    VLOG(3) << "ChromiumHttpConnection completed with network error="
-            << response_code << ": " << message;
-    delegate_->OnNetworkError(response_code, message);
-    return;
-  }
-
-  VLOG(3) << "ChromiumHttpConnection completed with response_code="
-          << response_code;
-
-  delegate_->OnCompleteResponse(response_code, raw_headers, *response_body);
-}
-
-void ChromiumHttpConnection::OnResponseStarted(
-    const GURL& final_url,
-    const network::mojom::URLResponseHead& response_header) {
-  if (enable_header_response_ && response_header.headers) {
-    // Only propagate |OnHeaderResponse()| once before any |OnPartialResponse()|
-    // invoked to honor the API contract.
-    delegate_->OnHeaderResponse(response_header.headers->raw_headers());
-  }
-}
-
-ChromiumHttpConnectionFactory::ChromiumHttpConnectionFactory(
-    std::unique_ptr<PendingSharedURLLoaderFactory> pending_url_loader_factory)
-    : url_loader_factory_(SharedURLLoaderFactory::Create(
-          std::move(pending_url_loader_factory))) {}
-
-ChromiumHttpConnectionFactory::~ChromiumHttpConnectionFactory() = default;
-
-HttpConnection* ChromiumHttpConnectionFactory::Create(
-    HttpConnection::Delegate* delegate) {
-  return new ChromiumHttpConnection(url_loader_factory_->Clone(), delegate);
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/chromium_http_connection.h b/chromeos/ash/services/libassistant/chromium_http_connection.h
deleted file mode 100644
index 4e23048..0000000
--- a/chromeos/ash/services/libassistant/chromium_http_connection.h
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_CHROMIUM_HTTP_CONNECTION_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_CHROMIUM_HTTP_CONNECTION_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <string_view>
-#include <vector>
-
-#include "base/memory/raw_ptr.h"
-#include "base/memory/ref_counted.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
-#include "net/http/http_request_headers.h"
-#include "services/network/public/cpp/simple_url_loader_stream_consumer.h"
-#include "services/network/public/mojom/chunked_data_pipe_getter.mojom.h"
-#include "services/network/public/mojom/url_response_head.mojom-forward.h"
-#include "url/gurl.h"
-
-namespace network {
-class SimpleURLLoader;
-class SharedURLLoaderFactory;
-class PendingSharedURLLoaderFactory;
-}  // namespace network
-
-namespace ash::libassistant {
-
-// Implements libassistant's HttpConnection.
-class ChromiumHttpConnection
-    : public assistant_client::HttpConnection,
-      public network::mojom::ChunkedDataPipeGetter,
-      public network::SimpleURLLoaderStreamConsumer,
-      public base::RefCountedThreadSafe<ChromiumHttpConnection> {
- public:
-  ChromiumHttpConnection(std::unique_ptr<network::PendingSharedURLLoaderFactory>
-                             pending_url_loader_factory,
-                         Delegate* delegate);
-
-  ChromiumHttpConnection(const ChromiumHttpConnection&) = delete;
-  ChromiumHttpConnection& operator=(const ChromiumHttpConnection&) = delete;
-
-  // assistant_client::HttpConnection implementation:
-  void SetRequest(const std::string& url, Method method) override;
-  void AddHeader(const std::string& name, const std::string& value) override;
-  void SetUploadContent(const std::string& content,
-                        const std::string& content_type) override;
-  void SetChunkedUploadContentType(const std::string& content_type) override;
-  void EnableHeaderResponse() override;
-  void EnablePartialResults() override;
-  void Start() override;
-  void Pause() override;
-  void Resume() override;
-  void Close() override;
-  void UploadData(const std::string& data, bool is_last_chunk) override;
-
-  // network::mojom::ChunkedDataPipeGetter implementation:
-  void GetSize(GetSizeCallback get_size_callback) override;
-  void StartReading(mojo::ScopedDataPipeProducerHandle pipe) override;
-
-  // network::SimpleURLLoaderStreamConsumer implementation:
-  void OnDataReceived(std::string_view string_piece,
-                      base::OnceClosure resume) override;
-  void OnComplete(bool success) override;
-  void OnRetry(base::OnceClosure start_retry) override;
-
- protected:
-  ~ChromiumHttpConnection() override;
-
- private:
-  friend class base::RefCountedThreadSafe<ChromiumHttpConnection>;
-
-  enum class State {
-    NEW,
-    STARTED,
-    COMPLETED,
-    DESTROYED,
-  };
-
-  // Send more chunked upload data.
-  void SendData();
-
-  // |upload_pipe_| can now receive more data.
-  void OnUploadPipeWriteable(MojoResult unused);
-
-  // URL loader completion callback.
-  void OnURLLoadComplete(std::unique_ptr<std::string> response_body);
-
-  // Callback invoked when the response of the http connection has started.
-  void OnResponseStarted(
-      const GURL& final_url,
-      const network::mojom::URLResponseHead& response_header);
-
-  const raw_ptr<Delegate> delegate_;
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
-  State state_ = State::NEW;
-  bool has_last_chunk_ = false;
-  uint64_t upload_body_size_ = 0;
-  std::unique_ptr<network::PendingSharedURLLoaderFactory>
-      pending_url_loader_factory_;
-  std::unique_ptr<network::SimpleURLLoader> url_loader_;
-  // The portion of the body not yet uploaded when doing chunked uploads.
-  std::string upload_body_;
-  // Current pipe being used to send the |upload_body_| to |url_loader_|.
-  mojo::ScopedDataPipeProducerHandle upload_pipe_;
-  // Watches |upload_pipe_| for writeability.
-  std::unique_ptr<mojo::SimpleWatcher> upload_pipe_watcher_;
-  // If non-null, invoked once the size of the upload is known.
-  network::mojom::ChunkedDataPipeGetter::GetSizeCallback get_size_callback_;
-  mojo::ReceiverSet<network::mojom::ChunkedDataPipeGetter> receiver_set_;
-
-  // Parameters to be set before Start() call.
-  GURL url_;
-  Method method_ = Method::GET;
-  ::net::HttpRequestHeaders headers_;
-  std::string upload_content_;
-  std::string upload_content_type_;
-  std::string chunked_upload_content_type_;
-  bool handle_partial_response_ = false;
-  bool enable_header_response_ = false;
-
-  // Set to true if the response transfer of the connection is paused.
-  bool is_paused_ = false;
-
-  base::OnceClosure on_resume_callback_;
-  std::string partial_response_cache_;
-};
-
-class ChromiumHttpConnectionFactory
-    : public assistant_client::HttpConnectionFactory {
- public:
-  explicit ChromiumHttpConnectionFactory(
-      std::unique_ptr<network::PendingSharedURLLoaderFactory>
-          pending_url_loader_factory);
-
-  ChromiumHttpConnectionFactory(const ChromiumHttpConnectionFactory&) = delete;
-  ChromiumHttpConnectionFactory& operator=(
-      const ChromiumHttpConnectionFactory&) = delete;
-
-  ~ChromiumHttpConnectionFactory() override;
-
-  // assistant_client::HttpConnectionFactory implementation:
-  assistant_client::HttpConnection* Create(
-      assistant_client::HttpConnection::Delegate* delegate) override;
-
- private:
-  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_CHROMIUM_HTTP_CONNECTION_H_
diff --git a/chromeos/ash/services/libassistant/constants.cc b/chromeos/ash/services/libassistant/constants.cc
deleted file mode 100644
index 739ae3b..0000000
--- a/chromeos/ash/services/libassistant/constants.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/constants.h"
-
-#include "base/files/file_util.h"
-#include "build/chromeos_buildflags.h"
-
-#define ASSISTANT_DIR_STRING "google-assistant-library"
-#define ASSISTANT_SOCKETS_STRING "sockets"
-#define ASSISTANT_TEMP_DIR "/tmp/libassistant/"
-#define LIBASSISTANT_DLC_DIR "opt/google/chrome/"
-#define LIBASSISTANT_V2_NAME "libassistant_v2.so"
-
-namespace ash::libassistant {
-
-#if BUILDFLAG(IS_CHROMEOS_DEVICE)
-const base::FilePath::CharType kAssistantBaseDirPath[] =
-    FILE_PATH_LITERAL("/home/chronos/user/" ASSISTANT_DIR_STRING);
-
-const base::FilePath::CharType kLibAssistantSocketPath[] =
-    FILE_PATH_LITERAL("/run/libassistant");
-
-const char kLibAssistantDlcRootPath[] =
-    "/run/imageloader/assistant-dlc/package/root";
-
-const base::FilePath::CharType kLibAssistantV2DlcPath[] =
-    FILE_PATH_LITERAL(LIBASSISTANT_DLC_DIR LIBASSISTANT_V2_NAME);
-#else
-// Directory and files used in gLinux simulation.
-const base::FilePath::CharType kAssistantBaseDirPath[] =
-    FILE_PATH_LITERAL(ASSISTANT_TEMP_DIR ASSISTANT_DIR_STRING);
-
-const base::FilePath::CharType kLibAssistantSocketPath[] =
-    FILE_PATH_LITERAL(ASSISTANT_TEMP_DIR ASSISTANT_SOCKETS_STRING);
-
-const char kLibAssistantDlcRootPath[] = "";
-
-const base::FilePath::CharType kLibAssistantV2DlcPath[] =
-    FILE_PATH_LITERAL(LIBASSISTANT_V2_NAME);
-#endif
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/constants.h b/chromeos/ash/services/libassistant/constants.h
deleted file mode 100644
index 3d770f6..0000000
--- a/chromeos/ash/services/libassistant/constants.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_CONSTANTS_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_CONSTANTS_H_
-
-#include "base/component_export.h"
-#include "base/files/file_path.h"
-
-namespace ash::libassistant {
-
-// A directory to save Assistant config files.
-COMPONENT_EXPORT(LIBASSISTANT_CONSTANTS)
-extern const base::FilePath::CharType kAssistantBaseDirPath[];
-
-// Libassistant library DLC root path.
-COMPONENT_EXPORT(LIBASSISTANT_CONSTANTS)
-extern const char kLibAssistantDlcRootPath[];
-
-// Libassistant v2 library DLC path.
-COMPONENT_EXPORT(LIBASSISTANT_CONSTANTS)
-extern const base::FilePath::CharType kLibAssistantV2DlcPath[];
-
-// A directory to save Libassistant socket files.
-COMPONENT_EXPORT(LIBASSISTANT_CONSTANTS)
-extern const base::FilePath::CharType kLibAssistantSocketPath[];
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_CONSTANTS_H_
diff --git a/chromeos/ash/services/libassistant/conversation_controller.cc b/chromeos/ash/services/libassistant/conversation_controller.cc
deleted file mode 100644
index 7d425ebc..0000000
--- a/chromeos/ash/services/libassistant/conversation_controller.cc
+++ /dev/null
@@ -1,537 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/conversation_controller.h"
-
-#include <memory>
-
-#include "base/memory/raw_ref.h"
-#include "base/sequence_checker.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/thread_annotations.h"
-#include "chromeos/ash/services/assistant/public/cpp/features.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client.h"
-#include "chromeos/ash/services/libassistant/public/mojom/conversation_controller.mojom.h"
-#include "chromeos/ash/services/libassistant/util.h"
-#include "chromeos/assistant/internal/internal_util.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/proto/shared/proto/conversation.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/internal_options.pb.h"
-#include "chromeos/strings/grit/chromeos_strings.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace ash::libassistant {
-
-using assistant::AssistantInteractionMetadata;
-using assistant::AssistantInteractionType;
-using assistant::AssistantQuerySource;
-
-namespace {
-
-constexpr base::TimeDelta kStopInteractionDelayTime = base::Milliseconds(500);
-
-// A macro which ensures we are running on the main thread.
-#define ENSURE_MOJOM_THREAD(method, ...)                                    \
-  DVLOG(3) << __func__;                                                     \
-  if (!mojom_task_runner_->RunsTasksInCurrentSequence()) {                  \
-    mojom_task_runner_->PostTask(                                           \
-        FROM_HERE,                                                          \
-        base::BindOnce(method, weak_factory_.GetWeakPtr(), ##__VA_ARGS__)); \
-    return;                                                                 \
-  }
-
-// Helper function to convert |action::Suggestion| to |AssistantSuggestion|.
-std::vector<assistant::AssistantSuggestion> ToAssistantSuggestion(
-    const std::vector<chromeos::assistant::action::Suggestion>& suggestions) {
-  std::vector<assistant::AssistantSuggestion> result;
-  for (const auto& suggestion : suggestions) {
-    assistant::AssistantSuggestion assistant_suggestion;
-    assistant_suggestion.id = base::UnguessableToken::Create();
-    assistant_suggestion.text = suggestion.text;
-    assistant_suggestion.icon_url = GURL(suggestion.icon_url);
-    assistant_suggestion.action_url = GURL(suggestion.action_url);
-    result.push_back(std::move(assistant_suggestion));
-  }
-
-  return result;
-}
-
-// Helper function to convert |action::Notification| to |AssistantNotification|.
-assistant::AssistantNotification ToAssistantNotification(
-    const chromeos::assistant::action::Notification& notification) {
-  assistant::AssistantNotification assistant_notification;
-  assistant_notification.title = notification.title;
-  assistant_notification.message = notification.text;
-  assistant_notification.action_url = GURL(notification.action_url);
-  assistant_notification.client_id = notification.notification_id;
-  assistant_notification.server_id = notification.notification_id;
-  assistant_notification.consistency_token = notification.consistency_token;
-  assistant_notification.opaque_token = notification.opaque_token;
-  assistant_notification.grouping_key = notification.grouping_key;
-  assistant_notification.obfuscated_gaia_id = notification.obfuscated_gaia_id;
-  assistant_notification.from_server = true;
-
-  if (notification.expiry_timestamp_ms) {
-    assistant_notification.expiry_time =
-        base::Time::FromMillisecondsSinceUnixEpoch(
-            notification.expiry_timestamp_ms);
-  }
-
-  // The server sometimes sends an empty |notification_id|, but our client
-  // requires a non-empty |client_id| for notifications. Known instances in
-  // which the server sends an empty |notification_id| are for Reminders.
-  if (assistant_notification.client_id.empty()) {
-    assistant_notification.client_id =
-        base::UnguessableToken::Create().ToString();
-  }
-
-  for (const auto& button : notification.buttons) {
-    assistant_notification.buttons.push_back(
-        {button.label, GURL(button.action_url),
-         /*remove_notification_on_click=*/true});
-  }
-  return assistant_notification;
-}
-}  // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// GrpcEventsObserver
-////////////////////////////////////////////////////////////////////////////////
-
-class ConversationController::GrpcEventsObserver
-    : public GrpcServicesObserver<
-          ::assistant::api::OnConversationStateEventRequest>,
-      public GrpcServicesObserver<::assistant::api::OnDeviceStateEventRequest> {
- public:
-  explicit GrpcEventsObserver(ConversationController* parent)
-      : parent_(*parent) {}
-  GrpcEventsObserver(const GrpcEventsObserver&) = delete;
-  GrpcEventsObserver& operator=(const GrpcEventsObserver&) = delete;
-  ~GrpcEventsObserver() override = default;
-
-  std::string AddPendingTextInteraction(const std::string& query,
-                                        AssistantQuerySource source) {
-    return NewPendingInteraction(AssistantInteractionType::kText, source,
-                                 query);
-  }
-
-  // GrpcServicesObserver:
-  // Invoked when a conversation state event has been received.
-  void OnGrpcMessage(const ::assistant::api::OnConversationStateEventRequest&
-                         request) override {
-    if (!request.event().has_on_turn_started())
-      return;
-
-    const auto& turn_started = request.event().on_turn_started();
-    // Retrieve the cached interaction metadata associated with this
-    // conversation turn or construct a new instance if there's no match in the
-    // cache.
-    AssistantInteractionMetadata interaction_metadata;
-    auto it = pending_interactions_.find(turn_started.turn_id());
-    if (it != pending_interactions_.end()) {
-      interaction_metadata = it->second;
-      pending_interactions_.erase(it);
-    } else {
-      interaction_metadata.type = turn_started.is_mic_open()
-                                      ? AssistantInteractionType::kVoice
-                                      : AssistantInteractionType::kText;
-      interaction_metadata.source =
-          AssistantQuerySource::kLibAssistantInitiated;
-    }
-
-    for (auto& observer : parent_->observers_) {
-      observer->OnInteractionStarted(interaction_metadata);
-    }
-  }
-
-  // Invoked when a device state event has been received.
-  void OnGrpcMessage(
-      const ::assistant::api::OnDeviceStateEventRequest& request) override {
-    const auto& event = request.event();
-    if (event.has_on_notification_removed()) {
-      const auto& grouping_id =
-          request.event().on_notification_removed().grouping_id();
-      if (grouping_id.empty())
-        RemoveAllNotifications();
-      else
-        RemoveNotification(grouping_id);
-      return;
-    }
-
-    if (event.has_on_communication_error()) {
-      if (event.on_communication_error().error_code() ==
-          ::assistant::api::events::DeviceStateEvent::OnCommunicationError::
-              AUTH_TOKEN_FAIL) {
-        for (auto& observer : parent_->authentication_state_observers_) {
-          observer->OnAuthenticationError();
-        }
-      }
-    }
-  }
-
- private:
-  void RemoveAllNotifications() {
-    parent_->notification_delegate_->RemoveAllNotifications(
-        /*from_server=*/true);
-  }
-
-  void RemoveNotification(const std::string& id) {
-    parent_->notification_delegate_->RemoveNotificationByGroupingKey(
-        id, /*from_server=*/true);
-  }
-
-  std::string NewPendingInteraction(AssistantInteractionType interaction_type,
-                                    AssistantQuerySource source,
-                                    const std::string& query) {
-    auto id = base::NumberToString(next_interaction_id_++);
-    pending_interactions_.emplace(
-        id, AssistantInteractionMetadata(interaction_type, source, query));
-    return id;
-  }
-
-  int next_interaction_id_ = 1;
-  std::map<std::string, AssistantInteractionMetadata> pending_interactions_;
-  const raw_ref<ConversationController> parent_;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// ConversationController
-////////////////////////////////////////////////////////////////////////////////
-
-ConversationController::ConversationController()
-    : receiver_(this),
-      events_observer_(std::make_unique<GrpcEventsObserver>(this)),
-      action_module_(
-          std::make_unique<chromeos::assistant::action::CrosActionModule>(
-              assistant::features::IsAppSupportEnabled(),
-              /* wait_enabled */ true)),
-      mojom_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {
-  action_module_->AddObserver(this);
-}
-
-ConversationController::~ConversationController() = default;
-
-void ConversationController::Bind(
-    mojo::PendingReceiver<mojom::ConversationController> receiver,
-    mojo::PendingRemote<mojom::NotificationDelegate> notification_delegate) {
-  // Cannot bind the receiver twice.
-  DCHECK(!receiver_.is_bound());
-  receiver_.Bind(std::move(receiver));
-
-  // Binds remote notification delegate.
-  notification_delegate_.Bind(std::move(notification_delegate));
-}
-
-void ConversationController::AddActionObserver(
-    chromeos::assistant::action::AssistantActionObserver* observer) {
-  action_module_->AddObserver(observer);
-}
-
-void ConversationController::AddAuthenticationStateObserver(
-    mojo::PendingRemote<mojom::AuthenticationStateObserver> observer) {
-  authentication_state_observers_.Add(std::move(observer));
-}
-
-void ConversationController::OnAssistantClientRunning(
-    AssistantClient* assistant_client) {
-  // Only when Libassistant is running we can start sending queries.
-  assistant_client_ = assistant_client;
-  requests_are_allowed_ = true;
-
-  // Register the action module when all libassistant services are ready.
-  // `action_module_` outlives gRPC services.
-  assistant_client->RegisterActionModule(action_module_.get());
-
-  assistant_client_->AddConversationStateEventObserver(events_observer_.get());
-  assistant_client_->AddDeviceStateEventObserver(events_observer_.get());
-}
-
-void ConversationController::OnDestroyingAssistantClient(
-    AssistantClient* assistant_client) {
-  assistant_client_ = nullptr;
-}
-
-void ConversationController::SendTextQuery(const std::string& query,
-                                           AssistantQuerySource source,
-                                           bool allow_tts) {
-  DVLOG(1) << __func__;
-
-  DCHECK(requests_are_allowed_)
-      << "Should not receive requests before Libassistant is running";
-  if (!assistant_client_)
-    return;
-
-  MaybeStopPreviousInteraction();
-
-  // Configs |VoicelessOptions|.
-  ::assistant::api::VoicelessOptions options;
-  options.set_is_user_initiated(true);
-  if (!allow_tts) {
-    options.set_modality(::assistant::api::VoicelessOptions::TYPING_MODALITY);
-  }
-  // Remember the interaction metadata, and pass the generated conversation id
-  // to LibAssistant.
-  options.set_conversation_turn_id(
-      events_observer_->AddPendingTextInteraction(query, source));
-
-  // Builds text interaction.
-  auto interaction = CreateTextQueryInteraction(query);
-
-  assistant_client_->SendVoicelessInteraction(
-      interaction, /*description=*/"text_query", options, base::DoNothing());
-}
-
-void ConversationController::StartVoiceInteraction() {
-  DVLOG(1) << __func__;
-
-  DCHECK(requests_are_allowed_)
-      << "Should not receive requests before Libassistant is running";
-  if (!assistant_client_) {
-    VLOG(1) << "Starting voice interaction without assistant manager.";
-    return;
-  }
-
-  MaybeStopPreviousInteraction();
-
-  assistant_client_->StartVoiceInteraction();
-}
-
-void ConversationController::StartEditReminderInteraction(
-    const std::string& client_id) {
-  DCHECK(requests_are_allowed_)
-      << "Should not receive requests before Libassistant is running";
-  if (!assistant_client_)
-    return;
-
-  // Cancels any ongoing StopInteraction posted by StopActiveInteraction()
-  // before we move forward to start an EditReminderInteraction. Failing to
-  // do this could expose a race condition and potentially result in the
-  // following EditReminderInteraction getting barged in and cancelled.
-  // See b/182948180.
-  MaybeStopPreviousInteraction();
-
-  ::assistant::api::VoicelessOptions options;
-  options.set_is_user_initiated(true);
-
-  assistant_client_->SendVoicelessInteraction(
-      CreateEditReminderInteraction(client_id),
-      /*description=*/std::string(), options, base::DoNothing());
-}
-
-void ConversationController::StopActiveInteraction(bool cancel_conversation) {
-  if (!assistant_client_) {
-    VLOG(1) << "Stopping interaction without assistant manager.";
-    return;
-  }
-
-  // We do not stop the interaction immediately, but instead we give
-  // Libassistant a bit of time to stop on its own accord. This improves
-  // stability as Libassistant might misbehave when it's forcefully stopped.
-  auto stop_callback = [](base::WeakPtr<ConversationController> weak_this,
-                          bool cancel_conversation) {
-    if (!weak_this || !weak_this->assistant_client_) {
-      return;
-    }
-    VLOG(1) << "Stopping Assistant interaction.";
-    weak_this->assistant_client_->StopAssistantInteraction(cancel_conversation);
-  };
-
-  stop_interaction_closure_ =
-      std::make_unique<base::CancelableOnceClosure>(base::BindOnce(
-          stop_callback, weak_factory_.GetWeakPtr(), cancel_conversation));
-
-  mojom_task_runner_->PostDelayedTask(FROM_HERE,
-                                      stop_interaction_closure_->callback(),
-                                      kStopInteractionDelayTime);
-}
-
-void ConversationController::RetrieveNotification(
-    AssistantNotification notification,
-    int32_t action_index) {
-  DCHECK(requests_are_allowed_)
-      << "Should not receive requests before Libassistant is running";
-  if (!assistant_client_)
-    return;
-
-  auto request_interaction = CreateNotificationRequestInteraction(
-      notification.server_id, notification.consistency_token,
-      notification.opaque_token, action_index);
-
-  ::assistant::api::VoicelessOptions options;
-  options.set_is_user_initiated(true);
-
-  assistant_client_->SendVoicelessInteraction(
-      request_interaction,
-      /*description=*/"RequestNotification", options, base::DoNothing());
-}
-
-void ConversationController::DismissNotification(
-    AssistantNotification notification) {
-  DCHECK(requests_are_allowed_)
-      << "Should not receive requests before Libassistant is running";
-  if (!assistant_client_)
-    return;
-
-  auto dismissed_interaction = CreateNotificationDismissedInteraction(
-      notification.server_id, notification.consistency_token,
-      notification.opaque_token, {notification.grouping_key});
-
-  ::assistant::api::VoicelessOptions options;
-  options.set_obfuscated_gaia_id(notification.obfuscated_gaia_id);
-
-  assistant_client_->SendVoicelessInteraction(
-      dismissed_interaction, /*description=*/"DismissNotification", options,
-      base::DoNothing());
-}
-
-void ConversationController::SendAssistantFeedback(
-    const AssistantFeedback& feedback) {
-  DCHECK(requests_are_allowed_)
-      << "Should not receive requests before Libassistant is running";
-  if (!assistant_client_)
-    return;
-
-  std::string raw_image_data(feedback.screenshot_png.begin(),
-                             feedback.screenshot_png.end());
-  auto interaction =
-      CreateSendFeedbackInteraction(feedback.assistant_debug_info_allowed,
-                                    feedback.description, raw_image_data);
-
-  ::assistant::api::VoicelessOptions options;
-  options.set_is_user_initiated(false);
-
-  assistant_client_->SendVoicelessInteraction(
-      interaction, /*description=*/"send feedback with details", options,
-      base::DoNothing());
-}
-
-void ConversationController::AddRemoteObserver(
-    mojo::PendingRemote<mojom::ConversationObserver> observer) {
-  observers_.Add(std::move(observer));
-}
-
-// Called from Libassistant thread.
-void ConversationController::OnShowHtml(const std::string& html_content,
-                                        const std::string& fallback) {
-  ENSURE_MOJOM_THREAD(&ConversationController::OnShowHtml, html_content,
-                      fallback);
-
-  for (auto& observer : observers_)
-    observer->OnHtmlResponse(html_content, fallback);
-}
-
-// Called from Libassistant thread.
-void ConversationController::OnShowText(const std::string& text) {
-  ENSURE_MOJOM_THREAD(&ConversationController::OnShowText, text);
-
-  for (auto& observer : observers_)
-    observer->OnTextResponse(text);
-}
-
-// Called from Libassistant thread.
-void ConversationController::OnShowSuggestions(
-    const std::vector<chromeos::assistant::action::Suggestion>& suggestions) {
-  ENSURE_MOJOM_THREAD(&ConversationController::OnShowSuggestions, suggestions);
-
-  for (auto& observer : observers_)
-    observer->OnSuggestionsResponse(ToAssistantSuggestion(suggestions));
-}
-
-// Called from Libassistant thread.
-void ConversationController::OnOpenUrl(const std::string& url,
-                                       bool in_background) {
-  ENSURE_MOJOM_THREAD(&ConversationController::OnOpenUrl, url, in_background);
-
-  for (auto& observer : observers_)
-    observer->OnOpenUrlResponse(GURL(url), in_background);
-}
-
-// Called from Libassistant thread.
-// Note that OnVerifyAndroidApp() will be handled by |DisplayController|
-// directly since it stores an updated list of all installed Android Apps on the
-// device.
-void ConversationController::OnOpenAndroidApp(
-    const assistant::AndroidAppInfo& app_info,
-    const chromeos::assistant::InteractionInfo& interaction) {
-  ENSURE_MOJOM_THREAD(&ConversationController::OnOpenAndroidApp, app_info,
-                      interaction);
-
-  for (auto& observer : observers_)
-    observer->OnOpenAppResponse(app_info);
-
-  // Note that we will always set |provider_found| to true since the preceding
-  // OnVerifyAndroidApp() should already confirm that the requested provider is
-  // available on the device.
-  auto interaction_proto = CreateOpenProviderResponseInteraction(
-      interaction.interaction_id, /*provider_found=*/true);
-  ::assistant::api::VoicelessOptions options;
-  options.set_obfuscated_gaia_id(interaction.user_id);
-
-  assistant_client_->SendVoicelessInteraction(
-      interaction_proto, /*description=*/"open_provider_response", options,
-      base::DoNothing());
-}
-
-// Called from Libassistant thread.
-void ConversationController::OnScheduleWait(int id, int time_ms) {
-  ENSURE_MOJOM_THREAD(&ConversationController::OnScheduleWait, id, time_ms);
-
-  // Schedule a wait for |time_ms|, notifying the CrosActionModule when the wait
-  // has finished so that it can inform LibAssistant to resume execution.
-  mojom_task_runner_->PostDelayedTask(
-      FROM_HERE,
-      base::BindOnce(
-          [](const base::WeakPtr<ConversationController>& weak_ptr, int id) {
-            if (weak_ptr) {
-              weak_ptr->action_module_->OnScheduledWaitDone(
-                  id, /*cancelled=*/false);
-            }
-          },
-          weak_factory_.GetWeakPtr(), id),
-      base::Milliseconds(time_ms));
-
-  // Notify subscribers that a wait has been started.
-  for (auto& observer : observers_)
-    observer->OnWaitStarted();
-}
-
-// Called from Libassistant thread.
-void ConversationController::OnShowNotification(
-    const chromeos::assistant::action::Notification& notification) {
-  ENSURE_MOJOM_THREAD(&ConversationController::OnShowNotification,
-                      notification);
-
-  notification_delegate_->AddOrUpdateNotification(
-      ToAssistantNotification(notification));
-}
-
-void ConversationController::OnInteractionStarted(
-    const AssistantInteractionMetadata& metadata) {
-  stop_interaction_closure_.reset();
-}
-
-void ConversationController::OnInteractionFinished(
-    assistant::AssistantInteractionResolution resolution) {
-  stop_interaction_closure_.reset();
-}
-
-void ConversationController::OnGrpcMessageForTesting(
-    const ::assistant::api::OnDeviceStateEventRequest& request) {
-  events_observer_->OnGrpcMessage(request);
-}
-
-void ConversationController::MaybeStopPreviousInteraction() {
-  DVLOG(1) << __func__;
-
-  if (!stop_interaction_closure_ || stop_interaction_closure_->IsCancelled()) {
-    return;
-  }
-
-  stop_interaction_closure_->callback().Run();
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/conversation_controller.h b/chromeos/ash/services/libassistant/conversation_controller.h
deleted file mode 100644
index 9768555a..0000000
--- a/chromeos/ash/services/libassistant/conversation_controller.h
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_CONVERSATION_CONTROLLER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_CONVERSATION_CONTROLLER_H_
-
-#include <memory>
-
-#include "base/cancelable_callback.h"
-#include "base/component_export.h"
-#include "base/memory/raw_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/assistant/public/cpp/conversation_observer.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client_observer.h"
-#include "chromeos/ash/services/libassistant/public/cpp/assistant_notification.h"
-#include "chromeos/ash/services/libassistant/public/mojom/authentication_state_observer.mojom.h"
-#include "chromeos/ash/services/libassistant/public/mojom/conversation_controller.mojom.h"
-#include "chromeos/ash/services/libassistant/public/mojom/notification_delegate.mojom.h"
-#include "chromeos/assistant/internal/action/assistant_action_observer.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_interface.pb.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote_set.h"
-
-namespace chromeos::assistant::action {
-class CrosActionModule;
-}
-
-namespace ash {
-
-class AssistantClient;
-
-namespace libassistant {
-
-class COMPONENT_EXPORT(LIBASSISTANT_SERVICE) ConversationController
-    : public mojom::ConversationController,
-      public AssistantClientObserver,
-      public chromeos::assistant::action::AssistantActionObserver,
-      public assistant::ConversationObserver {
- public:
-  using AssistantNotification = assistant::AssistantNotification;
-  using AssistantQuerySource = assistant::AssistantQuerySource;
-  using AssistantFeedback = assistant::AssistantFeedback;
-
-  ConversationController();
-  ConversationController(const ConversationController&) = delete;
-  ConversationController& operator=(const ConversationController&) = delete;
-  ~ConversationController() override;
-
-  void Bind(
-      mojo::PendingReceiver<mojom::ConversationController> receiver,
-      mojo::PendingRemote<mojom::NotificationDelegate> notification_delegate);
-
-  void AddActionObserver(
-      chromeos::assistant::action::AssistantActionObserver* observer);
-  void AddAuthenticationStateObserver(
-      mojo::PendingRemote<mojom::AuthenticationStateObserver> observer);
-
-  // AssistantClientObserver:
-  void OnAssistantClientRunning(AssistantClient* assistant_client) override;
-  void OnDestroyingAssistantClient(AssistantClient* assistant_client) override;
-
-  // mojom::ConversationController implementation:
-  void SendTextQuery(const std::string& query,
-                     AssistantQuerySource source,
-                     bool allow_tts) override;
-  void StartVoiceInteraction() override;
-  void StartEditReminderInteraction(const std::string& client_id) override;
-  void StopActiveInteraction(bool cancel_conversation) override;
-  void RetrieveNotification(AssistantNotification notification,
-                            int32_t action_index) override;
-  void DismissNotification(AssistantNotification notification) override;
-  void SendAssistantFeedback(const AssistantFeedback& feedback) override;
-  void AddRemoteObserver(
-      mojo::PendingRemote<mojom::ConversationObserver> observer) override;
-
-  // chromeos::assistant::action::AssistantActionObserver:
-  void OnShowHtml(const std::string& html_content,
-                  const std::string& fallback) override;
-  void OnShowText(const std::string& text) override;
-  void OnShowSuggestions(
-      const std::vector<chromeos::assistant::action::Suggestion>& suggestions)
-      override;
-  void OnOpenUrl(const std::string& url, bool in_background) override;
-  void OnOpenAndroidApp(
-      const assistant::AndroidAppInfo& app_info,
-      const chromeos::assistant::InteractionInfo& interaction) override;
-  void OnScheduleWait(int id, int time_ms) override;
-  void OnShowNotification(
-      const chromeos::assistant::action::Notification& notification) override;
-
-  // assistant::ConversationObserver:
-  void OnInteractionStarted(
-      const assistant::AssistantInteractionMetadata& metadata) override;
-  void OnInteractionFinished(
-      assistant::AssistantInteractionResolution resolution) override;
-
-  const mojo::RemoteSet<mojom::ConversationObserver>* conversation_observers() {
-    return &observers_;
-  }
-
-  chromeos::assistant::action::CrosActionModule* action_module() {
-    return action_module_.get();
-  }
-
-  void OnGrpcMessageForTesting(
-      const ::assistant::api::OnDeviceStateEventRequest& request);
-
- private:
-  class GrpcEventsObserver;
-
-  void MaybeStopPreviousInteraction();
-
-  mojo::Receiver<mojom::ConversationController> receiver_;
-  mojo::RemoteSet<mojom::ConversationObserver> observers_;
-  mojo::RemoteSet<mojom::AuthenticationStateObserver>
-      authentication_state_observers_;
-  mojo::Remote<mojom::NotificationDelegate> notification_delegate_;
-
-  // Owned by ServiceController.
-  // Set in `OnAssistantClientCreated()` and unset in
-  // `OnDestroyingAssistantClient()`.
-  raw_ptr<AssistantClient> assistant_client_ = nullptr;
-
-  // False until libassistant is running for the first time.
-  // Any request that comes in before that is an error and will be DCHECK'ed.
-  bool requests_are_allowed_ = false;
-
-  std::unique_ptr<GrpcEventsObserver> events_observer_;
-  std::unique_ptr<chromeos::assistant::action::CrosActionModule> action_module_;
-
-  std::unique_ptr<base::CancelableOnceClosure> stop_interaction_closure_;
-  base::TimeDelta stop_interaction_delay_ = base::Milliseconds(500);
-
-  scoped_refptr<base::SequencedTaskRunner> mojom_task_runner_;
-  base::WeakPtrFactory<ConversationController> weak_factory_{this};
-};
-
-}  // namespace libassistant
-}  // namespace ash
-
-#endif  //  CHROMEOS_ASH_SERVICES_LIBASSISTANT_CONVERSATION_CONTROLLER_H_
diff --git a/chromeos/ash/services/libassistant/conversation_controller_unittest.cc b/chromeos/ash/services/libassistant/conversation_controller_unittest.cc
deleted file mode 100644
index 6f51178..0000000
--- a/chromeos/ash/services/libassistant/conversation_controller_unittest.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/conversation_controller.h"
-#include "base/run_loop.h"
-#include "base/test/task_environment.h"
-#include "chromeos/ash/components/assistant/test_support/expect_utils.h"
-#include "chromeos/ash/services/libassistant/test_support/fake_assistant_client.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-class AssistantClientMock : public FakeAssistantClient {
- public:
-  AssistantClientMock(std::unique_ptr<chromeos::assistant::FakeAssistantManager>
-                          assistant_manager)
-      : FakeAssistantClient(std::move(assistant_manager)) {}
-  ~AssistantClientMock() override = default;
-
-  // AssistantClient:
-  MOCK_METHOD(void, StartVoiceInteraction, ());
-  MOCK_METHOD(void, StopAssistantInteraction, (bool cancel_conversation));
-  MOCK_METHOD(void,
-              SendVoicelessInteraction,
-              (const ::assistant::api::Interaction& interaction,
-               const std::string& description,
-               const ::assistant::api::VoicelessOptions& options,
-               base::OnceCallback<void(bool)> on_done));
-};
-
-}  // namespace
-
-class ConversationControllerTest : public ::testing::Test {
- public:
-  ConversationControllerTest() = default;
-  ConversationControllerTest(const ConversationControllerTest&) = delete;
-  ConversationControllerTest& operator=(const ConversationControllerTest&) =
-      delete;
-  ~ConversationControllerTest() override = default;
-
-  void StartLibassistant() {
-    controller_.OnAssistantClientRunning(&assistant_client_);
-  }
-
-  ConversationController& controller() { return controller_; }
-
-  AssistantClientMock& assistant_client_mock() { return assistant_client_; }
-
- private:
-  base::test::SingleThreadTaskEnvironment environment_;
-  ConversationController controller_;
-  AssistantClientMock assistant_client_{nullptr};
-};
-
-TEST_F(ConversationControllerTest, ShouldStartVoiceInteraction) {
-  StartLibassistant();
-
-  EXPECT_CALL(assistant_client_mock(), StartVoiceInteraction());
-
-  controller().StartVoiceInteraction();
-}
-
-TEST_F(ConversationControllerTest, ShouldStopInteractionAfterDelay) {
-  StartLibassistant();
-
-  EXPECT_CALL(assistant_client_mock(), StopAssistantInteraction).Times(0);
-
-  controller().StopActiveInteraction(true);
-  testing::Mock::VerifyAndClearExpectations(&assistant_client_mock());
-
-  WAIT_FOR_CALL(assistant_client_mock(), StopAssistantInteraction);
-}
-
-TEST_F(ConversationControllerTest,
-       ShouldStopInteractionImmediatelyBeforeNewVoiceInteraction) {
-  StartLibassistant();
-
-  EXPECT_CALL(assistant_client_mock(), StopAssistantInteraction).Times(0);
-
-  controller().StopActiveInteraction(true);
-  testing::Mock::VerifyAndClearExpectations(&assistant_client_mock());
-
-  ::testing::Expectation stop =
-      EXPECT_CALL(assistant_client_mock(), StopAssistantInteraction).Times(1);
-  EXPECT_CALL(assistant_client_mock(), StartVoiceInteraction)
-      .Times(1)
-      .After(stop);
-  controller().StartVoiceInteraction();
-}
-
-TEST_F(ConversationControllerTest,
-       ShouldStopInteractionImmediatelyBeforeNewEditReminderInteraction) {
-  StartLibassistant();
-
-  EXPECT_CALL(assistant_client_mock(), StopAssistantInteraction).Times(0);
-
-  controller().StopActiveInteraction(true);
-  testing::Mock::VerifyAndClearExpectations(&assistant_client_mock());
-
-  ::testing::Expectation stop =
-      EXPECT_CALL(assistant_client_mock(), StopAssistantInteraction).Times(1);
-  EXPECT_CALL(assistant_client_mock(), SendVoicelessInteraction)
-      .Times(1)
-      .After(stop);
-  controller().StartEditReminderInteraction("client-id");
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/conversation_observer_unittest.cc b/chromeos/ash/services/libassistant/conversation_observer_unittest.cc
deleted file mode 100644
index f1e7a32..0000000
--- a/chromeos/ash/services/libassistant/conversation_observer_unittest.cc
+++ /dev/null
@@ -1,271 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <memory>
-
-#include "base/memory/raw_ref.h"
-#include "base/test/task_environment.h"
-#include "chromeos/ash/services/libassistant/conversation_controller.h"
-#include "chromeos/ash/services/libassistant/libassistant_service.h"
-#include "chromeos/ash/services/libassistant/public/cpp/android_app_info.h"
-#include "chromeos/ash/services/libassistant/public/mojom/conversation_observer.mojom.h"
-#include "chromeos/ash/services/libassistant/test_support/libassistant_service_tester.h"
-#include "chromeos/assistant/internal/action/cros_action_module.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/test_support/fake_assistant_manager.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-// Helper class to fire interaction response handlers for tests.
-class CrosActionModuleHelper {
- public:
-  explicit CrosActionModuleHelper(
-      chromeos::assistant::action::CrosActionModule* action_module)
-      : action_module_(*action_module) {}
-  CrosActionModuleHelper(const CrosActionModuleHelper&) = delete;
-  CrosActionModuleHelper& operator=(const CrosActionModuleHelper&) = delete;
-  ~CrosActionModuleHelper() = default;
-
-  void ShowHtml(const std::string& html) {
-    for (auto* observer : action_observers())
-      observer->OnShowHtml(html, /*fallback=*/"");
-  }
-
-  void ShowText(const std::string& text) {
-    for (auto* observer : action_observers())
-      observer->OnShowText(text);
-  }
-
-  void ShowSuggestions(
-      const std::vector<chromeos::assistant::action::Suggestion>& suggestions) {
-    for (auto* observer : action_observers())
-      observer->OnShowSuggestions(suggestions);
-  }
-
-  void OpenUrl(const std::string& url, bool in_background) {
-    for (auto* observer : action_observers())
-      observer->OnOpenUrl(url, in_background);
-  }
-
-  void OpenAndroidApp(const assistant::AndroidAppInfo& app_info) {
-    chromeos::assistant::InteractionInfo info{};
-    for (auto* observer : action_observers())
-      observer->OnOpenAndroidApp(app_info, info);
-  }
-
-  void ScheduleWait() {
-    for (auto* observer : action_observers())
-      observer->OnScheduleWait(/*id=*/012, /*time_ms=*/123);
-  }
-
- private:
-  const std::vector<chromeos::assistant::action::AssistantActionObserver*>&
-  action_observers() {
-    return action_module_->GetActionObserversForTesting();
-  }
-
-  const raw_ref<const chromeos::assistant::action::CrosActionModule>
-      action_module_;
-};
-
-class ConversationObserverMock : public mojom::ConversationObserver {
- public:
-  ConversationObserverMock() = default;
-  ConversationObserverMock(const ConversationObserverMock&) = delete;
-  ConversationObserverMock& operator=(const ConversationObserverMock&) = delete;
-  ~ConversationObserverMock() override = default;
-
-  // mojom::ConversationObserver implementation:
-  MOCK_METHOD(void,
-              OnInteractionStarted,
-              (const ::ash::assistant::AssistantInteractionMetadata& metadata));
-  MOCK_METHOD(void,
-              OnInteractionFinished,
-              (assistant::AssistantInteractionResolution resolution));
-  MOCK_METHOD(void, OnTtsStarted, (bool due_to_error));
-  MOCK_METHOD(void,
-              OnHtmlResponse,
-              (const std::string& response, const std::string& fallback));
-  MOCK_METHOD(void, OnTextResponse, (const std::string& text));
-  MOCK_METHOD(void,
-              OnSuggestionsResponse,
-              (const std::vector<assistant::AssistantSuggestion>& suggestions));
-  MOCK_METHOD(void, OnOpenUrlResponse, (const GURL& url, bool in_background));
-  MOCK_METHOD(void,
-              OnOpenAppResponse,
-              (const assistant::AndroidAppInfo& app_info));
-  MOCK_METHOD(void, OnWaitStarted, ());
-
-  mojo::PendingRemote<mojom::ConversationObserver> BindNewPipeAndPassRemote() {
-    return receiver_.BindNewPipeAndPassRemote();
-  }
-
-  void FlushForTesting() { receiver_.FlushForTesting(); }
-
- private:
-  mojo::Receiver<mojom::ConversationObserver> receiver_{this};
-};
-
-}  // namespace
-
-class AssistantConversationObserverTest : public ::testing::Test {
- public:
-  AssistantConversationObserverTest() = default;
-  AssistantConversationObserverTest(const AssistantConversationObserverTest&) =
-      delete;
-  AssistantConversationObserverTest& operator=(
-      const AssistantConversationObserverTest&) = delete;
-  ~AssistantConversationObserverTest() override = default;
-
-  void SetUp() override {
-    service_tester_.conversation_controller().AddRemoteObserver(
-        observer_mock_.BindNewPipeAndPassRemote());
-
-    service_tester_.Start();
-
-    controller().OnAssistantClientRunning(&service_tester_.assistant_client());
-
-    action_module_helper_ = std::make_unique<CrosActionModuleHelper>(
-        static_cast<chromeos::assistant::action::CrosActionModule*>(
-            controller().action_module()));
-  }
-
-  assistant_client::ConversationStateListener& conversation_state_listener() {
-    return *service_tester_.assistant_manager().conversation_state_listener();
-  }
-
-  CrosActionModuleHelper& action_module_helper() {
-    return *action_module_helper_.get();
-  }
-
-  ConversationObserverMock& observer_mock() { return observer_mock_; }
-
-  ConversationController& controller() {
-    return service_tester_.service().conversation_controller();
-  }
-
- private:
-  base::test::SingleThreadTaskEnvironment environment_;
-  ::testing::StrictMock<ConversationObserverMock> observer_mock_;
-  LibassistantServiceTester service_tester_;
-  std::unique_ptr<CrosActionModuleHelper> action_module_helper_;
-};
-
-TEST_F(AssistantConversationObserverTest,
-       ShouldReceiveOnTurnFinishedEventWhenFinishedNormally) {
-  EXPECT_CALL(observer_mock(),
-              OnInteractionFinished(
-                  assistant::AssistantInteractionResolution::kNormal));
-
-  conversation_state_listener().OnConversationTurnFinished(
-      assistant_client::ConversationStateListener::Resolution::NORMAL);
-  observer_mock().FlushForTesting();
-}
-
-TEST_F(AssistantConversationObserverTest,
-       ShouldReceiveOnTurnFinishedEventWhenBeingInterrupted) {
-  EXPECT_CALL(observer_mock(),
-              OnInteractionFinished(
-                  assistant::AssistantInteractionResolution::kInterruption));
-
-  conversation_state_listener().OnConversationTurnFinished(
-      assistant_client::ConversationStateListener::Resolution::BARGE_IN);
-  observer_mock().FlushForTesting();
-}
-
-TEST_F(AssistantConversationObserverTest,
-       ShouldReceiveOnTtsStartedEventWhenFinishingNormally) {
-  EXPECT_CALL(observer_mock(), OnTtsStarted(/*due_to_error=*/false));
-
-  conversation_state_listener().OnRespondingStarted(false);
-  observer_mock().FlushForTesting();
-}
-
-TEST_F(AssistantConversationObserverTest,
-       ShouldReceiveOnTtsStartedEventWhenErrorOccured) {
-  EXPECT_CALL(observer_mock(), OnTtsStarted(/*due_to_error=*/true));
-
-  conversation_state_listener().OnRespondingStarted(true);
-  observer_mock().FlushForTesting();
-}
-
-TEST_F(AssistantConversationObserverTest, ShouldReceiveOnHtmlResponse) {
-  const std::string fake_html = "<h1>Hello world!</h1>";
-  EXPECT_CALL(observer_mock(), OnHtmlResponse(fake_html, ""));
-
-  // Fallback is always empty since it has been deprecated.
-  action_module_helper().ShowHtml(/*html=*/fake_html);
-  observer_mock().FlushForTesting();
-}
-
-TEST_F(AssistantConversationObserverTest, ShouldReceiveOnTextResponse) {
-  const std::string fake_text = "I'm a text response";
-  EXPECT_CALL(observer_mock(), OnTextResponse(fake_text));
-
-  action_module_helper().ShowText(fake_text);
-  observer_mock().FlushForTesting();
-}
-
-TEST_F(AssistantConversationObserverTest, ShouldReceiveOnSuggestionsResponse) {
-  const std::string fake_text = "text";
-  const std::string fake_icon_url = "https://icon-url/";
-  const std::string fake_action_url = "https://action-url/";
-  std::vector<chromeos::assistant::action::Suggestion> fake_suggestions{
-      {fake_text, fake_icon_url, fake_action_url}};
-
-  EXPECT_CALL(observer_mock(), OnSuggestionsResponse)
-      .WillOnce(testing::Invoke(
-          [&](const std::vector<assistant::AssistantSuggestion>& suggestions) {
-            EXPECT_EQ(fake_text, suggestions[0].text);
-            EXPECT_EQ(GURL(fake_icon_url), suggestions[0].icon_url);
-            EXPECT_EQ(GURL(fake_action_url), suggestions[0].action_url);
-          }));
-
-  action_module_helper().ShowSuggestions(fake_suggestions);
-  observer_mock().FlushForTesting();
-}
-
-TEST_F(AssistantConversationObserverTest, ShouldReceiveOnOpenUrlResponse) {
-  const std::string fake_url = "https://fake-url/";
-  EXPECT_CALL(observer_mock(),
-              OnOpenUrlResponse(GURL(fake_url), /*in_background=*/false));
-
-  action_module_helper().OpenUrl(fake_url, /*in_background=*/false);
-  observer_mock().FlushForTesting();
-}
-
-TEST_F(AssistantConversationObserverTest, ShouldReceiveOnOpenAppResponse) {
-  assistant::AndroidAppInfo fake_app_info;
-  fake_app_info.package_name = "fake package name";
-  fake_app_info.version = 123;
-  fake_app_info.localized_app_name = "fake localized name";
-  fake_app_info.action = "fake action";
-  fake_app_info.intent = "fake intent";
-  fake_app_info.status = assistant::AppStatus::kUnknown;
-
-  EXPECT_CALL(observer_mock(), OnOpenAppResponse)
-      .WillOnce(testing::Invoke([&](const assistant::AndroidAppInfo& app_info) {
-        EXPECT_EQ("fake package name", app_info.package_name);
-        EXPECT_EQ(123, app_info.version);
-        EXPECT_EQ("fake localized name", app_info.localized_app_name);
-        EXPECT_EQ("fake action", app_info.action);
-        EXPECT_EQ(assistant::AppStatus::kUnknown, app_info.status);
-      }));
-
-  action_module_helper().OpenAndroidApp(fake_app_info);
-  observer_mock().FlushForTesting();
-}
-
-TEST_F(AssistantConversationObserverTest, ShouldReceiveOnWaitStarted) {
-  EXPECT_CALL(observer_mock(), OnWaitStarted());
-
-  action_module_helper().ScheduleWait();
-  observer_mock().FlushForTesting();
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/conversation_state_listener_impl.cc b/chromeos/ash/services/libassistant/conversation_state_listener_impl.cc
deleted file mode 100644
index 5bbb515..0000000
--- a/chromeos/ash/services/libassistant/conversation_state_listener_impl.cc
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/conversation_state_listener_impl.h"
-
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/assistant/public/cpp/assistant_enums.h"
-#include "chromeos/ash/services/libassistant/audio_input_controller.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client.h"
-#include "chromeos/ash/services/libassistant/public/mojom/conversation_observer.mojom.h"
-#include "chromeos/ash/services/libassistant/public/mojom/speech_recognition_observer.mojom.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-// A macro which ensures we are running on the mojom thread.
-#define ENSURE_MOJOM_THREAD(method, ...)                                    \
-  if (!mojom_task_runner_->RunsTasksInCurrentSequence()) {                  \
-    mojom_task_runner_->PostTask(                                           \
-        FROM_HERE,                                                          \
-        base::BindOnce(method, weak_factory_.GetWeakPtr(), ##__VA_ARGS__)); \
-    return;                                                                 \
-  }
-
-}  // namespace
-
-ConversationStateListenerImpl::ConversationStateListenerImpl(
-    mojo::RemoteSet<mojom::SpeechRecognitionObserver>*
-        speech_recognition_observers,
-    const mojo::RemoteSet<mojom::ConversationObserver>* conversation_observers,
-    AudioInputController* audio_input_controller)
-    : speech_recognition_observers_(*speech_recognition_observers),
-      conversation_observers_(*conversation_observers),
-      audio_input_controller_(audio_input_controller),
-      mojom_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {
-  DCHECK(speech_recognition_observers);
-  DCHECK(conversation_observers);
-  DCHECK(audio_input_controller);
-}
-
-ConversationStateListenerImpl::~ConversationStateListenerImpl() = default;
-
-void ConversationStateListenerImpl::OnAssistantClientCreated(
-    AssistantClient* assistant_client) {
-  assistant_client->assistant_manager()->AddConversationStateListener(this);
-}
-
-void ConversationStateListenerImpl::OnRecognitionStateChanged(
-    RecognitionState state,
-    const RecognitionResult& recognition_result) {
-  ENSURE_MOJOM_THREAD(&ConversationStateListenerImpl::OnRecognitionStateChanged,
-                      state, recognition_result);
-
-  switch (state) {
-    case RecognitionState::STARTED:
-      for (auto& observer : *speech_recognition_observers_) {
-        observer->OnSpeechRecognitionStart();
-      }
-      break;
-    case RecognitionState::INTERMEDIATE_RESULT:
-      for (auto& observer : *speech_recognition_observers_) {
-        observer->OnIntermediateResult(recognition_result.high_confidence_text,
-                                       recognition_result.low_confidence_text);
-      }
-      break;
-    case RecognitionState::END_OF_UTTERANCE:
-      for (auto& observer : *speech_recognition_observers_) {
-        observer->OnSpeechRecognitionEnd();
-      }
-      break;
-    case RecognitionState::FINAL_RESULT:
-      for (auto& observer : *speech_recognition_observers_) {
-        observer->OnFinalResult(recognition_result.recognized_speech);
-      }
-      break;
-  }
-}
-
-void ConversationStateListenerImpl::OnConversationTurnFinished(
-    assistant_client::ConversationStateListener::Resolution resolution) {
-  ENSURE_MOJOM_THREAD(
-      &ConversationStateListenerImpl::OnConversationTurnFinished, resolution);
-
-  // TODO(b/179924068): refactor |AudioInputController| to be a normal
-  // |mojom::ConversationObserver| once we figured out a better approach to
-  // handle those edge cases.
-  audio_input_controller_->OnInteractionFinished(resolution);
-
-  switch (resolution) {
-    // Interaction ended normally.
-    case Resolution::NORMAL:
-    case Resolution::NORMAL_WITH_FOLLOW_ON:
-    case Resolution::NO_RESPONSE:
-      NotifyInteractionFinished(
-          assistant::AssistantInteractionResolution::kNormal);
-      return;
-    // Interaction ended due to interruption.
-    case Resolution::BARGE_IN:
-    case Resolution::CANCELLED:
-      NotifyInteractionFinished(
-          assistant::AssistantInteractionResolution::kInterruption);
-      return;
-    // Interaction ended due to mic timeout.
-    case Resolution::TIMEOUT:
-      NotifyInteractionFinished(
-          assistant::AssistantInteractionResolution::kMicTimeout);
-      return;
-    // Interaction ended due to error.
-    case Resolution::COMMUNICATION_ERROR:
-      NotifyInteractionFinished(
-          assistant::AssistantInteractionResolution::kError);
-      return;
-    // Interaction ended because the device was not selected to produce a
-    // response. This occurs due to multi-device hotword loss.
-    case Resolution::DEVICE_NOT_SELECTED:
-      NotifyInteractionFinished(
-          assistant::AssistantInteractionResolution::kMultiDeviceHotwordLoss);
-      return;
-    // This is only applicable in longform barge-in mode, which we do not use.
-    case Resolution::LONGFORM_KEEP_MIC_OPEN:
-    case Resolution::BLUE_STEEL_ON_DEVICE_REJECTION:
-      NOTREACHED();
-  }
-}
-
-void ConversationStateListenerImpl::OnRespondingStarted(
-    bool is_error_response) {
-  ENSURE_MOJOM_THREAD(&ConversationStateListenerImpl::OnRespondingStarted,
-                      is_error_response);
-
-  for (auto& observer : *conversation_observers_) {
-    observer->OnTtsStarted(is_error_response);
-  }
-}
-
-void ConversationStateListenerImpl::NotifyInteractionFinished(
-    assistant::AssistantInteractionResolution resolution) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  for (auto& observer : *conversation_observers_) {
-    observer->OnInteractionFinished(resolution);
-  }
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/conversation_state_listener_impl.h b/chromeos/ash/services/libassistant/conversation_state_listener_impl.h
deleted file mode 100644
index 71d5ec4..0000000
--- a/chromeos/ash/services/libassistant/conversation_state_listener_impl.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_CONVERSATION_STATE_LISTENER_IMPL_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_CONVERSATION_STATE_LISTENER_IMPL_H_
-
-#include "base/memory/raw_ptr.h"
-#include "base/memory/raw_ref.h"
-#include "base/sequence_checker.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client_observer.h"
-#include "chromeos/ash/services/libassistant/public/mojom/display_controller.mojom.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote_set.h"
-
-namespace ash::libassistant {
-
-namespace mojom {
-class ConversationObserver;
-class SpeechRecognitionObserver;
-}  // namespace mojom
-
-class AudioInputController;
-
-class ConversationStateListenerImpl
-    : public assistant_client::ConversationStateListener,
-      public AssistantClientObserver {
- public:
-  ConversationStateListenerImpl(
-      mojo::RemoteSet<mojom::SpeechRecognitionObserver>*
-          speech_recognition_observers,
-      const mojo::RemoteSet<mojom::ConversationObserver>*
-          conversation_observers,
-      AudioInputController* audio_input_controller);
-  ConversationStateListenerImpl(const ConversationStateListenerImpl&) = delete;
-  ConversationStateListenerImpl& operator=(
-      const ConversationStateListenerImpl&) = delete;
-  ~ConversationStateListenerImpl() override;
-
- private:
-  // AssistantClientObserver implementation:
-  void OnAssistantClientCreated(AssistantClient* assistant_client) override;
-
-  // assistant_client::ConversationStateListener implementation:
-  void OnRecognitionStateChanged(
-      RecognitionState state,
-      const RecognitionResult& recognition_result) override;
-  void OnConversationTurnFinished(
-      assistant_client::ConversationStateListener::Resolution resolution)
-      override;
-  void OnRespondingStarted(bool is_error_response) override;
-
-  void NotifyInteractionFinished(
-      assistant::AssistantInteractionResolution resolution);
-
-  // Owned by |LibassistantService|.
-  const raw_ref<mojo::RemoteSet<mojom::SpeechRecognitionObserver>>
-      speech_recognition_observers_;
-
-  // Owned by |ConversationController|.
-  const raw_ref<const mojo::RemoteSet<mojom::ConversationObserver>>
-      conversation_observers_;
-
-  const raw_ptr<AudioInputController> audio_input_controller_ = nullptr;
-
-  // The callbacks from Libassistant are called on a different sequence,
-  // so this sequence checker ensures that no other methods are called on the
-  // libassistant sequence.
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  scoped_refptr<base::SequencedTaskRunner> mojom_task_runner_;
-  base::WeakPtrFactory<ConversationStateListenerImpl> weak_factory_{this};
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_CONVERSATION_STATE_LISTENER_IMPL_H_
diff --git a/chromeos/ash/services/libassistant/device_settings_controller.cc b/chromeos/ash/services/libassistant/device_settings_controller.cc
deleted file mode 100644
index 9aac40f..0000000
--- a/chromeos/ash/services/libassistant/device_settings_controller.cc
+++ /dev/null
@@ -1,360 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/device_settings_controller.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/containers/contains.h"
-#include "base/logging.h"
-#include "base/memory/raw_ref.h"
-#include "base/memory/weak_ptr.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client.h"
-#include "chromeos/ash/services/libassistant/public/mojom/device_settings_delegate.mojom.h"
-#include "chromeos/ash/services/libassistant/util.h"
-#include "chromeos/assistant/internal/internal_util.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/proto/shared/proto/conversation.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/device_args.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/internal_options.pb.h"
-
-namespace client_op = ::assistant::api::client_op;
-
-namespace ash::libassistant {
-
-using mojom::DeviceSettingsDelegate;
-using mojom::GetBrightnessResultPtr;
-
-namespace {
-// A macro which ensures we are running on the main thread.
-#define ENSURE_MOJOM_THREAD(method, ...)                                    \
-  if (!mojom_task_runner_->RunsTasksInCurrentSequence()) {                  \
-    mojom_task_runner_->PostTask(                                           \
-        FROM_HERE,                                                          \
-        base::BindOnce(method, weak_factory_.GetWeakPtr(), ##__VA_ARGS__)); \
-    return;                                                                 \
-  }
-}  // namespace
-
-class Setting {
- public:
-  explicit Setting(DeviceSettingsDelegate* delegate) : delegate_(*delegate) {}
-  Setting(Setting&) = delete;
-  Setting& operator=(Setting&) = delete;
-  virtual ~Setting() = default;
-
-  virtual const char* setting_id() const = 0;
-  virtual void Modify(const client_op::ModifySettingArgs& request) = 0;
-
-  DeviceSettingsDelegate& delegate() { return *delegate_; }
-
- private:
-  const raw_ref<DeviceSettingsDelegate> delegate_;
-};
-
-namespace {
-
-constexpr char kWiFiDeviceSettingId[] = "WIFI";
-constexpr char kBluetoothDeviceSettingId[] = "BLUETOOTH";
-constexpr char kScreenBrightnessDeviceSettingId[] = "BRIGHTNESS_LEVEL";
-constexpr char kDoNotDisturbDeviceSettingId[] = "DO_NOT_DISTURB";
-constexpr char kNightLightDeviceSettingId[] = "NIGHT_LIGHT_SWITCH";
-constexpr char kSwitchAccessDeviceSettingId[] = "SWITCH_ACCESS";
-
-constexpr float kDefaultSliderStep = 0.1f;
-
-void LogUnsupportedChange(client_op::ModifySettingArgs args) {
-  LOG(ERROR) << "Unsupported change operation: " << args.change()
-             << " for setting " << args.setting_id();
-}
-
-void HandleOnOffChange(client_op::ModifySettingArgs modify_setting_args,
-                       std::function<void(bool)> on_off_handler) {
-  switch (modify_setting_args.change()) {
-    case client_op::ModifySettingArgs_Change_ON:
-      on_off_handler(true);
-      return;
-    case client_op::ModifySettingArgs_Change_OFF:
-      on_off_handler(false);
-      return;
-
-    // Currently there are no use-cases for toggling.  This could change in the
-    // future.
-    case client_op::ModifySettingArgs_Change_TOGGLE:
-      break;
-
-    case client_op::ModifySettingArgs_Change_SET:
-    case client_op::ModifySettingArgs_Change_INCREASE:
-    case client_op::ModifySettingArgs_Change_DECREASE:
-    case client_op::ModifySettingArgs_Change_UNSPECIFIED:
-      // This shouldn't happen.
-      break;
-  }
-  LogUnsupportedChange(modify_setting_args);
-}
-
-// Helper function that converts a slider value sent from the server, either
-// absolute or a delta, from a given unit (e.g., STEP), to a percentage.
-double ConvertSliderValueToLevel(double value,
-                                 client_op::ModifySettingArgs_Unit unit,
-                                 double default_value) {
-  switch (unit) {
-    case client_op::ModifySettingArgs_Unit_RANGE:
-      // "set brightness to 20%".
-      return value;
-    case client_op::ModifySettingArgs_Unit_STEP:
-      // "set brightness to 20".  Treat the step as a percentage.
-      return value / 100.0f;
-
-    // Currently, factor (e.g., 'double the brightness') and decibel units
-    // aren't handled by the backend.  This could change in the future.
-    case client_op::ModifySettingArgs_Unit_FACTOR:
-    case client_op::ModifySettingArgs_Unit_DECIBEL:
-      break;
-
-    case client_op::ModifySettingArgs_Unit_NATIVE:
-    case client_op::ModifySettingArgs_Unit_UNKNOWN_UNIT:
-      // This shouldn't happen.
-      break;
-  }
-  LOG(ERROR) << "Unsupported slider unit: " << unit;
-  return default_value;
-}
-
-void HandleSliderChange(client_op::ModifySettingArgs request,
-                        std::function<void(double)> set_value_handler,
-                        std::function<double()> get_value_handler) {
-  switch (request.change()) {
-    case client_op::ModifySettingArgs_Change_SET: {
-      // For unsupported units, set the value to the current value, for
-      // visual feedback.
-      double new_value = ConvertSliderValueToLevel(
-          request.numeric_value(), request.unit(), get_value_handler());
-      set_value_handler(new_value);
-      return;
-    }
-
-    case client_op::ModifySettingArgs_Change_INCREASE:
-    case client_op::ModifySettingArgs_Change_DECREASE: {
-      double current_value = get_value_handler();
-      double step = kDefaultSliderStep;
-      if (request.numeric_value() != 0.0f) {
-        // For unsupported units, use the default step percentage.
-        step = ConvertSliderValueToLevel(request.numeric_value(),
-                                         request.unit(), kDefaultSliderStep);
-      }
-      double new_value =
-          (request.change() == client_op::ModifySettingArgs_Change_INCREASE)
-              ? std::min(current_value + step, 1.0)
-              : std::max(current_value - step, 0.0);
-      set_value_handler(new_value);
-      return;
-    }
-
-    case client_op::ModifySettingArgs_Change_ON:
-    case client_op::ModifySettingArgs_Change_OFF:
-    case client_op::ModifySettingArgs_Change_TOGGLE:
-    case client_op::ModifySettingArgs_Change_UNSPECIFIED:
-      // This shouldn't happen.
-      break;
-  }
-  LogUnsupportedChange(request);
-}
-
-class WifiSetting : public Setting {
- public:
-  using Setting::Setting;
-
-  const char* setting_id() const override { return kWiFiDeviceSettingId; }
-
-  void Modify(const client_op::ModifySettingArgs& request) override {
-    HandleOnOffChange(
-        request, [&](bool enabled) { delegate().SetWifiEnabled(enabled); });
-  }
-};
-
-class BluetoothSetting : public Setting {
- public:
-  using Setting::Setting;
-
-  const char* setting_id() const override { return kBluetoothDeviceSettingId; }
-
-  void Modify(const client_op::ModifySettingArgs& request) override {
-    HandleOnOffChange(request, [&](bool enabled) {
-      VLOG(1) << "Assistant: Setting bluetooth enabled: " << enabled;
-      delegate().SetBluetoothEnabled(enabled);
-    });
-  }
-};
-
-class DoNotDisturbSetting : public Setting {
- public:
-  using Setting::Setting;
-
-  const char* setting_id() const override {
-    return kDoNotDisturbDeviceSettingId;
-  }
-
-  void Modify(const client_op::ModifySettingArgs& request) override {
-    HandleOnOffChange(request, [&](bool enabled) {
-      VLOG(1) << "Assistant: Setting do not disturb enabled: " << enabled;
-      delegate().SetDoNotDisturbEnabled(enabled);
-    });
-  }
-};
-
-class SwitchAccessSetting : public Setting {
- public:
-  using Setting::Setting;
-
-  const char* setting_id() const override {
-    return kSwitchAccessDeviceSettingId;
-  }
-
-  void Modify(const client_op::ModifySettingArgs& request) override {
-    HandleOnOffChange(request, [&](bool enabled) {
-      VLOG(1) << "Assistant: Setting switch access enabled: " << enabled;
-      delegate().SetSwitchAccessEnabled(enabled);
-    });
-  }
-};
-
-class NightLightSetting : public Setting {
- public:
-  using Setting::Setting;
-
-  const char* setting_id() const override { return kNightLightDeviceSettingId; }
-
-  void Modify(const client_op::ModifySettingArgs& request) override {
-    HandleOnOffChange(request, [&](bool enabled) {
-      VLOG(1) << "Assistant: Setting night light enabled: " << enabled;
-      delegate().SetNightLightEnabled(enabled);
-    });
-  }
-};
-
-class BrightnessSetting : public Setting {
- public:
-  explicit BrightnessSetting(DeviceSettingsDelegate* delegate)
-      : Setting(delegate), weak_factory_(this) {}
-
-  const char* setting_id() const override {
-    return kScreenBrightnessDeviceSettingId;
-  }
-
-  void Modify(const client_op::ModifySettingArgs& request) override {
-    delegate().GetScreenBrightnessLevel(base::BindOnce(
-        [](base::WeakPtr<BrightnessSetting> this_,
-           client_op::ModifySettingArgs request,
-           GetBrightnessResultPtr result) {
-          if (!result || !this_) {
-            LOG(WARNING) << "Failed to get brightness level";
-            return;
-          }
-          HandleSliderChange(
-              request,
-              [&this_](double new_value) {
-                VLOG(1) << "Assistant: Setting brightness to " << new_value
-                        << " percent";
-                this_->delegate().SetScreenBrightnessLevel(new_value, true);
-              },
-              [current_value = result->level]() { return current_value; });
-        },
-        weak_factory_.GetWeakPtr(), request));
-  }
-
- private:
-  base::WeakPtrFactory<BrightnessSetting> weak_factory_;
-};
-
-}  // namespace
-
-DeviceSettingsController::DeviceSettingsController()
-    : mojom_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {}
-DeviceSettingsController::~DeviceSettingsController() = default;
-
-void DeviceSettingsController::Bind(
-    mojo::PendingRemote<mojom::DeviceSettingsDelegate> remote) {
-  remote_.Bind(std::move(remote));
-
-  AddSetting(std::make_unique<WifiSetting>(remote_.get()));
-  AddSetting(std::make_unique<BluetoothSetting>(remote_.get()));
-  AddSetting(std::make_unique<NightLightSetting>(remote_.get()));
-  AddSetting(std::make_unique<DoNotDisturbSetting>(remote_.get()));
-  AddSetting(std::make_unique<BrightnessSetting>(remote_.get()));
-  AddSetting(std::make_unique<SwitchAccessSetting>(remote_.get()));
-}
-
-void DeviceSettingsController::OnModifyDeviceSetting(
-    const client_op::ModifySettingArgs& modify_setting_args) {
-  ENSURE_MOJOM_THREAD(&DeviceSettingsController::OnModifyDeviceSetting,
-                      modify_setting_args);
-  VLOG(1) << "Assistant: Modifying Device Setting '"
-          << modify_setting_args.setting_id() << "'";
-  DCHECK(IsSettingSupported(modify_setting_args.setting_id()));
-
-  for (const auto& setting : settings_) {
-    if (setting->setting_id() == modify_setting_args.setting_id()) {
-      setting->Modify(modify_setting_args);
-      return;
-    }
-  }
-
-  NOTREACHED();
-}
-
-void DeviceSettingsController::OnGetDeviceSettings(
-    int interaction_id,
-    const ::assistant::api::client_op::GetDeviceSettingsArgs& args) {
-  if (!assistant_client_) {
-    VLOG(1) << "Assistant: Dropping OnGetDeviceSettings call as Libassistant "
-               "has not started yet";
-    return;
-  }
-
-  std::vector<chromeos::assistant::DeviceSetting> result =
-      GetSupportedDeviceSettings(args);
-
-  auto interaction_proto = ash::libassistant::CreateGetDeviceSettingInteraction(
-      interaction_id, result);
-
-  ::assistant::api::VoicelessOptions options;
-  options.set_is_user_initiated(true);
-
-  assistant_client_->SendVoicelessInteraction(
-      interaction_proto, /*description=*/"get_settings_result", options,
-      base::DoNothing());
-}
-
-void DeviceSettingsController::OnAssistantClientCreated(
-    AssistantClient* assistant_client) {
-  assistant_client_ = assistant_client;
-}
-
-void DeviceSettingsController::OnDestroyingAssistantClient(
-    AssistantClient* assistant_client) {
-  assistant_client_ = nullptr;
-}
-
-std::vector<chromeos::assistant::DeviceSetting>
-DeviceSettingsController::GetSupportedDeviceSettings(
-    const ::assistant::api::client_op::GetDeviceSettingsArgs& args) const {
-  std::vector<chromeos::assistant::DeviceSetting> result;
-  for (const std::string& setting_id : args.setting_ids())
-    result.emplace_back(setting_id, IsSettingSupported(setting_id));
-  return result;
-}
-
-bool DeviceSettingsController::IsSettingSupported(
-    const std::string& setting_id) const {
-  return base::Contains(settings_, setting_id, &Setting::setting_id);
-}
-
-void DeviceSettingsController::AddSetting(std::unique_ptr<Setting> setting) {
-  settings_.push_back(std::move(setting));
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/device_settings_controller.h b/chromeos/ash/services/libassistant/device_settings_controller.h
deleted file mode 100644
index 2a2ed3f..0000000
--- a/chromeos/ash/services/libassistant/device_settings_controller.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_DEVICE_SETTINGS_CONTROLLER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_DEVICE_SETTINGS_CONTROLLER_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/component_export.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client_observer.h"
-#include "chromeos/ash/services/libassistant/public/mojom/device_settings_delegate.mojom.h"
-#include "chromeos/assistant/internal/action/assistant_action_observer.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/remote.h"
-
-namespace assistant {
-namespace api {
-namespace client_op {
-class ModifySettingArgs;
-class GetDeviceSettingsArgs;
-}  // namespace client_op
-}  // namespace api
-}  // namespace assistant
-
-namespace chromeos {
-namespace assistant {
-struct DeviceSetting;
-}  // namespace assistant
-}  // namespace chromeos
-
-namespace ash::libassistant {
-
-class AssistantClient;
-class Setting;
-
-class DeviceSettingsController
-    : public AssistantClientObserver,
-      public chromeos::assistant::action::AssistantActionObserver {
- public:
-  DeviceSettingsController();
-  DeviceSettingsController(DeviceSettingsController&) = delete;
-  DeviceSettingsController& operator=(DeviceSettingsController&) = delete;
-  ~DeviceSettingsController() override;
-
-  void Bind(mojo::PendingRemote<mojom::DeviceSettingsDelegate> delegate);
-
-  // chromeos::assistant::action::AssistantActionObserver implementation:
-  void OnModifyDeviceSetting(
-      const ::assistant::api::client_op::ModifySettingArgs& setting) override;
-  void OnGetDeviceSettings(
-      int interaction_id,
-      const ::assistant::api::client_op::GetDeviceSettingsArgs& setting)
-      override;
-
-  // AssistantClientObserver implementation:
-  void OnAssistantClientCreated(AssistantClient* assistant_client) override;
-  void OnDestroyingAssistantClient(AssistantClient* assistant_client) override;
-
-  // Returns which of the given device settings are supported or not.
-  std::vector<chromeos::assistant::DeviceSetting> GetSupportedDeviceSettings(
-      const ::assistant::api::client_op::GetDeviceSettingsArgs& args) const;
-
- private:
-  bool IsSettingSupported(const std::string& setting_id) const;
-
-  void AddSetting(std::unique_ptr<Setting> setting);
-
-  std::vector<std::unique_ptr<Setting>> settings_;
-  raw_ptr<AssistantClient> assistant_client_ = nullptr;
-  mojo::Remote<mojom::DeviceSettingsDelegate> remote_;
-  scoped_refptr<base::SequencedTaskRunner> mojom_task_runner_;
-  base::WeakPtrFactory<DeviceSettingsController> weak_factory_{this};
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_DEVICE_SETTINGS_CONTROLLER_H_
diff --git a/chromeos/ash/services/libassistant/device_settings_controller_unittest.cc b/chromeos/ash/services/libassistant/device_settings_controller_unittest.cc
deleted file mode 100644
index e1280ac9..0000000
--- a/chromeos/ash/services/libassistant/device_settings_controller_unittest.cc
+++ /dev/null
@@ -1,281 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/device_settings_controller.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/command_line.h"
-#include "base/run_loop.h"
-#include "base/test/task_environment.h"
-#include "chromeos/ash/services/libassistant/public/mojom/device_settings_delegate.mojom.h"
-#include "chromeos/assistant/internal/internal_util.h"
-#include "chromeos/assistant/internal/proto/shared/proto/device_args.pb.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace chromeos {
-namespace assistant {
-
-bool operator==(const DeviceSetting& left, const DeviceSetting& right) {
-  return (left.is_supported == right.is_supported) &&
-         (left.setting_id == right.setting_id);
-}
-
-void PrintTo(const DeviceSetting& settings, std::ostream* out) {
-  *out << "DeviceSettings {" << std::endl;
-  *out << "    setting_id: " << settings.setting_id << std::endl;
-  *out << "    is_supported: " << settings.is_supported << std::endl;
-  *out << "}";
-}
-
-}  // namespace assistant
-}  // namespace chromeos
-
-namespace ash::libassistant {
-
-namespace {
-
-constexpr double kEpsilon = 0.001;
-
-using ::assistant::api::client_op::GetDeviceSettingsArgs;
-using ::assistant::api::client_op::ModifySettingArgs;
-using chromeos::assistant::DeviceSetting;
-using Change = ::assistant::api::client_op::ModifySettingArgs::Change;
-using Unit = ::assistant::api::client_op::ModifySettingArgs::Unit;
-using ::testing::AnyNumber;
-using ::testing::DoubleNear;
-using ::testing::ElementsAre;
-using ::testing::FloatNear;
-using ::testing::Return;
-using ::testing::StrictMock;
-
-constexpr char kWiFi[] = "WIFI";
-constexpr char kBluetooth[] = "BLUETOOTH";
-constexpr char kScreenBrightness[] = "BRIGHTNESS_LEVEL";
-constexpr char kDoNotDisturb[] = "DO_NOT_DISTURB";
-constexpr char kNightLight[] = "NIGHT_LIGHT_SWITCH";
-constexpr char kSwitchAccess[] = "SWITCH_ACCESS";
-
-// Returns the settings that are always supported.
-const std::vector<std::string> kAlwaysSupportedSettings = {
-    kWiFi,         kBluetooth,  kScreenBrightness,
-    kDoNotDisturb, kNightLight, kSwitchAccess,
-};
-
-class DeviceSettingsDelegateMock : public mojom::DeviceSettingsDelegate {
- public:
-  // mojom::DeviceSettingsDelegate implementation:
-  void GetScreenBrightnessLevel(
-      GetScreenBrightnessLevelCallback callback) override {
-    std::move(callback).Run(
-        mojom::GetBrightnessResult::New(current_brightness_));
-  }
-  MOCK_METHOD(void, SetBluetoothEnabled, (bool enabled));
-  MOCK_METHOD(void, SetDoNotDisturbEnabled, (bool enabled));
-  MOCK_METHOD(void, SetNightLightEnabled, (bool enabled));
-  MOCK_METHOD(void, SetScreenBrightnessLevel, (double level, bool gradual));
-  MOCK_METHOD(void, SetSwitchAccessEnabled, (bool enabled));
-  MOCK_METHOD(void, SetWifiEnabled, (bool enabled));
-
-  mojo::PendingRemote<mojom::DeviceSettingsDelegate>
-  BindNewPipeAndPassRemote() {
-    return receiver_.BindNewPipeAndPassRemote();
-  }
-
-  void FlushForTesting() { receiver_.FlushForTesting(); }
-
-  void set_current_brightness(double value) { current_brightness_ = value; }
-
- private:
-  mojo::Receiver<DeviceSettingsDelegate> receiver_{this};
-  double current_brightness_;
-};
-
-}  // namespace
-
-class AssistantDeviceSettingsControllerTest : public testing::Test {
- public:
-  AssistantDeviceSettingsControllerTest() = default;
-
-  void SetUp() override {
-    controller().Bind(delegate_mock_.BindNewPipeAndPassRemote());
-  }
-
-  DeviceSetting GetSupportedDeviceSettings(const std::string& setting_id) {
-    GetDeviceSettingsArgs args;
-    args.add_setting_ids(setting_id);
-
-    std::vector<DeviceSetting> result =
-        controller().GetSupportedDeviceSettings(args);
-    EXPECT_EQ(result.size(), 1u);
-    return result[0];
-  }
-
-  void ModifySetting(const ModifySettingArgs& args) {
-    controller().OnModifyDeviceSetting(args);
-    delegate_mock().FlushForTesting();
-    // When we're changing the brightness, we first fetch the current value
-    // and then need to run a callback on the main thread.
-    base::RunLoop().RunUntilIdle();
-  }
-
-  DeviceSettingsController& controller() { return controller_; }
-
-  DeviceSettingsDelegateMock& delegate_mock() { return delegate_mock_; }
-
- private:
-  base::test::SingleThreadTaskEnvironment environment_;
-  DeviceSettingsController controller_;
-  DeviceSettingsDelegateMock delegate_mock_;
-};
-
-std::ostream& operator<<(std::ostream& stream, const DeviceSetting& value) {
-  stream << "{ " << value.setting_id << ": " << value.is_supported << "}";
-  return stream;
-}
-
-TEST_F(AssistantDeviceSettingsControllerTest,
-       GetDeviceSettingsShouldReturnFalseForUnknownSetting) {
-  EXPECT_EQ(GetSupportedDeviceSettings("UNKNOWN_SETTING"),
-            DeviceSetting("UNKNOWN_SETTING", false));
-}
-
-TEST_F(AssistantDeviceSettingsControllerTest,
-       GetDeviceSettingsShouldReturnTrueForKnownSettings) {
-  for (const std::string& setting : kAlwaysSupportedSettings) {
-    EXPECT_EQ(GetSupportedDeviceSettings(setting), DeviceSetting(setting, true))
-        << "Error for " << setting;
-  }
-}
-
-TEST_F(AssistantDeviceSettingsControllerTest,
-       GetDeviceSettingsShouldMultipleSettingsAtTheSameTime) {
-  GetDeviceSettingsArgs args;
-  args.add_setting_ids("UNKNOWN_SETTING");
-  args.add_setting_ids(kWiFi);
-
-  std::vector<DeviceSetting> result =
-      controller().GetSupportedDeviceSettings(args);
-
-  EXPECT_THAT(controller().GetSupportedDeviceSettings(args),
-              ElementsAre(DeviceSetting("UNKNOWN_SETTING", false),
-                          DeviceSetting(kWiFi, true)));
-}
-
-TEST_F(AssistantDeviceSettingsControllerTest, ShouldTurnWifiOnAndOff) {
-  ModifySettingArgs args;
-  args.set_setting_id(kWiFi);
-
-  args.set_change(Change::ModifySettingArgs_Change_ON);
-  EXPECT_CALL(delegate_mock(), SetWifiEnabled(true));
-  ModifySetting(args);
-
-  args.set_change(Change::ModifySettingArgs_Change_OFF);
-  EXPECT_CALL(delegate_mock(), SetWifiEnabled(false));
-  ModifySetting(args);
-}
-
-TEST_F(AssistantDeviceSettingsControllerTest, ShouldTurnBluetoothOnAndOff) {
-  ModifySettingArgs args;
-  args.set_setting_id(kBluetooth);
-
-  args.set_change(Change::ModifySettingArgs_Change_ON);
-  EXPECT_CALL(delegate_mock(), SetBluetoothEnabled(true));
-  ModifySetting(args);
-
-  args.set_change(Change::ModifySettingArgs_Change_OFF);
-  EXPECT_CALL(delegate_mock(), SetBluetoothEnabled(false));
-  ModifySetting(args);
-}
-
-TEST_F(AssistantDeviceSettingsControllerTest, ShouldTurnQuietModeOnAndOff) {
-  ModifySettingArgs args;
-  args.set_setting_id(kDoNotDisturb);
-
-  args.set_change(Change::ModifySettingArgs_Change_ON);
-  EXPECT_CALL(delegate_mock(), SetDoNotDisturbEnabled(true));
-  ModifySetting(args);
-
-  args.set_change(Change::ModifySettingArgs_Change_OFF);
-  EXPECT_CALL(delegate_mock(), SetDoNotDisturbEnabled(false));
-  ModifySetting(args);
-}
-
-TEST_F(AssistantDeviceSettingsControllerTest, ShouldTurnSwitchAccessOnAndOff) {
-  ModifySettingArgs args;
-  args.set_setting_id(kSwitchAccess);
-
-  args.set_change(Change::ModifySettingArgs_Change_ON);
-  EXPECT_CALL(delegate_mock(), SetSwitchAccessEnabled(true));
-  ModifySetting(args);
-
-  args.set_change(Change::ModifySettingArgs_Change_OFF);
-  EXPECT_CALL(delegate_mock(), SetSwitchAccessEnabled(false));
-  ModifySetting(args);
-}
-
-TEST_F(AssistantDeviceSettingsControllerTest, ShouldTurnNightLightOnAndOff) {
-  ModifySettingArgs args;
-  args.set_setting_id(kNightLight);
-
-  args.set_change(Change::ModifySettingArgs_Change_ON);
-  EXPECT_CALL(delegate_mock(), SetNightLightEnabled(true));
-  ModifySetting(args);
-
-  args.set_change(Change::ModifySettingArgs_Change_OFF);
-  EXPECT_CALL(delegate_mock(), SetNightLightEnabled(false));
-  ModifySetting(args);
-}
-
-TEST_F(AssistantDeviceSettingsControllerTest, ShouldSetBrightness) {
-  ModifySettingArgs args;
-  args.set_setting_id(kScreenBrightness);
-  args.set_change(Change::ModifySettingArgs_Change_SET);
-
-  // Set brightness to 20%
-  args.set_numeric_value(0.2);
-  args.set_unit(Unit::ModifySettingArgs_Unit_RANGE);
-  EXPECT_CALL(delegate_mock(),
-              SetScreenBrightnessLevel(DoubleNear(0.2, kEpsilon),
-                                       /*gradual=*/true));
-  ModifySetting(args);
-
-  // Set brightness to 30.
-  // This will be converted to a percentage
-  args.set_numeric_value(30);
-  args.set_unit(Unit::ModifySettingArgs_Unit_STEP);
-  EXPECT_CALL(delegate_mock(),
-              SetScreenBrightnessLevel(DoubleNear(0.3, kEpsilon),
-                                       /*gradual=*/true));
-  ModifySetting(args);
-}
-
-TEST_F(AssistantDeviceSettingsControllerTest,
-       ShouldIncreaseAndDecreaseBrightness) {
-  ModifySettingArgs args;
-  args.set_setting_id(kScreenBrightness);
-
-  // Increase brightness - this will use a default increment of 10%
-  args.set_change(Change::ModifySettingArgs_Change_INCREASE);
-  args.set_unit(Unit::ModifySettingArgs_Unit_UNKNOWN_UNIT);
-  delegate_mock().set_current_brightness(0.2);
-  EXPECT_CALL(delegate_mock(),
-              SetScreenBrightnessLevel(DoubleNear(0.3, kEpsilon),
-                                       /*gradual=*/true));
-  ModifySetting(args);
-
-  // Decrease brightness - this will use a default decrement of 10%
-  args.set_change(Change::ModifySettingArgs_Change_DECREASE);
-  args.set_unit(Unit::ModifySettingArgs_Unit_UNKNOWN_UNIT);
-  delegate_mock().set_current_brightness(0.2);
-  EXPECT_CALL(delegate_mock(),
-              SetScreenBrightnessLevel(DoubleNear(0.1, kEpsilon),
-                                       /*gradual=*/true));
-  ModifySetting(args);
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/display_connection.cc b/chromeos/ash/services/libassistant/display_connection.cc
deleted file mode 100644
index fc862bbd8..0000000
--- a/chromeos/ash/services/libassistant/display_connection.cc
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/display_connection.h"
-
-#include <sstream>
-
-#include "base/check.h"
-#include "base/logging.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/display_interface.pb.h"
-
-namespace ash::libassistant {
-
-DisplayConnection::DisplayConnection(DisplayConnectionObserver* observer,
-                                     bool feedback_ui_enabled)
-    : observer_(observer),
-      feedback_ui_enabled_(feedback_ui_enabled),
-      task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {
-  DCHECK(observer_);
-}
-
-DisplayConnection::~DisplayConnection() = default;
-
-void DisplayConnection::OnGrpcMessage(
-    const ::assistant::api::OnAssistantDisplayEventRequest& request) {
-  auto& assistant_display_event = request.event();
-
-  DCHECK(assistant_display_event.has_on_assistant_event());
-  DCHECK(
-      assistant_display_event.on_assistant_event().has_assistant_event_bytes());
-  DVLOG(1) << "AssistantDisplayEventObserver received GrpcMessage.";
-
-  const std::string& assistant_event_bytes =
-      assistant_display_event.on_assistant_event().assistant_event_bytes();
-
-  ::assistant::display::AssistantEvent event;
-  if (!event.ParseFromString(assistant_event_bytes)) {
-    LOG(ERROR) << "Unable to parse assistant event";
-    return;
-  }
-
-  if (event.has_speech_level_event()) {
-    task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&DisplayConnectionObserver::OnSpeechLevelUpdated,
-                       base::Unretained(observer_),
-                       event.speech_level_event().speech_level()));
-  }
-}
-
-void DisplayConnection::SetAssistantClient(AssistantClient* assistant_client) {
-  assistant_client_ = assistant_client;
-}
-
-void DisplayConnection::SetArcPlayStoreEnabled(bool enabled) {
-  arc_play_store_enabled_ = enabled;
-  SendDisplayRequest();
-}
-
-void DisplayConnection::SetDeviceAppsEnabled(bool enabled) {
-  // For now we don't handle disabling the device apps bit, since we do not have
-  // a way to get the bit changes. We only sync the bit at Service start post
-  // login.
-  // If user accept the whole activity control flow later we update the bit to
-  // true.
-  DCHECK(enabled || !device_apps_enabled_);
-  if (device_apps_enabled_ == enabled)
-    return;
-  device_apps_enabled_ = enabled;
-  SendDisplayRequest();
-}
-
-void DisplayConnection::SetAssistantContextEnabled(bool enabled) {
-  if (related_info_enabled_ == enabled)
-    return;
-  related_info_enabled_ = enabled;
-  SendDisplayRequest();
-}
-
-void DisplayConnection::OnAndroidAppListRefreshed(
-    const std::vector<assistant::AndroidAppInfo>& apps_info) {
-  apps_info_ = apps_info;
-  SendDisplayRequest();
-}
-
-void DisplayConnection::SendDisplayRequest() {
-  if (!assistant_client_) {
-    LOG(ERROR) << "Can't send DisplayRequest before assistant client is set.";
-    return;
-  }
-
-  ::assistant::display::DisplayRequest display_request;
-  FillDisplayRequest(display_request);
-
-  ::assistant::api::OnDisplayRequestRequest request;
-  request.set_display_request_bytes(display_request.SerializeAsString());
-  assistant_client_->SendDisplayRequest(request);
-}
-
-void DisplayConnection::FillDisplayRequest(
-    ::assistant::display::DisplayRequest& dr) {
-  auto* set_capabilities_request = dr.mutable_set_capabilities_request();
-  auto* screen_capabilities =
-      set_capabilities_request->mutable_screen_capabilities_to_merge();
-  auto* resolution = screen_capabilities->mutable_resolution();
-  // TODO(b/111841376): Set actual chromeos screen resolution and reset it when
-  // resolution is changed.
-  resolution->set_width_px(300);
-  resolution->set_height_px(200);
-  set_capabilities_request->set_server_generated_feedback_chips_enabled(
-      feedback_ui_enabled_);
-  set_capabilities_request->set_web_browser_supported(true);
-  set_capabilities_request->mutable_supported_provider_types()
-      ->add_supported_types(
-          ::assistant::api::core_types::ProviderType::WEB_PROVIDER);
-
-  if (arc_play_store_enabled_ && device_apps_enabled_) {
-    set_capabilities_request->mutable_supported_provider_types()
-        ->add_supported_types(
-            ::assistant::api::core_types::ProviderType::ANDROID_APP);
-
-    for (auto& app_info : apps_info_) {
-      auto* android_app_info = set_capabilities_request->add_app_capabilities()
-                                   ->mutable_provider()
-                                   ->mutable_android_app_info();
-      android_app_info->set_package_name(app_info.package_name);
-      android_app_info->set_app_version(app_info.version);
-      android_app_info->set_localized_app_name(app_info.localized_app_name);
-      // android_intent are not set here since server will exclude app info
-      // with intent field set.
-    }
-  }
-
-  set_capabilities_request->mutable_supported_features()
-      ->set_media_session_detection(
-          related_info_enabled_
-              ? ::assistant::api::RELIABLE_MEDIA_SESSION_DETECTION
-              : ::assistant::api::
-                    MEDIA_SESSION_DETECTION_DISABLED_SCREEN_CONTEXT);
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/display_connection.h b/chromeos/ash/services/libassistant/display_connection.h
deleted file mode 100644
index 599b187..0000000
--- a/chromeos/ash/services/libassistant/display_connection.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_DISPLAY_CONNECTION_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_DISPLAY_CONNECTION_H_
-
-#include <string>
-
-#include "base/memory/raw_ptr.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/grpc_services_observer.h"
-#include "chromeos/ash/services/libassistant/public/cpp/android_app_info.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/proto/assistant/display_connection.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_interface.pb.h"
-
-namespace ash::libassistant {
-
-class AssistantClient;
-
-class DisplayConnectionObserver {
- public:
-  virtual ~DisplayConnectionObserver() = default;
-  virtual void OnSpeechLevelUpdated(const float speech_level) {}
-};
-
-// Implements |asssistant_client::DisplayConnection| to initialize surface
-// configuration and listen assistant event.
-class DisplayConnection
-    : public GrpcServicesObserver<
-          ::assistant::api::OnAssistantDisplayEventRequest> {
- public:
-  DisplayConnection(DisplayConnectionObserver* observer,
-                    bool feedback_ui_enabled);
-  DisplayConnection(const DisplayConnection&) = delete;
-  DisplayConnection& operator=(const DisplayConnection&) = delete;
-  ~DisplayConnection() override;
-
-  // GrpcServicesObserver:
-  // Invoked when an Assistant display event has been received.
-  void OnGrpcMessage(
-      const ::assistant::api::OnAssistantDisplayEventRequest& request) override;
-
-  void SetAssistantClient(AssistantClient* assistant_client);
-  void SetArcPlayStoreEnabled(bool enabled);
-  void SetDeviceAppsEnabled(bool enabled);
-  void SetAssistantContextEnabled(bool enabled);
-  void OnAndroidAppListRefreshed(
-      const std::vector<assistant::AndroidAppInfo>& apps_info);
-
-  const std::vector<assistant::AndroidAppInfo>& GetCachedAndroidAppList() {
-    return apps_info_;
-  }
-
- private:
-  void SendDisplayRequest();
-
-  void FillDisplayRequest(::assistant::display::DisplayRequest& dr);
-
-  raw_ptr<AssistantClient> assistant_client_ = nullptr;
-
-  // Owned by the parent which also owns `this`.
-  const raw_ptr<DisplayConnectionObserver> observer_;
-
-  // Whether Assistant feedback UI is enabled.
-  const bool feedback_ui_enabled_;
-
-  // Whether ARC++ is enabled.
-  bool arc_play_store_enabled_ = false;
-
-  // Whether device apps user data consent is granted.
-  bool device_apps_enabled_ = false;
-
-  // Whether related info setting is on.
-  bool related_info_enabled_ = false;
-
-  // Supported Android apps information.
-  std::vector<assistant::AndroidAppInfo> apps_info_;
-
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_DISPLAY_CONNECTION_H_
diff --git a/chromeos/ash/services/libassistant/display_controller.cc b/chromeos/ash/services/libassistant/display_controller.cc
deleted file mode 100644
index 8b739c0..0000000
--- a/chromeos/ash/services/libassistant/display_controller.cc
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/display_controller.h"
-
-#include <memory>
-
-#include "base/memory/raw_ptr.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/assistant/public/cpp/features.h"
-#include "chromeos/ash/services/libassistant/display_connection.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client.h"
-#include "chromeos/ash/services/libassistant/public/mojom/speech_recognition_observer.mojom.h"
-#include "chromeos/ash/services/libassistant/util.h"
-#include "chromeos/assistant/internal/internal_util.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/proto/shared/proto/conversation.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/internal_options.pb.h"
-
-namespace ash::libassistant {
-
-namespace {
-// A macro which ensures we are running on the main thread.
-#define ENSURE_MOJOM_THREAD(method, ...)                                    \
-  if (!mojom_task_runner_->RunsTasksInCurrentSequence()) {                  \
-    mojom_task_runner_->PostTask(                                           \
-        FROM_HERE,                                                          \
-        base::BindOnce(method, weak_factory_.GetWeakPtr(), ##__VA_ARGS__)); \
-    return;                                                                 \
-  }
-}  // namespace
-
-class DisplayController::EventObserver : public DisplayConnectionObserver {
- public:
-  explicit EventObserver(DisplayController* parent) : parent_(parent) {}
-  EventObserver(const EventObserver&) = delete;
-  EventObserver& operator=(const EventObserver&) = delete;
-  ~EventObserver() override = default;
-
-  void OnSpeechLevelUpdated(const float speech_level) override {
-    for (auto& observer : *parent_->speech_recognition_observers_) {
-      observer->OnSpeechLevelUpdated(speech_level);
-    }
-  }
-
- private:
-  const raw_ptr<DisplayController> parent_;
-};
-
-DisplayController::DisplayController(
-    mojo::RemoteSet<mojom::SpeechRecognitionObserver>*
-        speech_recognition_observers)
-    : event_observer_(std::make_unique<EventObserver>(this)),
-      display_connection_(
-          std::make_unique<DisplayConnection>(event_observer_.get(),
-                                              /*feedback_ui_enabled=*/true)),
-      speech_recognition_observers_(*speech_recognition_observers),
-      mojom_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {
-  DCHECK(speech_recognition_observers);
-}
-
-DisplayController::~DisplayController() = default;
-
-void DisplayController::Bind(
-    mojo::PendingReceiver<mojom::DisplayController> receiver) {
-  receiver_.Bind(std::move(receiver));
-}
-
-void DisplayController::SetActionModule(
-    chromeos::assistant::action::CrosActionModule* action_module) {
-  DCHECK(action_module);
-  action_module_ = action_module;
-}
-
-void DisplayController::SetArcPlayStoreEnabled(bool enabled) {
-  display_connection_->SetArcPlayStoreEnabled(enabled);
-}
-
-void DisplayController::SetDeviceAppsEnabled(bool enabled) {
-  display_connection_->SetDeviceAppsEnabled(enabled);
-
-  DCHECK(action_module_);
-  action_module_->SetAppSupportEnabled(
-      assistant::features::IsAppSupportEnabled() && enabled);
-}
-
-void DisplayController::SetRelatedInfoEnabled(bool enabled) {
-  display_connection_->SetAssistantContextEnabled(enabled);
-}
-
-void DisplayController::SetAndroidAppList(
-    const std::vector<assistant::AndroidAppInfo>& apps) {
-  display_connection_->OnAndroidAppListRefreshed(apps);
-}
-
-void DisplayController::OnAssistantClientCreated(
-    AssistantClient* assistant_client) {
-  assistant_client_ = assistant_client;
-  display_connection_->SetAssistantClient(assistant_client_);
-
-  // |display_connection_| outlives |assistant_client_|.
-  assistant_client_->AddDisplayEventObserver(display_connection_.get());
-}
-
-void DisplayController::OnDestroyingAssistantClient(
-    AssistantClient* assistant_client) {
-  assistant_client_ = nullptr;
-  display_connection_->SetAssistantClient(nullptr);
-}
-
-// Called from Libassistant thread.
-void DisplayController::OnVerifyAndroidApp(
-    const std::vector<assistant::AndroidAppInfo>& apps_info,
-    const chromeos::assistant::InteractionInfo& interaction) {
-  ENSURE_MOJOM_THREAD(&DisplayController::OnVerifyAndroidApp, apps_info,
-                      interaction);
-
-  std::vector<assistant::AndroidAppInfo> result_apps_info;
-  for (auto& app_info : apps_info) {
-    assistant::AndroidAppInfo result_app_info(app_info);
-    auto app_status = GetAndroidAppStatus(app_info.package_name);
-    result_app_info.status = app_status;
-    result_apps_info.emplace_back(result_app_info);
-  }
-
-  auto interaction_proto =
-      ash::libassistant::CreateVerifyProviderResponseInteraction(
-          interaction.interaction_id, result_apps_info);
-
-  ::assistant::api::VoicelessOptions options;
-  options.set_obfuscated_gaia_id(interaction.user_id);
-  // Set the request to be user initiated so that a new conversation will be
-  // created to handle the client OPs in the response of this request.
-  options.set_is_user_initiated(true);
-
-  assistant_client_->SendVoicelessInteraction(
-      interaction_proto, /*description=*/"verify_provider_response", options,
-      base::DoNothing());
-}
-
-assistant::AppStatus DisplayController::GetAndroidAppStatus(
-    const std::string& package_name) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  for (auto& app_info : display_connection_->GetCachedAndroidAppList()) {
-    if (app_info.package_name == package_name) {
-      DVLOG(1) << "Assistant: App is available on the device.";
-      return assistant::AppStatus::kAvailable;
-    }
-  }
-
-  DVLOG(1) << "Assistant: App is unavailable on the device";
-  return assistant::AppStatus::kUnavailable;
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/display_controller.h b/chromeos/ash/services/libassistant/display_controller.h
deleted file mode 100644
index f1b3a0d9..0000000
--- a/chromeos/ash/services/libassistant/display_controller.h
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_DISPLAY_CONTROLLER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_DISPLAY_CONTROLLER_H_
-
-#include "base/memory/raw_ptr.h"
-#include "base/memory/raw_ref.h"
-#include "base/sequence_checker.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client_observer.h"
-#include "chromeos/ash/services/libassistant/public/mojom/display_controller.mojom.h"
-#include "chromeos/assistant/internal/action/assistant_action_observer.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote_set.h"
-
-namespace chromeos {
-namespace assistant {
-namespace action {
-class CrosActionModule;
-}  // namespace action
-}  // namespace assistant
-}  // namespace chromeos
-
-namespace ash::libassistant {
-
-namespace mojom {
-class SpeechRecognitionObserver;
-}
-
-class DisplayConnection;
-
-class DisplayController
-    : public mojom::DisplayController,
-      public AssistantClientObserver,
-      public chromeos::assistant::action::AssistantActionObserver {
- public:
-  explicit DisplayController(mojo::RemoteSet<mojom::SpeechRecognitionObserver>*
-                                 speech_recognition_observers);
-  DisplayController(const DisplayController&) = delete;
-  DisplayController& operator=(const DisplayController&) = delete;
-  ~DisplayController() override;
-
-  void Bind(mojo::PendingReceiver<mojom::DisplayController> receiver);
-
-  void SetActionModule(
-      chromeos::assistant::action::CrosActionModule* action_module);
-
-  // mojom::DisplayController implementation:
-  void SetArcPlayStoreEnabled(bool enabled) override;
-  void SetDeviceAppsEnabled(bool enabled) override;
-  void SetRelatedInfoEnabled(bool enabled) override;
-  void SetAndroidAppList(
-      const std::vector<assistant::AndroidAppInfo>& apps) override;
-
-  // AssistantClientObserver implementation:
-  void OnAssistantClientCreated(AssistantClient* assistant_client) override;
-  void OnDestroyingAssistantClient(AssistantClient* assistant_client) override;
-
-  // chromeos::assistant::action::AssistantActionObserver:
-  void OnVerifyAndroidApp(
-      const std::vector<assistant::AndroidAppInfo>& apps_info,
-      const chromeos::assistant::InteractionInfo& interaction) override;
-
-  DisplayConnection& GetDisplayConnectionForTesting() {
-    return *display_connection_.get();
-  }
-
- private:
-  class EventObserver;
-
-  // Checks if the requested Android App with |package_name| is available on the
-  // device.
-  assistant::AppStatus GetAndroidAppStatus(const std::string& package_name);
-
-  mojo::Receiver<mojom::DisplayController> receiver_{this};
-  std::unique_ptr<EventObserver> event_observer_;
-  std::unique_ptr<DisplayConnection> display_connection_;
-
-  // Owned by |LibassistantService|.
-  const raw_ref<mojo::RemoteSet<mojom::SpeechRecognitionObserver>>
-      speech_recognition_observers_;
-
-  raw_ptr<AssistantClient> assistant_client_ = nullptr;
-
-  // Owned by |ConversationController|.
-  raw_ptr<chromeos::assistant::action::CrosActionModule> action_module_ =
-      nullptr;
-
-  // The callbacks from Libassistant are called on a different sequence,
-  // so this sequence checker ensures that no other methods are called on the
-  // libassistant sequence.
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  scoped_refptr<base::SequencedTaskRunner> mojom_task_runner_;
-  base::WeakPtrFactory<DisplayController> weak_factory_{this};
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_DISPLAY_CONTROLLER_H_
diff --git a/chromeos/ash/services/libassistant/display_controller_unittest.cc b/chromeos/ash/services/libassistant/display_controller_unittest.cc
deleted file mode 100644
index d30c95b..0000000
--- a/chromeos/ash/services/libassistant/display_controller_unittest.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/display_controller.h"
-#include "base/run_loop.h"
-#include "base/test/task_environment.h"
-#include "chromeos/ash/components/assistant/test_support/expect_utils.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client.h"
-#include "chromeos/ash/services/libassistant/public/mojom/speech_recognition_observer.mojom.h"
-#include "chromeos/ash/services/libassistant/test_support/fake_assistant_client.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-using assistant::AndroidAppInfo;
-using chromeos::assistant::InteractionInfo;
-
-constexpr int kSampleInteractionId = 123;
-constexpr char kSampleUserId[] = "user-id";
-constexpr char kSamplePackageName[] = "app.test";
-
-class AssistantClientMock : public FakeAssistantClient {
- public:
-  AssistantClientMock(std::unique_ptr<chromeos::assistant::FakeAssistantManager>
-                          assistant_manager)
-      : FakeAssistantClient(std::move(assistant_manager)) {}
-  ~AssistantClientMock() override = default;
-
-  // AssistantClient:
-  MOCK_METHOD(void,
-              SendVoicelessInteraction,
-              (const ::assistant::api::Interaction& interaction,
-               const std::string& description,
-               const ::assistant::api::VoicelessOptions& options,
-               base::OnceCallback<void(bool)> on_done));
-
-  MOCK_METHOD(void,
-              AddDisplayEventObserver,
-              (GrpcServicesObserver<OnAssistantDisplayEventRequest> *
-               observer));
-};
-
-}  // namespace
-
-class DisplayControllerTest : public ::testing::Test {
- public:
-  DisplayControllerTest() = default;
-  DisplayControllerTest(const DisplayControllerTest&) = delete;
-  DisplayControllerTest& operator=(const DisplayControllerTest&) = delete;
-  ~DisplayControllerTest() override = default;
-
-  void SetUp() override {
-    controller_ =
-        std::make_unique<DisplayController>(&speech_recognition_observers_);
-  }
-
-  void StartLibassistant() {
-    controller_->OnAssistantClientCreated(&assistant_client_);
-  }
-
-  DisplayController* controller() { return controller_.get(); }
-
-  AssistantClientMock& assistant_client_mock() { return assistant_client_; }
-
- private:
-  base::test::SingleThreadTaskEnvironment environment_;
-  mojo::RemoteSet<mojom::SpeechRecognitionObserver>
-      speech_recognition_observers_;
-  std::unique_ptr<DisplayController> controller_;
-  AssistantClientMock assistant_client_{nullptr};
-};
-
-TEST_F(DisplayControllerTest, ShouldSetDisplayEventObserver) {
-  EXPECT_CALL(assistant_client_mock(), AddDisplayEventObserver);
-
-  StartLibassistant();
-}
-
-TEST_F(DisplayControllerTest,
-       ShouldSendVoicelessInteractionOnVerifyAndroidApp) {
-  EXPECT_CALL(assistant_client_mock(), AddDisplayEventObserver);
-  StartLibassistant();
-
-  AndroidAppInfo app_info;
-  app_info.package_name = kSamplePackageName;
-  InteractionInfo interaction = {kSampleInteractionId, kSampleUserId};
-
-  EXPECT_CALL(assistant_client_mock(), SendVoicelessInteraction);
-  controller()->OnVerifyAndroidApp({app_info}, interaction);
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/fake_auth_provider.cc b/chromeos/ash/services/libassistant/fake_auth_provider.cc
deleted file mode 100644
index 8fa3a78..0000000
--- a/chromeos/ash/services/libassistant/fake_auth_provider.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/fake_auth_provider.h"
-
-namespace ash::libassistant {
-
-std::string FakeAuthProvider::GetAuthClientId() {
-  return "kFakeClientId";
-}
-
-std::vector<std::string> FakeAuthProvider::GetClientCertificateChain() {
-  return {};
-}
-
-void FakeAuthProvider::CreateCredentialAttestationJwt(
-    const std::string& authorization_code,
-    const std::vector<std::pair<std::string, std::string>>& claims,
-    CredentialCallback attestation_callback) {
-  attestation_callback(Error::SUCCESS, "", "");
-}
-
-void FakeAuthProvider::CreateRefreshAssertionJwt(
-    const std::string& key_identifier,
-    const std::vector<std::pair<std::string, std::string>>& claims,
-    AssertionCallback assertion_callback) {
-  assertion_callback(Error::SUCCESS, "");
-}
-
-void FakeAuthProvider::CreateDeviceAttestationJwt(
-    const std::vector<std::pair<std::string, std::string>>& claims,
-    AssertionCallback attestation_callback) {
-  attestation_callback(Error::SUCCESS, "");
-}
-
-std::string FakeAuthProvider::GetAttestationCertFingerprint() {
-  return "kFakeAttestationCertFingerprint";
-}
-
-void FakeAuthProvider::RemoveCredentialKey(const std::string& key_identifier) {}
-
-void FakeAuthProvider::Reset() {}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/fake_auth_provider.h b/chromeos/ash/services/libassistant/fake_auth_provider.h
deleted file mode 100644
index cc3c466..0000000
--- a/chromeos/ash/services/libassistant/fake_auth_provider.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_FAKE_AUTH_PROVIDER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_FAKE_AUTH_PROVIDER_H_
-
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-
-#include <string>
-#include <vector>
-
-namespace ash::libassistant {
-
-// ChromeOS does not use auth manager, so we don't yet need to implement a
-// real auth provider.
-class FakeAuthProvider : public assistant_client::AuthProvider {
- public:
-  FakeAuthProvider() = default;
-  ~FakeAuthProvider() override = default;
-
-  // assistant_client::AuthProvider implementation:
-  std::string GetAuthClientId() override;
-  std::vector<std::string> GetClientCertificateChain() override;
-
-  void CreateCredentialAttestationJwt(
-      const std::string& authorization_code,
-      const std::vector<std::pair<std::string, std::string>>& claims,
-      CredentialCallback attestation_callback) override;
-
-  void CreateRefreshAssertionJwt(
-      const std::string& key_identifier,
-      const std::vector<std::pair<std::string, std::string>>& claims,
-      AssertionCallback assertion_callback) override;
-
-  void CreateDeviceAttestationJwt(
-      const std::vector<std::pair<std::string, std::string>>& claims,
-      AssertionCallback attestation_callback) override;
-
-  std::string GetAttestationCertFingerprint() override;
-
-  void RemoveCredentialKey(const std::string& key_identifier) override;
-
-  void Reset() override;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_FAKE_AUTH_PROVIDER_H_
diff --git a/chromeos/ash/services/libassistant/file_provider_impl.cc b/chromeos/ash/services/libassistant/file_provider_impl.cc
deleted file mode 100644
index 5e611b47..0000000
--- a/chromeos/ash/services/libassistant/file_provider_impl.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/file_provider_impl.h"
-
-#include "base/files/file_util.h"
-#include "chromeos/ash/grit/ash_resources.h"
-#include "chromeos/ash/services/libassistant/util.h"
-#include "ui/base/resource/resource_bundle.h"
-
-namespace ash::libassistant {
-namespace {
-
-constexpr int kReadFileSizeLimitInBytes = 10 * 1024 * 1024;
-
-}  // namespace
-
-FileProviderImpl::FileProviderImpl() : root_path_(GetBaseAssistantDir()) {}
-
-FileProviderImpl::~FileProviderImpl() = default;
-
-std::string FileProviderImpl::ReadFile(const std::string& path) {
-  std::string data;
-  base::ReadFileToStringWithMaxSize(root_path_.Append(path), &data,
-                                    kReadFileSizeLimitInBytes);
-  return data;
-}
-
-bool FileProviderImpl::WriteFile(const std::string& path,
-                                 const std::string& data) {
-  base::FilePath full_path = root_path_.Append(path);
-  if (!base::PathExists(full_path.DirName()) &&
-      !base::CreateDirectory(full_path.DirName()))
-    return false;
-
-  // Create a temp file.
-  base::FilePath temp_file;
-  auto fd = base::CreateAndOpenFdForTemporaryFileInDir(full_path.DirName(),
-                                                       &temp_file);
-  if (!fd.is_valid())
-    return false;
-
-  // Write to the tmp file.
-  const bool success = base::WriteFileDescriptor(fd.get(), data);
-  if (!success)
-    return false;
-
-  // Replace the current file with the temp file.
-  if (!base::ReplaceFile(temp_file, full_path, nullptr)) {
-    return false;
-  }
-
-  return true;
-}
-
-std::string FileProviderImpl::ReadSecureFile(const std::string& path) {
-  return ReadFile(path);
-}
-
-bool FileProviderImpl::WriteSecureFile(const std::string& path,
-                                       const std::string& data) {
-  // No need to encrypt since |root_path_| should be inside the primary user's
-  // cryptohome and is already encrypted.
-  return WriteFile(path, data);
-}
-
-void FileProviderImpl::CleanAssistantData() {
-  base::DeletePathRecursively(root_path_);
-}
-
-bool FileProviderImpl::GetResource(uint16_t resource_id, std::string* out) {
-  int chrome_resource_id = -1;
-  switch (resource_id) {
-    case assistant_client::resource_ids::kGeneralError:
-      chrome_resource_id = IDR_ASSISTANT_SPEECH_RECOGNITION_ERROR;
-      break;
-    case assistant_client::resource_ids::kWifiNeedsSetupError:
-    case assistant_client::resource_ids::kWifiNotConnectedError:
-    case assistant_client::resource_ids::kWifiCannotConnectError:
-    case assistant_client::resource_ids::kNetworkConnectingError:
-    // These above do not apply to ChromeOS, but let it fall through to get a
-    // generic error.
-    case assistant_client::resource_ids::kNetworkCannotReachServerError:
-      chrome_resource_id = IDR_ASSISTANT_NO_INTERNET_ERROR;
-      break;
-    default:
-      break;
-  }
-
-  if (chrome_resource_id < 0)
-    return false;
-
-  auto data = ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
-      chrome_resource_id);
-  out->assign(data.data(), data.length());
-  return true;
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/file_provider_impl.h b/chromeos/ash/services/libassistant/file_provider_impl.h
deleted file mode 100644
index 90ee747..0000000
--- a/chromeos/ash/services/libassistant/file_provider_impl.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_FILE_PROVIDER_IMPL_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_FILE_PROVIDER_IMPL_H_
-
-#include <string>
-
-#include "base/files/file_path.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-
-namespace ash::libassistant {
-
-class FileProviderImpl : public assistant_client::FileProvider {
- public:
-  FileProviderImpl();
-
-  FileProviderImpl(const FileProviderImpl&) = delete;
-  FileProviderImpl& operator=(const FileProviderImpl&) = delete;
-
-  ~FileProviderImpl() override;
-
-  // assistant_client::FileProvider overrides:
-  std::string ReadFile(const std::string& path) override;
-  bool WriteFile(const std::string& path, const std::string& data) override;
-  std::string ReadSecureFile(const std::string& path) override;
-  bool WriteSecureFile(const std::string& path,
-                       const std::string& data) override;
-  void CleanAssistantData() override;
-  bool GetResource(uint16_t resource_id, std::string* out) override;
-
- private:
-  // Root path which other paths are relative to.
-  const base::FilePath root_path_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_FILE_PROVIDER_IMPL_H_
diff --git a/chromeos/ash/services/libassistant/grpc/BUILD.gn b/chromeos/ash/services/libassistant/grpc/BUILD.gn
deleted file mode 100644
index 733f983d..0000000
--- a/chromeos/ash/services/libassistant/grpc/BUILD.gn
+++ /dev/null
@@ -1,163 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-assert(is_chromeos, "Non ChromeOS builds must not depend on //chromeos/ash")
-
-source_set("assistant_client") {
-  sources = [
-    "./utils/media_status_utils.cc",
-    "./utils/media_status_utils.h",
-    "./utils/settings_utils.cc",
-    "./utils/settings_utils.h",
-    "./utils/timer_utils.cc",
-    "./utils/timer_utils.h",
-    "assistant_client.cc",
-    "assistant_client.h",
-    "assistant_client_impl.cc",
-    "assistant_client_impl.h",
-    "assistant_client_observer.h",
-  ]
-
-  deps = [
-    ":grpc_service",
-    ":grpc_util",
-    ":libassistant_client",
-    "external_services:grpc_services_initializer",
-    "external_services:grpc_services_observer",
-    "//base",
-    "//chromeos/ash/services/assistant/public/cpp",
-    "//chromeos/ash/services/libassistant:callback_utils",
-    "//chromeos/assistant/internal",
-    "//chromeos/assistant/internal:libassistant_shared_headers",
-  ]
-}
-
-source_set("grpc_client") {
-  sources = [
-    "grpc_client_thread.cc",
-    "grpc_client_thread.h",
-    "grpc_state.h",
-  ]
-
-  public_deps = [
-    ":grpc_util",
-    "//third_party/grpc:grpc++",
-  ]
-
-  deps = [
-    "//base",
-    "//chromeos/assistant/internal",
-    "//third_party/protobuf:protobuf_lite",
-  ]
-
-  # Make grpc_config as all dependent to avoid adding public deps
-  # for any top-level targets that are not immediate dependents and
-  # indirectly includes headers from grpc through grpc_libassistant_client header.
-  all_dependent_configs = [ "//third_party/grpc:grpc_config" ]
-}
-
-source_set("grpc_service") {
-  sources = [
-    "async_service_driver.h",
-    "rpc_method_driver.h",
-    "services_initializer_base.cc",
-    "services_initializer_base.h",
-    "services_status_observer.h",
-    "services_status_provider.cc",
-    "services_status_provider.h",
-  ]
-
-  public_deps = [ "//chromeos/assistant/internal/proto:assistant" ]
-
-  deps = [
-    ":grpc_util",
-    "external_services:grpc_services_observer",
-    "//base",
-    "//third_party/grpc:grpc++",
-  ]
-
-  all_dependent_configs = [ "//third_party/grpc:grpc_config" ]
-}
-
-source_set("grpc_util") {
-  sources = [
-    "grpc_util.cc",
-    "grpc_util.h",
-  ]
-
-  deps = [
-    "//base",
-    "//chromeos/assistant/internal:support",
-    "//third_party/grpc:grpc++",
-    "//third_party/protobuf:protobuf_lite",
-  ]
-
-  all_dependent_configs = [ "//third_party/grpc:grpc_config" ]
-}
-
-source_set("libassistant_client") {
-  sources = [
-    "grpc_libassistant_client.cc",
-    "grpc_libassistant_client.h",
-  ]
-
-  public_deps = [ "//chromeos/assistant/internal/proto:assistant" ]
-
-  deps = [
-    ":grpc_client",
-    "//base",
-    "//chromeos/assistant/internal:support",
-  ]
-
-  # Make grpc_config as all dependent to avoid adding public deps
-  # for any top-level targets that are not immediate dependents and
-  # indirectly includes headers from grpc through grpc_libassistant_client header.
-  all_dependent_configs = [ "//third_party/grpc:grpc_config" ]
-}
-
-source_set("http_connection_client") {
-  sources = [
-    "grpc_http_connection_client.cc",
-    "grpc_http_connection_client.h",
-    "grpc_http_connection_delegate.cc",
-    "grpc_http_connection_delegate.h",
-  ]
-
-  public_deps = [
-    "//chromeos/assistant/internal/proto:assistant",
-    "//chromeos/assistant/internal/proto:assistant_grpc",
-  ]
-
-  deps = [
-    ":grpc_client",
-    "//base",
-    "//chromeos/assistant/internal",
-    "//chromeos/assistant/internal:libassistant_shared_headers",
-  ]
-}
-
-source_set("unit_tests") {
-  testonly = true
-  sources = [
-    "external_services/grpc_services_initializer_unittests.cc",
-    "grpc_http_connection_client_unittests.cc",
-  ]
-
-  deps = [
-    ":assistant_client",
-    ":grpc_service",
-    ":grpc_util",
-    ":http_connection_client",
-    "external_services:grpc_services_initializer",
-    "//base/test:test_support",
-    "//chromeos/ash/services/assistant/public/cpp",
-    "//chromeos/assistant/internal",
-    "//chromeos/assistant/internal:libassistant_shared_headers",
-    "//chromeos/assistant/internal:test_support",
-    "//chromeos/assistant/internal/proto:assistant",
-    "//chromeos/assistant/internal/proto:assistant_grpc",
-    "//testing/gmock",
-    "//testing/gtest",
-  ]
-}
diff --git a/chromeos/ash/services/libassistant/grpc/DEPS b/chromeos/ash/services/libassistant/grpc/DEPS
deleted file mode 100644
index 37f51b6..0000000
--- a/chromeos/ash/services/libassistant/grpc/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
-  "+base",
-  "+third_party/grpc",
-]
diff --git a/chromeos/ash/services/libassistant/grpc/assistant_client.cc b/chromeos/ash/services/libassistant/grpc/assistant_client.cc
deleted file mode 100644
index aa453567..0000000
--- a/chromeos/ash/services/libassistant/grpc/assistant_client.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/assistant_client.h"
-
-#include <memory>
-
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-
-namespace ash::libassistant {
-
-AssistantClient::AssistantClient(
-    std::unique_ptr<assistant_client::AssistantManager> assistant_manager)
-    : assistant_manager_(std::move(assistant_manager)) {}
-
-AssistantClient::~AssistantClient() = default;
-
-void AssistantClient::ResetAssistantManager() {
-  assistant_manager_ = nullptr;
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/assistant_client.h b/chromeos/ash/services/libassistant/grpc/assistant_client.h
deleted file mode 100644
index e3ee762..0000000
--- a/chromeos/ash/services/libassistant/grpc/assistant_client.h
+++ /dev/null
@@ -1,249 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_ASSISTANT_CLIENT_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_ASSISTANT_CLIENT_H_
-
-#include <memory>
-
-#include "base/functional/callback_forward.h"
-#include "base/memory/raw_ptr.h"
-#include "base/scoped_observation_traits.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/grpc_services_observer.h"
-#include "chromeos/ash/services/libassistant/grpc/services_status_observer.h"
-#include "chromeos/ash/services/libassistant/public/cpp/assistant_timer.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/device_state_event.pb.h"
-
-namespace assistant {
-namespace api {
-class CancelSpeakerIdEnrollmentRequest;
-class GetSpeakerIdEnrollmentInfoRequest;
-class GetSpeakerIdEnrollmentInfoResponse;
-class GetAssistantSettingsResponse;
-class Interaction;
-class OnAlarmTimerEventRequest;
-class OnAssistantDisplayEventRequest;
-class OnConversationStateEventRequest;
-class OnDeviceStateEventRequest;
-class OnDisplayRequestRequest;
-class OnMediaActionFallbackEventRequest;
-class OnSpeakerIdEnrollmentEventRequest;
-class StartSpeakerIdEnrollmentRequest;
-class UpdateAssistantSettingsResponse;
-class VoicelessOptions;
-
-namespace events {
-class SpeakerIdEnrollmentEvent;
-}  // namespace events
-}  // namespace api
-}  // namespace assistant
-
-namespace assistant {
-namespace ui {
-class SettingsUiSelector;
-class SettingsUiUpdate;
-}  // namespace ui
-}  // namespace assistant
-
-namespace assistant_client {
-class ActionModule;
-class AssistantManager;
-class HttpConnectionFactory;
-}  // namespace assistant_client
-
-namespace ash::libassistant {
-
-// The Libassistant customer class which establishes a gRPC connection to
-// Libassistant and provides an interface for interacting with gRPC Libassistant
-// client. It helps to build request/response proto messages internally for each
-// specific method below and call the appropriate gRPC (IPC) client method.
-class AssistantClient {
- public:
-  // Speaker Id Enrollment:
-  using CancelSpeakerIdEnrollmentRequest =
-      ::assistant::api::CancelSpeakerIdEnrollmentRequest;
-  using GetSpeakerIdEnrollmentInfoRequest =
-      ::assistant::api::GetSpeakerIdEnrollmentInfoRequest;
-  using GetSpeakerIdEnrollmentInfoResponse =
-      ::assistant::api::GetSpeakerIdEnrollmentInfoResponse;
-  using StartSpeakerIdEnrollmentRequest =
-      ::assistant::api::StartSpeakerIdEnrollmentRequest;
-  using SpeakerIdEnrollmentEvent =
-      ::assistant::api::events::SpeakerIdEnrollmentEvent;
-  using OnSpeakerIdEnrollmentEventRequest =
-      ::assistant::api::OnSpeakerIdEnrollmentEventRequest;
-
-  // Display:
-  using OnAssistantDisplayEventRequest =
-      ::assistant::api::OnAssistantDisplayEventRequest;
-  using OnDisplayRequestRequest = ::assistant::api::OnDisplayRequestRequest;
-
-  // Media:
-  using MediaStatus = ::assistant::api::events::DeviceState::MediaStatus;
-  using OnDeviceStateEventRequest = ::assistant::api::OnDeviceStateEventRequest;
-  using OnMediaActionFallbackEventRequest =
-      ::assistant::api::OnMediaActionFallbackEventRequest;
-
-  // Conversation:
-  using OnConversationStateEventRequest =
-      ::assistant::api::OnConversationStateEventRequest;
-
-  // Each authentication token exists of a [gaia_id, access_token] tuple.
-  using AuthTokens = std::vector<std::pair<std::string, std::string>>;
-
-  AssistantClient(
-      std::unique_ptr<assistant_client::AssistantManager> assistant_manager);
-  AssistantClient(const AssistantClient&) = delete;
-  AssistantClient& operator=(const AssistantClient&) = delete;
-  virtual ~AssistantClient();
-
-  // Starts Libassistant services. |services_status_observer| will get notified
-  // on new status change.
-  virtual void StartServices(
-      ServicesStatusObserver* services_status_observer) = 0;
-
-  virtual void StartGrpcHttpConnectionClient(
-      assistant_client::HttpConnectionFactory*) = 0;
-
-  // 1. Start a gRPC server which hosts the services that Libassistant depends
-  // on (maybe called by Libassistant) or receive events from Libassistant.
-  // 2. Register this client as a customer of Libassistant by sending
-  // RegisterCustomerRequest to Libassistant periodically. All supported
-  // services should be registered first before calling this method.
-  virtual bool StartGrpcServices() = 0;
-
-  virtual void AddExperimentIds(const std::vector<std::string>& exp_ids) = 0;
-
-  // Speaker Id Enrollment methods.
-  virtual void AddSpeakerIdEnrollmentEventObserver(
-      GrpcServicesObserver<OnSpeakerIdEnrollmentEventRequest>* observer) = 0;
-  virtual void RemoveSpeakerIdEnrollmentEventObserver(
-      GrpcServicesObserver<OnSpeakerIdEnrollmentEventRequest>* observer) = 0;
-  virtual void StartSpeakerIdEnrollment(
-      const StartSpeakerIdEnrollmentRequest& request) = 0;
-  virtual void CancelSpeakerIdEnrollment(
-      const CancelSpeakerIdEnrollmentRequest& request) = 0;
-  virtual void GetSpeakerIdEnrollmentInfo(
-      const GetSpeakerIdEnrollmentInfoRequest& request,
-      base::OnceCallback<void(bool user_model_exists)> on_done) = 0;
-
-  virtual void ResetAllDataAndShutdown() = 0;
-
-  // Display methods.
-  virtual void SendDisplayRequest(const OnDisplayRequestRequest& request) = 0;
-  virtual void AddDisplayEventObserver(
-      GrpcServicesObserver<OnAssistantDisplayEventRequest>* observer) = 0;
-
-  // Media methods.
-  virtual void ResumeCurrentStream() = 0;
-  virtual void PauseCurrentStream() = 0;
-  // Sets the current media status of media playing outside of libassistant.
-  // Setting external state will stop any internally playing media.
-  virtual void SetExternalPlaybackState(const MediaStatus& status_proto) = 0;
-  virtual void AddDeviceStateEventObserver(
-      GrpcServicesObserver<OnDeviceStateEventRequest>* observer) = 0;
-  virtual void AddMediaActionFallbackEventObserver(
-      GrpcServicesObserver<OnMediaActionFallbackEventRequest>* observer) = 0;
-
-  // Conversation methods.
-  virtual void SendVoicelessInteraction(
-      const ::assistant::api::Interaction& interaction,
-      const std::string& description,
-      const ::assistant::api::VoicelessOptions& options,
-      base::OnceCallback<void(bool)> on_done) = 0;
-  virtual void RegisterActionModule(
-      assistant_client::ActionModule* action_module) = 0;
-  virtual void StartVoiceInteraction() = 0;
-  virtual void StopAssistantInteraction(bool cancel_conversation) = 0;
-  virtual void AddConversationStateEventObserver(
-      GrpcServicesObserver<OnConversationStateEventRequest>* observer) = 0;
-
-  // Settings-related functionality during bootup:
-  virtual void SetAuthenticationInfo(const AuthTokens& tokens) = 0;
-  virtual void SetInternalOptions(const std::string& locale,
-                                  bool spoken_feedback_enabled) = 0;
-
-  // Settings-related functionality after fully started:
-  virtual void UpdateAssistantSettings(
-      const ::assistant::ui::SettingsUiUpdate& settings,
-      const std::string& user_id,
-      base::OnceCallback<
-          void(const ::assistant::api::UpdateAssistantSettingsResponse&)>
-          on_done) = 0;
-  virtual void GetAssistantSettings(
-      const ::assistant::ui::SettingsUiSelector& selector,
-      const std::string& user_id,
-      base::OnceCallback<void(
-          const ::assistant::api::GetAssistantSettingsResponse&)> on_done) = 0;
-  virtual void SetLocaleOverride(const std::string& locale) = 0;
-  virtual std::string GetDeviceId() = 0;
-
-  // Audio-related functionality:
-  // Enables or disables audio input pipeline.
-  virtual void EnableListening(bool listening_enabled) = 0;
-
-  // Alarm/timer-related functionality:
-  // Adds extra time to the timer.
-  virtual void AddTimeToTimer(const std::string& id,
-                              const base::TimeDelta& duration) = 0;
-  // Pauses the specified timer. This will be a no-op if the |timer_id| is
-  // invalid.
-  virtual void PauseTimer(const std::string& timer_id) = 0;
-  // Removes and cancels the timer.
-  virtual void RemoveTimer(const std::string& timer_id) = 0;
-  // Resumes the specified timer (expected to be in paused state).
-  virtual void ResumeTimer(const std::string& timer_id) = 0;
-  // Returns the list of all currently scheduled, ringing or paused timers in
-  // the callback.
-  virtual void GetTimers(
-      base::OnceCallback<void(const std::vector<assistant::AssistantTimer>&)>
-          on_done) = 0;
-
-  // Registers |observer| to get notified on any alarm/timer status change.
-  virtual void AddAlarmTimerEventObserver(
-      GrpcServicesObserver<::assistant::api::OnAlarmTimerEventRequest>*
-          observer) = 0;
-
-  // Will not return nullptr.
-  assistant_client::AssistantManager* assistant_manager() {
-    return assistant_manager_.get();
-  }
-
-  // Creates an instance of AssistantClient.
-  static std::unique_ptr<AssistantClient> Create(
-      std::unique_ptr<assistant_client::AssistantManager> assistant_manager);
-
- protected:
-  void ResetAssistantManager();
-
- private:
-  std::unique_ptr<assistant_client::AssistantManager> assistant_manager_;
-};
-
-}  // namespace ash::libassistant
-
-namespace base {
-
-template <>
-struct ScopedObservationTraits<
-    ash::libassistant::AssistantClient,
-    ash::libassistant::GrpcServicesObserver<
-        ::assistant::api::OnSpeakerIdEnrollmentEventRequest>> {
-  static void AddObserver(
-      ash::libassistant::AssistantClient* source,
-      ash::libassistant::GrpcServicesObserver<
-          ::assistant::api::OnSpeakerIdEnrollmentEventRequest>* observer) {
-    source->AddSpeakerIdEnrollmentEventObserver(observer);
-  }
-  static void RemoveObserver(
-      ash::libassistant::AssistantClient* source,
-      ash::libassistant::GrpcServicesObserver<
-          ::assistant::api::OnSpeakerIdEnrollmentEventRequest>* observer) {
-    source->RemoveSpeakerIdEnrollmentEventObserver(observer);
-  }
-};
-
-}  // namespace base
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_ASSISTANT_CLIENT_H_
diff --git a/chromeos/ash/services/libassistant/grpc/assistant_client_impl.cc b/chromeos/ash/services/libassistant/grpc/assistant_client_impl.cc
deleted file mode 100644
index 1b3f917..0000000
--- a/chromeos/ash/services/libassistant/grpc/assistant_client_impl.cc
+++ /dev/null
@@ -1,474 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/assistant_client_impl.h"
-
-#include <memory>
-#include <string>
-
-#include "base/functional/bind.h"
-#include "base/functional/callback.h"
-#include "base/logging.h"
-#include "base/system/sys_info.h"
-#include "base/time/time.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/action_service.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_libassistant_client.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_util.h"
-#include "chromeos/ash/services/libassistant/grpc/services_status_observer.h"
-#include "chromeos/ash/services/libassistant/grpc/utils/media_status_utils.h"
-#include "chromeos/ash/services/libassistant/grpc/utils/timer_utils.h"
-#include "chromeos/ash/services/libassistant/public/cpp/assistant_timer.h"
-#include "chromeos/assistant/internal/grpc_transport/request_utils.h"
-#include "chromeos/assistant/internal/internal_constants.h"
-#include "chromeos/assistant/internal/internal_util.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/proto/shared/proto/settings_ui.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/alarm_timer_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/audio_utils_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/bootup_settings_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/config_settings_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/device_state_event.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/display_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/experiment_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/query_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/speaker_id_enrollment_interface.pb.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-using ::assistant::api::EnableListeningRequest;
-using ::assistant::api::EnableListeningResponse;
-using ::assistant::api::GetAssistantSettingsResponse;
-using ::assistant::api::OnAlarmTimerEventRequest;
-using ::assistant::api::OnDeviceStateEventRequest;
-using ::assistant::api::OnSpeakerIdEnrollmentEventRequest;
-using ::assistant::api::SetLocaleOverrideRequest;
-using ::assistant::api::SetLocaleOverrideResponse;
-using ::assistant::api::UpdateAssistantSettingsResponse;
-using ::assistant::ui::SettingsUiUpdate;
-
-// Rpc call config constants.
-constexpr int kMaxRpcRetries = 5;
-constexpr int kDefaultTimeoutMs = 5000;
-
-// Interaction related calls has longer timeout.
-constexpr int kAssistantInteractionDefaultTimeoutMs = 20000;
-
-const StateConfig kDefaultStateConfig =
-    StateConfig{kMaxRpcRetries, kDefaultTimeoutMs};
-
-const StateConfig kInteractionDefaultStateConfig =
-    StateConfig{kMaxRpcRetries, kAssistantInteractionDefaultTimeoutMs};
-
-#define LOG_GRPC_STATUS(level, status, func_name)                \
-  if (status.ok()) {                                             \
-    DVLOG(level) << func_name << " succeed with ok status.";     \
-  } else {                                                       \
-    LOG(ERROR) << func_name << " failed with a non-ok status.";  \
-    LOG(ERROR) << "Error code: " << status.error_code()          \
-               << ", error message: " << status.error_message(); \
-  }
-
-// Creates a callback for logging the request status. The callback will
-// ignore the returned response as it either doesn't contain any information
-// we need or is empty.
-template <typename Response>
-base::OnceCallback<void(const grpc::Status& status, const Response&)>
-GetLoggingCallback(const std::string& request_name) {
-  return base::BindOnce(
-      [](const std::string& request_name, const grpc::Status& status,
-         const Response& ignored) { LOG_GRPC_STATUS(2, status, request_name); },
-      request_name);
-}
-
-}  // namespace
-
-AssistantClientImpl::AssistantClientImpl(
-    std::unique_ptr<assistant_client::AssistantManager> assistant_manager,
-    const std::string& libassistant_service_address,
-    const std::string& assistant_service_address)
-    : AssistantClient(std::move(assistant_manager)),
-      grpc_services_(libassistant_service_address, assistant_service_address),
-      libassistant_client_(grpc_services_.GrpcLibassistantClient()) {}
-
-AssistantClientImpl::~AssistantClientImpl() {
-  // The following sequence is used to prevent unnecessary heart beats from
-  // being sent during shutdown:
-  // 1. Stop other LibAssistant gRPC services by destroying the
-  // `assistant_manager_`.
-  // 2. Stop assistant_grpc service by destroying `grpc_services_`.
-  ResetAssistantManager();
-}
-
-void AssistantClientImpl::StartServices(
-    ServicesStatusObserver* services_status_observer) {
-  grpc_services_.GetServicesStatusProvider().AddObserver(
-      services_status_observer);
-
-  StartGrpcServices();
-}
-
-bool AssistantClientImpl::StartGrpcServices() {
-  return grpc_services_.Start();
-}
-
-void AssistantClientImpl::StartGrpcHttpConnectionClient(
-    assistant_client::HttpConnectionFactory* factory) {
-  grpc_services_.StartGrpcHttpConnectionClient(factory);
-}
-
-void AssistantClientImpl::AddExperimentIds(
-    const std::vector<std::string>& exp_ids) {
-  ::assistant::api::UpdateExperimentIdsRequest request;
-  request.set_operation(
-      ::assistant::api::UpdateExperimentIdsRequest_Operation_MERGE);
-  *request.mutable_experiment_ids() = {exp_ids.begin(), exp_ids.end()};
-
-  libassistant_client_->CallServiceMethod(
-      request,
-      GetLoggingCallback<::assistant::api::UpdateExperimentIdsResponse>(
-          /*request_name=*/__func__),
-      kDefaultStateConfig);
-}
-
-void AssistantClientImpl::AddSpeakerIdEnrollmentEventObserver(
-    GrpcServicesObserver<OnSpeakerIdEnrollmentEventRequest>* observer) {
-  grpc_services_.AddSpeakerIdEnrollmentEventObserver(observer);
-}
-
-void AssistantClientImpl::RemoveSpeakerIdEnrollmentEventObserver(
-    GrpcServicesObserver<OnSpeakerIdEnrollmentEventRequest>* observer) {
-  grpc_services_.RemoveSpeakerIdEnrollmentEventObserver(observer);
-}
-
-void AssistantClientImpl::StartSpeakerIdEnrollment(
-    const StartSpeakerIdEnrollmentRequest& request) {
-  libassistant_client_->CallServiceMethod(
-      request,
-      GetLoggingCallback<::assistant::api::StartSpeakerIdEnrollmentResponse>(
-          /*request_name=*/__func__),
-      kDefaultStateConfig);
-}
-
-void AssistantClientImpl::CancelSpeakerIdEnrollment(
-    const CancelSpeakerIdEnrollmentRequest& request) {
-  libassistant_client_->CallServiceMethod(
-      request,
-      GetLoggingCallback<::assistant::api::CancelSpeakerIdEnrollmentResponse>(
-          /*request_name=*/__func__),
-      kDefaultStateConfig);
-}
-
-void AssistantClientImpl::GetSpeakerIdEnrollmentInfo(
-    const GetSpeakerIdEnrollmentInfoRequest& request,
-    base::OnceCallback<void(bool user_model_exists)> on_done) {
-  libassistant_client_->CallServiceMethod(
-      request,
-      base::BindOnce(
-          [](base::OnceCallback<void(bool user_model_exists)> on_done,
-             const grpc::Status& status,
-             const ::assistant::api::GetSpeakerIdEnrollmentInfoResponse&
-                 response) {
-            bool has_model = false;
-            //  `response` could have an error field.
-            // Treat any error as no existing model.
-            if (response.has_user_model_status_response()) {
-              has_model =
-                  response.user_model_status_response().user_model_exists();
-            }
-            std::move(on_done).Run(has_model);
-          },
-          std::move(on_done)),
-      kDefaultStateConfig);
-}
-
-void AssistantClientImpl::ResetAllDataAndShutdown() {
-  assistant_manager()->ResetAllDataAndShutdown();
-}
-
-void AssistantClientImpl::SendDisplayRequest(
-    const OnDisplayRequestRequest& request) {
-  libassistant_client_->CallServiceMethod(
-      request,
-      GetLoggingCallback<::assistant::api::OnDisplayRequestResponse>(
-          /*request_name=*/__func__),
-      kInteractionDefaultStateConfig);
-}
-
-void AssistantClientImpl::AddDisplayEventObserver(
-    GrpcServicesObserver<OnAssistantDisplayEventRequest>* observer) {
-  grpc_services_.AddAssistantDisplayEventObserver(observer);
-}
-
-void AssistantClientImpl::ResumeCurrentStream() {
-  assistant_manager()->GetMediaManager()->Resume();
-}
-
-void AssistantClientImpl::PauseCurrentStream() {
-  assistant_manager()->GetMediaManager()->Pause();
-}
-
-void AssistantClientImpl::SetExternalPlaybackState(
-    const MediaStatus& status_proto) {
-  assistant_client::MediaStatus media_status;
-  ConvertMediaStatusToV1FromV2(status_proto, &media_status);
-  assistant_manager()->GetMediaManager()->SetExternalPlaybackState(
-      media_status);
-}
-
-void AssistantClientImpl::AddDeviceStateEventObserver(
-    GrpcServicesObserver<OnDeviceStateEventRequest>* observer) {
-  grpc_services_.AddDeviceStateEventObserver(observer);
-}
-
-void AssistantClientImpl::AddMediaActionFallbackEventObserver(
-    GrpcServicesObserver<OnMediaActionFallbackEventRequest>* observer) {
-  grpc_services_.AddMediaActionFallbackEventObserver(observer);
-}
-
-void AssistantClientImpl::SendVoicelessInteraction(
-    const ::assistant::api::Interaction& interaction,
-    const std::string& description,
-    const ::assistant::api::VoicelessOptions& options,
-    base::OnceCallback<void(bool)> on_done) {
-  ::assistant::api::SendQueryRequest request;
-  chromeos::libassistant::PopulateSendQueryRequest(interaction, description,
-                                                   options, &request);
-
-  libassistant_client_->CallServiceMethod(
-      request,
-      base::BindOnce(
-          [](base::OnceCallback<void(bool)> on_done, const grpc::Status& status,
-             const ::assistant::api::SendQueryResponse& response) {
-            std::move(on_done).Run(response.success());
-          },
-          std::move(on_done)),
-      kInteractionDefaultStateConfig);
-}
-
-void AssistantClientImpl::RegisterActionModule(
-    assistant_client::ActionModule* action_module) {
-  grpc_services_.GetActionService()->RegisterActionModule(action_module);
-}
-
-void AssistantClientImpl::StartVoiceInteraction() {
-  libassistant_client_->CallServiceMethod(
-      ::assistant::api::StartVoiceQueryRequest(),
-      GetLoggingCallback<::assistant::api::StartVoiceQueryResponse>(
-          /*request_name=*/__func__),
-      kInteractionDefaultStateConfig);
-}
-
-void AssistantClientImpl::StopAssistantInteraction(bool cancel_conversation) {
-  ::assistant::api::StopQueryRequest request;
-  request.set_type(::assistant::api::StopQueryRequest::ACTIVE_INTERNAL);
-  request.set_cancel_conversation(cancel_conversation);
-
-  libassistant_client_->CallServiceMethod(
-      request,
-      GetLoggingCallback<::assistant::api::StopQueryResponse>(
-          /*request_name=*/__func__),
-      kInteractionDefaultStateConfig);
-}
-
-void AssistantClientImpl::AddConversationStateEventObserver(
-    GrpcServicesObserver<OnConversationStateEventRequest>* observer) {
-  grpc_services_.AddConversationStateEventObserver(observer);
-}
-
-void AssistantClientImpl::SetAuthenticationInfo(const AuthTokens& tokens) {
-  ::assistant::api::SetAuthInfoRequest request;
-  // Each token exists of a [gaia_id, auth_token] tuple.
-  for (const auto& token : tokens) {
-    auto* proto = request.add_tokens();
-    proto->set_user_id(token.first);
-    proto->set_auth_token(token.second);
-  }
-
-  libassistant_client_->CallServiceMethod(
-      request,
-      GetLoggingCallback<::assistant::api::SetAuthInfoResponse>(
-          /*request_name=*/__func__),
-      kDefaultStateConfig);
-}
-
-void AssistantClientImpl::SetInternalOptions(const std::string& locale,
-                                             bool spoken_feedback_enabled) {
-  auto internal_options = chromeos::assistant::CreateInternalOptionsProto(
-      locale, spoken_feedback_enabled);
-
-  ::assistant::api::SetInternalOptionsRequest request;
-  *request.mutable_internal_options() = std::move(internal_options);
-
-  // SetInternalOptions request causes AssistantManager reconfiguration.
-  constexpr int kAssistantReconfigureInternalDefaultTimeoutMs = 20000;
-  StateConfig custom_config(kMaxRpcRetries,
-                            kAssistantReconfigureInternalDefaultTimeoutMs);
-  libassistant_client_->CallServiceMethod(
-      request,
-      GetLoggingCallback<::assistant::api::SetInternalOptionsResponse>(
-          /*request_name=*/__func__),
-      custom_config);
-}
-
-void AssistantClientImpl::UpdateAssistantSettings(
-    const ::assistant::ui::SettingsUiUpdate& update,
-    const std::string& user_id,
-    base::OnceCallback<void(
-        const ::assistant::api::UpdateAssistantSettingsResponse&)> on_done) {
-  using ::assistant::api::UpdateAssistantSettingsRequest;
-  using ::assistant::api::UpdateAssistantSettingsResponse;
-
-  UpdateAssistantSettingsRequest request;
-  // Sets obfuscated gaia id.
-  request.set_user_id(user_id);
-  // Sets the update to be applied to the settings.
-  *request.mutable_update_settings_ui_request()->mutable_settings_update() =
-      update;
-
-  auto cb = base::BindOnce(
-      [](base::OnceCallback<void(const UpdateAssistantSettingsResponse&)>
-             on_done,
-         const grpc::Status& status,
-         const UpdateAssistantSettingsResponse& response) {
-        LOG_GRPC_STATUS(/*level=*/2, status, "UpdateAssistantSettings")
-        std::move(on_done).Run(response);
-      },
-      std::move(on_done));
-  libassistant_client_->CallServiceMethod(request, std::move(cb),
-                                          kDefaultStateConfig);
-}
-
-void AssistantClientImpl::GetAssistantSettings(
-    const ::assistant::ui::SettingsUiSelector& selector,
-    const std::string& user_id,
-    base::OnceCallback<
-        void(const ::assistant::api::GetAssistantSettingsResponse&)> on_done) {
-  using ::assistant::api::GetAssistantSettingsRequest;
-  using ::assistant::api::GetAssistantSettingsResponse;
-
-  GetAssistantSettingsRequest request;
-  *request.mutable_get_settings_ui_request()->mutable_selector() = selector;
-  request.set_user_id(user_id);
-
-  auto cb = base::BindOnce(
-      [](base::OnceCallback<void(const GetAssistantSettingsResponse&)> on_done,
-         const grpc::Status& status,
-         const GetAssistantSettingsResponse& response) {
-        LOG_GRPC_STATUS(/*level=*/2, status, "GetAssistantSettings")
-        std::move(on_done).Run(response);
-      },
-      std::move(on_done));
-
-  libassistant_client_->CallServiceMethod(request, std::move(cb),
-                                          kDefaultStateConfig);
-}
-
-void AssistantClientImpl::SetLocaleOverride(const std::string& locale) {
-  SetLocaleOverrideRequest request;
-  request.set_locale(locale);
-
-  libassistant_client_->CallServiceMethod(
-      request, GetLoggingCallback<SetLocaleOverrideResponse>(__func__),
-      kDefaultStateConfig);
-}
-
-std::string AssistantClientImpl::GetDeviceId() {
-  return assistant_manager()->GetDeviceId();
-}
-
-void AssistantClientImpl::EnableListening(bool listening_enabled) {
-  EnableListeningRequest request;
-  request.set_enable(listening_enabled);
-
-  libassistant_client_->CallServiceMethod(
-      request, GetLoggingCallback<EnableListeningResponse>(__func__),
-      kDefaultStateConfig);
-}
-
-void AssistantClientImpl::AddTimeToTimer(const std::string& id,
-                                         const base::TimeDelta& duration) {
-  ::assistant::api::AddTimeToTimerRequest request;
-  request.set_timer_id(id);
-  request.set_extra_time_seconds(duration.InSeconds());
-  libassistant_client_->CallServiceMethod(
-      request,
-      GetLoggingCallback<::assistant::api::AddTimeToTimerResponse>(
-          /*request_name=*/__func__),
-      kDefaultStateConfig);
-}
-
-void AssistantClientImpl::PauseTimer(const std::string& timer_id) {
-  ::assistant::api::PauseTimerRequest request;
-  request.set_timer_id(timer_id);
-  libassistant_client_->CallServiceMethod(
-      request,
-      GetLoggingCallback<::assistant::api::PauseTimerResponse>(
-          /*request_name=*/__func__),
-      kDefaultStateConfig);
-}
-
-void AssistantClientImpl::RemoveTimer(const std::string& timer_id) {
-  ::assistant::api::RemoveTimerRequest request;
-  request.set_timer_id(timer_id);
-  libassistant_client_->CallServiceMethod(
-      request,
-      GetLoggingCallback<::assistant::api::RemoveTimerResponse>(
-          /*request_name=*/__func__),
-      kDefaultStateConfig);
-}
-
-void AssistantClientImpl::ResumeTimer(const std::string& timer_id) {
-  ::assistant::api::ResumeTimerRequest request;
-  request.set_timer_id(timer_id);
-  libassistant_client_->CallServiceMethod(
-      request,
-      GetLoggingCallback<::assistant::api::ResumeTimerResponse>(
-          /*request_name=*/__func__),
-      kDefaultStateConfig);
-}
-
-void AssistantClientImpl::GetTimers(
-    base::OnceCallback<void(const std::vector<assistant::AssistantTimer>&)>
-        on_done) {
-  ::assistant::api::GetTimersResponse response;
-
-  libassistant_client_->CallServiceMethod(
-      ::assistant::api::GetTimersRequest(),
-      base::BindOnce(
-          [](base::OnceCallback<void(
-                 const std::vector<assistant::AssistantTimer>&)> on_done,
-             const grpc::Status& status,
-             const ::assistant::api::GetTimersResponse& response) {
-            if (status.ok()) {
-              std::move(on_done).Run(
-                  ConstructAssistantTimersFromProto(response.timers()));
-            } else {
-              std::move(on_done).Run(/*timers=*/{});
-            }
-          },
-          std::move(on_done)),
-      kDefaultStateConfig);
-}
-
-void AssistantClientImpl::AddAlarmTimerEventObserver(
-    GrpcServicesObserver<::assistant::api::OnAlarmTimerEventRequest>*
-        observer) {
-  grpc_services_.AddAlarmTimerEventObserver(observer);
-}
-
-// static
-std::unique_ptr<AssistantClient> AssistantClient::Create(
-    std::unique_ptr<assistant_client::AssistantManager> assistant_manager) {
-  const bool is_chromeos_device = base::SysInfo::IsRunningOnChromeOS();
-  return std::make_unique<AssistantClientImpl>(
-      std::move(assistant_manager),
-      GetLibassistantServiceAddress(is_chromeos_device),
-      GetAssistantServiceAddress(is_chromeos_device));
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/assistant_client_impl.h b/chromeos/ash/services/libassistant/grpc/assistant_client_impl.h
deleted file mode 100644
index 5a129c81..0000000
--- a/chromeos/ash/services/libassistant/grpc/assistant_client_impl.h
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_ASSISTANT_CLIENT_IMPL_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_ASSISTANT_CLIENT_IMPL_H_
-
-#include <memory>
-#include <string>
-
-#include "base/functional/callback_forward.h"
-#include "base/memory/raw_ref.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/grpc_services_initializer.h"
-#include "chromeos/ash/services/libassistant/grpc/services_status_provider.h"
-
-namespace ash::libassistant {
-
-class GrpcLibassistantClient;
-class ServicesStatusObserver;
-
-class AssistantClientImpl : public AssistantClient {
- public:
-  AssistantClientImpl(
-      std::unique_ptr<assistant_client::AssistantManager> assistant_manager,
-      const std::string& libassistant_service_address,
-      const std::string& assistant_service_address);
-
-  ~AssistantClientImpl() override;
-
-  // AssistantClient:
-  void StartServices(ServicesStatusObserver* services_status_observer) override;
-  bool StartGrpcServices() override;
-  void StartGrpcHttpConnectionClient(
-      assistant_client::HttpConnectionFactory*) override;
-  void AddExperimentIds(const std::vector<std::string>& exp_ids) override;
-  void AddSpeakerIdEnrollmentEventObserver(
-      GrpcServicesObserver<OnSpeakerIdEnrollmentEventRequest>* observer)
-      override;
-  void RemoveSpeakerIdEnrollmentEventObserver(
-      GrpcServicesObserver<OnSpeakerIdEnrollmentEventRequest>* observer)
-      override;
-  void StartSpeakerIdEnrollment(
-      const StartSpeakerIdEnrollmentRequest& request) override;
-  void CancelSpeakerIdEnrollment(
-      const CancelSpeakerIdEnrollmentRequest& request) override;
-  void GetSpeakerIdEnrollmentInfo(
-      const GetSpeakerIdEnrollmentInfoRequest& request,
-      base::OnceCallback<void(bool user_model_exists)> on_done) override;
-  void ResetAllDataAndShutdown() override;
-  void SendDisplayRequest(const OnDisplayRequestRequest& request) override;
-  void AddDisplayEventObserver(
-      GrpcServicesObserver<OnAssistantDisplayEventRequest>* observer) override;
-  void ResumeCurrentStream() override;
-  void PauseCurrentStream() override;
-  void SetExternalPlaybackState(const MediaStatus& status_proto) override;
-  void AddDeviceStateEventObserver(
-      GrpcServicesObserver<OnDeviceStateEventRequest>* observer) override;
-  void AddMediaActionFallbackEventObserver(
-      GrpcServicesObserver<OnMediaActionFallbackEventRequest>* observer)
-      override;
-  void SendVoicelessInteraction(
-      const ::assistant::api::Interaction& interaction,
-      const std::string& description,
-      const ::assistant::api::VoicelessOptions& options,
-      base::OnceCallback<void(bool)> on_done) override;
-  void RegisterActionModule(
-      assistant_client::ActionModule* action_module) override;
-  void StartVoiceInteraction() override;
-  void StopAssistantInteraction(bool cancel_conversation) override;
-  void AddConversationStateEventObserver(
-      GrpcServicesObserver<OnConversationStateEventRequest>* observer) override;
-
-  // Settings-related setters:
-  void SetAuthenticationInfo(const AuthTokens& tokens) override;
-  void SetInternalOptions(const std::string& locale,
-                          bool spoken_feedback_enabled) override;
-  void UpdateAssistantSettings(
-      const ::assistant::ui::SettingsUiUpdate& update,
-      const std::string& user_id,
-      base::OnceCallback<void(
-          const ::assistant::api::UpdateAssistantSettingsResponse&)> on_done)
-      override;
-  void GetAssistantSettings(
-      const ::assistant::ui::SettingsUiSelector& selector,
-      const std::string& user_id,
-      base::OnceCallback<
-          void(const ::assistant::api::GetAssistantSettingsResponse&)> on_done)
-      override;
-  void SetLocaleOverride(const std::string& locale) override;
-  std::string GetDeviceId() override;
-
-  // Audio-related functionality:
-  void EnableListening(bool listening_enabled) override;
-
-  // Timer related:
-  void AddTimeToTimer(const std::string& id,
-                      const base::TimeDelta& duration) override;
-  void PauseTimer(const std::string& timer_id) override;
-  void RemoveTimer(const std::string& timer_id) override;
-  void ResumeTimer(const std::string& timer_id) override;
-  void GetTimers(
-      base::OnceCallback<void(const std::vector<assistant::AssistantTimer>&)>
-          on_done) override;
-  void AddAlarmTimerEventObserver(
-      GrpcServicesObserver<::assistant::api::OnAlarmTimerEventRequest>*
-          observer) override;
-
- private:
-  GrpcServicesInitializer grpc_services_;
-
-  // Entry point for Libassistant V2 APIs, through which V2 methods can be
-  // invoked. Created and owned by |GrpcServicesInitializer|.
-  const raw_ref<GrpcLibassistantClient> libassistant_client_;
-
-  // Invoked when all LibAssistant services are ready to query.
-  base::OnceClosure services_ready_callback_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_ASSISTANT_CLIENT_IMPL_H_
diff --git a/chromeos/ash/services/libassistant/grpc/assistant_client_observer.h b/chromeos/ash/services/libassistant/grpc/assistant_client_observer.h
deleted file mode 100644
index 0d9d773..0000000
--- a/chromeos/ash/services/libassistant/grpc/assistant_client_observer.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_ASSISTANT_CLIENT_OBSERVER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_ASSISTANT_CLIENT_OBSERVER_H_
-
-#include "base/component_export.h"
-#include "base/observer_list_types.h"
-
-namespace ash::libassistant {
-
-class AssistantClient;
-
-// Observer informed when the |AssistantClient| is created or destroyed.
-// This is used internally in our mojom service implementation, to allow our
-// different components to know when they can use the Libassistant objects.
-class AssistantClientObserver : public base::CheckedObserver {
- public:
-  // Called when the |AssistantClient| has been created, but not started yet.
-  // The pointers are guaranteed to remain valid until after
-  // OnDestroyingAssistantClient() is called.
-  virtual void OnAssistantClientCreated(AssistantClient* assistant_client) {}
-
-  // Called when Start() has been called on the |AssistantClient|.  The
-  // pointers are guaranteed to remain valid until after
-  // OnDestroyingAssistantClient() is called.
-  virtual void OnAssistantClientStarted(AssistantClient* assistant_client) {}
-
-  // Called when |AssistantClient| has finished its start logic and is ready
-  // to handle queries.
-  // The pointers are guaranteed to remain valid until after
-  // OnDestroyingAssistantClient() is called.
-  virtual void OnAssistantClientRunning(AssistantClient* assistant_client) {}
-
-  // Called just before the |AssistantClient| will be destroyed. They should
-  // not be used anymore after this has been called. The pointers passed in are
-  // guaranteed to be the same as passed to the last call to
-  // OnAssistantClientCreated() (and are just passed in again for the
-  // implementer's convenience).
-  virtual void OnDestroyingAssistantClient(AssistantClient* assistant_client) {}
-
-  // Called when the |AssistantClient| has been destroyed.
-  virtual void OnAssistantClientDestroyed() {}
-
- protected:
-  ~AssistantClientObserver() override = default;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_ASSISTANT_CLIENT_OBSERVER_H_
diff --git a/chromeos/ash/services/libassistant/grpc/async_service_driver.h b/chromeos/ash/services/libassistant/grpc/async_service_driver.h
deleted file mode 100644
index e93633c6..0000000
--- a/chromeos/ash/services/libassistant/grpc/async_service_driver.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_ASYNC_SERVICE_DRIVER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_ASYNC_SERVICE_DRIVER_H_
-
-#include "base/check.h"
-#include "base/logging.h"
-#include "base/memory/raw_ptr.h"
-#include "third_party/grpc/source/include/grpcpp/server_builder.h"
-
-namespace ash::libassistant {
-
-// Base class for asynchronous RPC drivers. Implementations of async drivers
-// for gRPC services exposed by libassistant should derive from this class.
-class AsyncServiceDriver {
- public:
-  // |server_builder| should not be nullptr.
-  explicit AsyncServiceDriver(grpc::ServerBuilder* server_builder)
-      : server_builder_(server_builder) {
-    DCHECK(server_builder);
-  }
-
-  virtual ~AsyncServiceDriver() = default;
-
-  virtual void StartCQ(grpc::ServerCompletionQueue* cq) = 0;
-
- protected:
-  // Owned by |GrpcServicesInitializer|.
-  raw_ptr<grpc::ServerBuilder> server_builder_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_ASYNC_SERVICE_DRIVER_H_
diff --git a/chromeos/ash/services/libassistant/grpc/external_services/BUILD.gn b/chromeos/ash/services/libassistant/grpc/external_services/BUILD.gn
deleted file mode 100644
index a92bd906..0000000
--- a/chromeos/ash/services/libassistant/grpc/external_services/BUILD.gn
+++ /dev/null
@@ -1,74 +0,0 @@
-# Copyright 2021 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-assert(is_chromeos, "Non ChromeOS builds must not depend on //chromeos/ash")
-
-source_set("grpc_services_initializer") {
-  sources = [
-    "action_args.cc",
-    "action_args.h",
-    "action_service.cc",
-    "action_service.h",
-    "event_handler_driver.cc",
-    "event_handler_driver.h",
-    "grpc_services_initializer.cc",
-    "grpc_services_initializer.h",
-  ]
-
-  deps = [
-    ":customer_registration_client",
-    ":grpc_services_observer",
-    ":heartbeat_event_handler_driver",
-    "//base",
-    "//chromeos/ash/services/libassistant:callback_utils",
-    "//chromeos/ash/services/libassistant/grpc:grpc_client",
-    "//chromeos/ash/services/libassistant/grpc:grpc_service",
-    "//chromeos/ash/services/libassistant/grpc:grpc_util",
-    "//chromeos/ash/services/libassistant/grpc:http_connection_client",
-    "//chromeos/ash/services/libassistant/grpc:libassistant_client",
-    "//chromeos/assistant/internal",
-    "//chromeos/assistant/internal:libassistant_shared_headers",
-    "//third_party/grpc:grpc++",
-  ]
-}
-
-source_set("grpc_services_observer") {
-  sources = [ "grpc_services_observer.h" ]
-
-  deps = [ "//base" ]
-}
-
-source_set("customer_registration_client") {
-  sources = [
-    "customer_registration_client.cc",
-    "customer_registration_client.h",
-  ]
-
-  deps = [
-    "//base",
-    "//chromeos/ash/services/libassistant/grpc:grpc_client",
-    "//chromeos/ash/services/libassistant/grpc:libassistant_client",
-    "//chromeos/assistant/internal/proto:assistant",
-    "//chromeos/assistant/internal/proto:assistant_grpc",
-  ]
-}
-
-source_set("heartbeat_event_handler_driver") {
-  sources = [
-    "heartbeat_event_handler_driver.cc",
-    "heartbeat_event_handler_driver.h",
-  ]
-
-  public_deps = [
-    "//chromeos/assistant/internal/proto:assistant",
-    "//chromeos/assistant/internal/proto:assistant_grpc",
-  ]
-
-  deps = [
-    ":grpc_services_observer",
-    "//base",
-    "//chromeos/ash/services/libassistant/grpc:grpc_service",
-    "//third_party/grpc:grpc++",
-  ]
-}
diff --git a/chromeos/ash/services/libassistant/grpc/external_services/action_args.cc b/chromeos/ash/services/libassistant/grpc/external_services/action_args.cc
deleted file mode 100644
index b449c2bd..0000000
--- a/chromeos/ash/services/libassistant/grpc/external_services/action_args.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/external_services/action_args.h"
-
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/action_interface.pb.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-bool GetProtobufFromMap(const google::protobuf::RepeatedPtrField<
-                            ::assistant::api::ProtobufMapEntry>& map,
-                        const std::string& key,
-                        const std::string& type,
-                        std::string* protobuf_data) {
-  for (const auto& entry : map) {
-    if (!entry.has_value() || !entry.has_key() || key != entry.key())
-      continue;
-    const auto& pb = entry.value();
-    if (type != pb.protobuf_type())
-      continue;
-    *protobuf_data = pb.protobuf_data();
-    return true;
-  }
-  return false;
-}
-
-}  // namespace
-
-ActionArgs::ActionArgs(const ::assistant::api::HandleActionRequest& request)
-    : ActionArgs(request.conversation_id(),
-                 request.user_id(),
-                 request.event_id(),
-                 request.interaction_id(),
-                 request.args()) {}
-
-ActionArgs::ActionArgs(const std::string& conversation_id,
-                       const std::string& user_id,
-                       const std::string& event_id,
-                       int32_t interaction_id,
-                       ::assistant::api::ClientOp::Args client_op_args)
-    : conversation_id_(conversation_id),
-      user_id_(user_id),
-      event_id_(event_id),
-      interaction_id_(interaction_id),
-      client_op_args_(client_op_args) {}
-
-ActionArgs::~ActionArgs() = default;
-
-bool ActionArgs::GetProtobuf(const std::string& key,
-                             const std::string& type,
-                             std::string* protobuf_data) const {
-  return GetProtobufFromMap(client_op_args_.arg(), key, type, protobuf_data);
-}
-
-std::string ActionArgs::GetConversationId() const {
-  return conversation_id_;
-}
-
-std::string ActionArgs::GetUserId() const {
-  return user_id_;
-}
-
-std::string ActionArgs::GetEventId() const {
-  return event_id_;
-}
-
-int32_t ActionArgs::GetInteractionId() const {
-  return interaction_id_;
-}
-
-assistant_client::ActionModule::Args* ActionArgs::Clone() const {
-  return new ActionArgs(conversation_id_, user_id_, event_id_, interaction_id_,
-                        client_op_args_);
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/external_services/action_args.h b/chromeos/ash/services/libassistant/grpc/external_services/action_args.h
deleted file mode 100644
index a605818..0000000
--- a/chromeos/ash/services/libassistant/grpc/external_services/action_args.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_ACTION_ARGS_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_ACTION_ARGS_H_
-
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/proto/shared/proto/client_op.pb.h"
-
-namespace assistant {
-namespace api {
-class HandleActionRequest;
-}  // namespace api
-}  // namespace assistant
-
-namespace ash::libassistant {
-
-class ActionArgs : public assistant_client::ActionModule::Args {
- public:
-  explicit ActionArgs(const ::assistant::api::HandleActionRequest& request);
-  ActionArgs(const std::string& conversation_id,
-             const std::string& user_id,
-             const std::string& event_id,
-             int32_t interaction_id,
-             ::assistant::api::ClientOp::Args client_op_args);
-  ~ActionArgs() override;
-
-  // assistant_client::ActionModule::Args:
-  bool GetProtobuf(const std::string& key,
-                   const std::string& type,
-                   std::string* protobuf_data) const override;
-  assistant_client::ActionModule::Args* Clone() const override;
-  std::string GetConversationId() const override;
-  std::string GetUserId() const override;
-  std::string GetEventId() const override;
-  int32_t GetInteractionId() const override;
-
- private:
-  std::string conversation_id_;
-  std::string user_id_;
-  std::string event_id_;
-  int32_t interaction_id_ = -1;
-  ::assistant::api::ClientOp::Args client_op_args_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_ACTION_ARGS_H_
diff --git a/chromeos/ash/services/libassistant/grpc/external_services/action_service.cc b/chromeos/ash/services/libassistant/grpc/external_services/action_service.cc
deleted file mode 100644
index d06e2b2..0000000
--- a/chromeos/ash/services/libassistant/grpc/external_services/action_service.cc
+++ /dev/null
@@ -1,288 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/external_services/action_service.h"
-
-#include "base/memory/ptr_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/libassistant/callback_utils.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/action_args.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_libassistant_client.h"
-#include "chromeos/assistant/internal/grpc_transport/request_utils.h"
-#include "chromeos/assistant/internal/internal_constants.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-std::string GetActionId(const ::assistant::api::HandleActionRequest* request) {
-  return request->conversation_id() + ":" +
-         base::NumberToString(request->interaction_id());
-}
-
-}  // namespace
-
-ActionService::ActionService(::grpc::ServerBuilder* server_builder,
-                             GrpcLibassistantClient* libassistant_client,
-                             const std::string& assistant_service_address)
-    : AsyncServiceDriver(server_builder),
-      libassistant_client_(libassistant_client),
-      assistant_service_address_(assistant_service_address),
-      task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {
-  DCHECK(server_builder);
-  DCHECK(libassistant_client_);
-
-  server_builder_->RegisterService(&service_);
-}
-
-ActionService::~ActionService() = default;
-
-void ActionService::RegisterActionModule(
-    assistant_client::ActionModule* action_module) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(!action_module_);
-
-  action_module_ = action_module;
-  StartRegistration();
-}
-
-void ActionService::StartRegistration() {
-  ::assistant::api::RegisterActionModuleRequest request;
-  for (const auto& action : action_module_->GetSupportedActions()) {
-    chromeos::libassistant::PopulateRegisterActionModuleRequest(action,
-                                                                &request);
-  }
-
-  auto* action_handler = request.mutable_action_handler();
-  action_handler->set_server_address(assistant_service_address_);
-  action_handler->set_service_name(chromeos::assistant::kActionServiceName);
-  action_handler->set_handler_method(
-      chromeos::assistant::kHandleActionMethodName);
-
-  auto* context_provider = request.mutable_context_provider();
-  context_provider->set_server_address(assistant_service_address_);
-  context_provider->set_service_name(chromeos::assistant::kActionServiceName);
-  context_provider->set_handler_method(
-      chromeos::assistant::kGetContextMethodName);
-
-  constexpr int kMaxRegisterRetry = 3;
-  constexpr int kRegisterTimeoutInMs = 2000;
-  StateConfig config;
-  config.max_retries = kMaxRegisterRetry;
-  config.timeout_in_ms = kRegisterTimeoutInMs;
-
-  libassistant_client_->CallServiceMethod(
-      request,
-      base::BindOnce(&ActionService::OnRegistrationDone,
-                     weak_factory_.GetWeakPtr()),
-      std::move(config));
-}
-
-void ActionService::OnRegistrationDone(
-    const ::grpc::Status& status,
-    const ::assistant::api::RegisterActionModuleResponse& response) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (!status.ok()) {
-    LOG(ERROR) << "Registration failed with status: " << status.error_code()
-               << " and message: " << status.error_message();
-    return;
-  }
-
-  bool has_failure = false;
-  for (const auto& result : response.register_result()) {
-    DVLOG(3) << "Client op <" << result.first
-             << "> registration status = " << result.second;
-    if (result.second !=
-        ::assistant::api::RegisterActionModuleResponse_Status_SUCCESS) {
-      has_failure = true;
-    }
-  }
-
-  if (has_failure) {
-    LOG(ERROR) << "Registration failed.";
-  }
-}
-
-void ActionService::OnHandleActionRequest(
-    grpc::ServerContext* context,
-    const ::assistant::api::HandleActionRequest* request,
-    base::OnceCallback<void(const grpc::Status&,
-                            const ::assistant::api::HandleActionResponse&)>
-        done) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(request);
-
-  if (!request->has_conversation_id() || !request->has_interaction_id()) {
-    LOG(ERROR) << "Received invalid HandleActionRequest.";
-    ::assistant::api::HandleActionResponse response;
-    std::move(done).Run(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
-                                     "HandleActionRequest missing arguments."),
-                        response);
-    return;
-  }
-
-  assistant_client::ActionModule::Action* action = PrepareAction(request);
-  if (!action) {
-    // TODO: Set the proper operation status in response.
-    // If the status is not OK, it will ignore the response and generate
-    // `Result::Error` and send to server.
-    LOG(ERROR) << "PrepareAction returns nullptr.";
-    ::assistant::api::HandleActionResponse response;
-    std::move(done).Run(grpc::Status::OK, response);
-    return;
-  }
-
-  DVLOG(3) << "Received request: operation=" << request->operation()
-           << ", client_op_name=" << request->client_op_name();
-  switch (request->operation()) {
-    case ::assistant::api::HandleActionRequest_Operation_PREPARE: {
-      ::assistant::api::HandleActionResponse response;
-      std::move(done).Run(grpc::Status::OK, response);
-      return;
-    }
-    case ::assistant::api::HandleActionRequest_Operation_EXECUTE: {
-      const std::string& action_id = GetActionId(request);
-      action->Execute(ToStdFunction(base::BindOnce(
-          &ActionService::OnActionDone, weak_factory_.GetWeakPtr(),
-          std::move(done), action_id)));
-      return;
-    }
-    case ::assistant::api::HandleActionRequest_Operation_INTERRUPT: {
-      // TODO: Add interrupt logic.
-      const std::string& action_id = GetActionId(request);
-      DVLOG(2) << "Action is interrupted, id: " << action_id;
-      return;
-    }
-    case ::assistant::api::HandleActionRequest_Operation_TERMINATE: {
-      const std::string& action_id = GetActionId(request);
-      const auto action_iter = alive_actions_.find(action_id);
-      if (action_iter != alive_actions_.end()) {
-        DVLOG(3) << "Destroyed action without execution, id: " << action_id
-                 << ", name: " << action_iter->second.first;
-        alive_actions_.erase(action_id);
-      } else {
-        LOG(ERROR)
-            << "The action with id: " << action_id
-            << " doesn't exist in |alive_actions_|. This should never happen.";
-      }
-      return;
-    }
-  }
-}
-
-assistant_client::ActionModule::Action* ActionService::PrepareAction(
-    const ::assistant::api::HandleActionRequest* request) {
-  const std::string& action_id = GetActionId(request);
-  const auto action_iter = alive_actions_.find(action_id);
-  // Try to retrieve the action from the alive actions. This is for retrieving
-  // the action that has prepare phase for execute operation or the action is
-  // executing for interrupt operation.
-  if (action_iter != alive_actions_.end()) {
-    return action_iter->second.second.get();
-  }
-
-  // Never try to create a new action if the operation is interrupting or
-  // terminating.
-  if (request->operation() ==
-          ::assistant::api::HandleActionRequest_Operation_INTERRUPT ||
-      request->operation() ==
-          ::assistant::api::HandleActionRequest_Operation_TERMINATE) {
-    return nullptr;
-  }
-
-  if (!request->has_client_op_name()) {
-    LOG(ERROR) << "Failed to create the action because of no client op name in "
-                  "the request.";
-    return nullptr;
-  }
-  const std::string& action_name = request->client_op_name();
-
-  // ActionModule returns the raw pointer of a new action and transfers
-  // the ownership. The raw pointer is used to cross the ABI boundaries.
-  auto* action =
-      action_module_->CreateAction(action_name, ActionArgs(*request));
-  if (!action) {
-    LOG(ERROR) << "Action module failed to create action : " << action_name;
-    return nullptr;
-  }
-
-  alive_actions_.insert(
-      {action_id, std::make_pair(action_name, base::WrapUnique(action))});
-  return action;
-}
-
-void ActionService::OnActionDone(
-    base::OnceCallback<void(const grpc::Status&,
-                            const ::assistant::api::HandleActionResponse&)>
-        done,
-    const std::string& action_id,
-    const assistant_client::ActionModule::Result& result) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  ::assistant::api::HandleActionResponse response;
-  chromeos::libassistant::PopulateHandleActionResponse(result, &response);
-
-  const auto action_iter = alive_actions_.find(action_id);
-  if (action_iter != alive_actions_.end()) {
-    DVLOG(3) << "Finished executing action with id: " << action_id
-             << " and name: " << action_iter->second.first;
-    // Delete the action in the future to prevent deadlock on the WaitAction.
-    // When the WaitAction runs its callback in `OnScheduledWaitDone()` with
-    // lock, the callback (this function) will delete the action here. In the
-    // dtor of the WaitAction, it will try to call `OnScheduledWaitDone()` to
-    // clean up, which will end up with deadlock.
-    auto action = std::move(action_iter->second.second);
-    alive_actions_.erase(action_id);
-    task_runner_->DeleteSoon(FROM_HERE, action.release());
-  } else {
-    LOG(ERROR)
-        << "The action with id: " << action_id
-        << " doesn't exist in |alive_actions_|. This should never happen.";
-  }
-
-  std::move(done).Run(grpc::Status::OK, response);
-}
-
-void ActionService::OnGetActionServiceContextRequest(
-    grpc::ServerContext* context,
-    const ::assistant::api::GetActionServiceContextRequest* request,
-    base::OnceCallback<
-        void(const grpc::Status&,
-             const ::assistant::api::GetActionServiceContextResponse&)> done) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  DVLOG(3) << "Getting service context.";
-  ::assistant::api::GetActionServiceContextResponse response;
-  chromeos::libassistant::PopulateGetActionServiceContextResponse(
-      *action_module_, &response);
-  std::move(done).Run(grpc::Status::OK, response);
-}
-
-void ActionService::StartCQ(::grpc::ServerCompletionQueue* cq) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  action_handler_driver_ = std::make_unique<
-      RpcMethodDriver<::assistant::api::HandleActionRequest,
-                      ::assistant::api::HandleActionResponse>>(
-      cq,
-      base::BindRepeating(
-          &::assistant::api::ActionService::AsyncService::RequestHandleAction,
-          async_service_weak_factory_.GetWeakPtr()),
-      base::BindRepeating(&ActionService::OnHandleActionRequest,
-                          weak_factory_.GetWeakPtr()));
-
-  service_context_driver_ = std::make_unique<
-      RpcMethodDriver<::assistant::api::GetActionServiceContextRequest,
-                      ::assistant::api::GetActionServiceContextResponse>>(
-      cq,
-      base::BindRepeating(&::assistant::api::ActionService::AsyncService::
-                              RequestGetActionServiceContext,
-                          async_service_weak_factory_.GetWeakPtr()),
-      base::BindRepeating(&ActionService::OnGetActionServiceContextRequest,
-                          weak_factory_.GetWeakPtr()));
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/external_services/action_service.h b/chromeos/ash/services/libassistant/grpc/external_services/action_service.h
deleted file mode 100644
index f2994d62..0000000
--- a/chromeos/ash/services/libassistant/grpc/external_services/action_service.h
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_ACTION_SERVICE_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_ACTION_SERVICE_H_
-
-#include "base/containers/flat_map.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/libassistant/grpc/async_service_driver.h"
-#include "chromeos/ash/services/libassistant/grpc/rpc_method_driver.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/action_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/action_service.grpc.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/query_interface.pb.h"
-
-namespace assistant {
-namespace api {
-class GetActionServiceContextRequest;
-class GetActionServiceContextResponse;
-class HandleActionRequest;
-class HandleActionResponse;
-}  // namespace api
-}  // namespace assistant
-
-namespace ash::libassistant {
-
-class GrpcLibassistantClient;
-
-class ActionService : public AsyncServiceDriver {
- public:
-  ActionService(::grpc::ServerBuilder* server_builder,
-                GrpcLibassistantClient* libassistant_client,
-                const std::string& assistant_service_address);
-  ~ActionService() override;
-
-  // ActionService does no own the ActionModules, so the ActionModules have to
-  // be live as long as the ActionService.
-  void RegisterActionModule(assistant_client::ActionModule* action_module);
-
-  // This should be called only when we know the server is ready.
-  void StartRegistration();
-
- private:
-  // Handles the response of RegisterActionModuleRequest from libassistant.
-  void OnRegistrationDone(
-      const ::grpc::Status& status,
-      const ::assistant::api::RegisterActionModuleResponse& response);
-
-  // Handles HandleActionRequest from libassistant to
-  // prepare/execute/interrupt one action. see action_interface.proto.
-  void OnHandleActionRequest(
-      grpc::ServerContext* context,
-      const ::assistant::api::HandleActionRequest* request,
-      base::OnceCallback<void(const grpc::Status&,
-                              const ::assistant::api::HandleActionResponse&)>
-          done);
-
-  // If the requested operation is
-  // * PREPARE, returns a new action.
-  // * EXECUTE, returns the prepared action if there is one created before
-  // because of PREPARE request, or create a new one.
-  // * INTERRUPT, returns the alive action from `alive_actions_` if there is one
-  // existing.
-  // Returned actions are owned by `alive_actions_` and will be deleted when
-  // `OnActionDone()`.
-  assistant_client::ActionModule::Action* PrepareAction(
-      const ::assistant::api::HandleActionRequest* request);
-
-  // Sends the action result back to libassistant and clean up actions.
-  void OnActionDone(
-      base::OnceCallback<void(const grpc::Status&,
-                              const ::assistant::api::HandleActionResponse&)>
-          done,
-      const std::string& action_id,
-      const assistant_client::ActionModule::Result& result);
-
-  // Handles GetActionServiceContextRequest from libassistant.
-  void OnGetActionServiceContextRequest(
-      grpc::ServerContext* context,
-      const ::assistant::api::GetActionServiceContextRequest* request,
-      base::OnceCallback<
-          void(const grpc::Status&,
-               const ::assistant::api::GetActionServiceContextResponse&)> done);
-
-  // AsyncServiceDriver:
-  void StartCQ(::grpc::ServerCompletionQueue* cq) override;
-
-  raw_ptr<assistant_client::ActionModule> action_module_ = nullptr;
-
-  // Map with the concatenated |convesation_id| and |interaction_id| from
-  // |HandleActionRequest| as the key. The value is a pair of the action name
-  // and the action itself.
-  base::flat_map<
-      std::string,
-      std::pair<std::string,
-                std::unique_ptr<assistant_client::ActionModule::Action>>>
-      alive_actions_;
-
-  // Owned by `GrpcServicesInitializer`.
-  raw_ptr<GrpcLibassistantClient> libassistant_client_ = nullptr;
-
-  const std::string assistant_service_address_;
-
-  ::assistant::api::ActionService::AsyncService service_;
-
-  std::unique_ptr<RpcMethodDriver<::assistant::api::HandleActionRequest,
-                                  ::assistant::api::HandleActionResponse>>
-      action_handler_driver_;
-  std::unique_ptr<
-      RpcMethodDriver<::assistant::api::GetActionServiceContextRequest,
-                      ::assistant::api::GetActionServiceContextResponse>>
-      service_context_driver_;
-
-  // This sequence checker ensures that all callbacks are called on the main
-  // sequence.
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
-
-  base::WeakPtrFactory<::assistant::api::ActionService::AsyncService>
-      async_service_weak_factory_{&service_};
-  base::WeakPtrFactory<ActionService> weak_factory_{this};
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_ACTION_SERVICE_H_
diff --git a/chromeos/ash/services/libassistant/grpc/external_services/customer_registration_client.cc b/chromeos/ash/services/libassistant/grpc/external_services/customer_registration_client.cc
deleted file mode 100644
index c0b50550..0000000
--- a/chromeos/ash/services/libassistant/grpc/external_services/customer_registration_client.cc
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/external_services/customer_registration_client.h"
-
-#include "base/check_op.h"
-#include "base/functional/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/task/bind_post_task.h"
-#include "base/time/time.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_libassistant_client.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_state.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/customer_registration_service.grpc.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_service.grpc.pb.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-using ::assistant::api::HeartbeatEventHandlerInterface;
-using ::assistant::api::RegisterCustomerResponse;
-using ::assistant::api::ServiceRegistrationRequest;
-using ::assistant::api::ServiceRegistrationResponse;
-
-// Period at which CustomerRegistrationClient sends requests to the assistant's
-// customer registration service until it receives the first heartbeat.
-constexpr base::TimeDelta kRegistrationPollingPeriod = base::Seconds(3);
-
-StateConfig BuildCustomerRegistrationStateConfig() {
-  StateConfig state_config;
-  state_config.max_retries = 20;
-  state_config.timeout_in_ms = kRegistrationPollingPeriod.InMilliseconds();
-  state_config.wait_for_ready = true;
-  return state_config;
-}
-
-}  // namespace
-
-CustomerRegistrationClient::CustomerRegistrationClient(
-    const std::string& customer_server_address,
-    base::TimeDelta heartbeat_period,
-    GrpcLibassistantClient* libassistant_client)
-    : customer_server_address_(customer_server_address),
-      libassistant_client_(libassistant_client) {
-  DCHECK(!customer_server_address_.empty());
-  DCHECK(libassistant_client_);
-
-  customer_registration_request_.set_server_address(customer_server_address_);
-  ServiceRegistrationRequest heartbeat_service_request;
-  heartbeat_service_request.mutable_heartbeat_handler_metadata()
-      ->set_heartbeat_response_period_ms(heartbeat_period.InMilliseconds());
-
-  AddSupportedService(
-      HeartbeatEventHandlerInterface::service_full_name(),
-      heartbeat_service_request,
-      base::BindOnce(
-          &CustomerRegistrationClient::OnHeartbeatServiceRegistrationResponse,
-          weak_factory_.GetWeakPtr()));
-}
-
-CustomerRegistrationClient::~CustomerRegistrationClient() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-void CustomerRegistrationClient::AddSupportedService(
-    const std::string& service_name,
-    const ServiceRegistrationRequest& service_registration_request,
-    ServiceRegistrationResponseCb on_service_registration_response) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  // All services must be registered before Start().
-  DCHECK(!is_started_);
-  DCHECK(on_service_registration_response);
-  // Same service should not be registered more than once.
-  DCHECK(!(customer_registration_request_.services().contains(service_name) ||
-           service_registration_response_cbs_.contains(service_name)))
-      << service_name << " has already been registered.";
-  (*customer_registration_request_.mutable_services())[service_name] =
-      service_registration_request;
-  service_registration_response_cbs_[service_name] =
-      std::move(on_service_registration_response);
-}
-
-void CustomerRegistrationClient::Start() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  is_started_ = true;
-
-  RegisterWithCustomerService();
-}
-
-void CustomerRegistrationClient::RegisterWithCustomerService() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  libassistant_client_->CallServiceMethod(
-      customer_registration_request_,
-      base::BindOnce(
-          &CustomerRegistrationClient::OnCustomerRegistrationResponse,
-          weak_factory_.GetWeakPtr()),
-      BuildCustomerRegistrationStateConfig());
-}
-
-void CustomerRegistrationClient::OnCustomerRegistrationResponse(
-    const grpc::Status& status,
-    const RegisterCustomerResponse& response) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (!status.ok()) {
-    LOG(ERROR) << "Customer " << customer_server_address_
-               << " failed to connect to CustomerRegistrationService. "
-                  "Trying again...";
-  } else {
-    for (const auto& service_response_pair : response.services()) {
-      const std::string& service_name = service_response_pair.first;
-      if (!service_registration_response_cbs_.contains(service_name)) {
-        // If it contains some other services that are not present in the
-        // RegisterCustomerRequest, it's almost certainly a bug somewhere.
-        // Instead of simply crashing the whole service, which would be too
-        // severe, we put an error log before continuing as an alert of this
-        // situation.
-        LOG(ERROR) << "Found unregistered service " << service_name
-                   << " in the RegisterCustomerResponse.";
-        continue;
-      }
-      std::move(service_registration_response_cbs_.at(service_name))
-          .Run(service_response_pair.second);
-    }
-    DVLOG(3) << "Customer " << customer_server_address_
-             << " successfully registered with libassistant.";
-  }
-
-  // Note that regardless of the success of the RegisterCustomer Rpc, the client
-  // should continue make RegisterCustomer calls until a heartbeat is received.
-  // TODO(meilinw): add retry logic.
-}
-
-void CustomerRegistrationClient::OnHeartbeatServiceRegistrationResponse(
-    const ServiceRegistrationResponse& response) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  // This really should never fail. If it does, there's almost certainly a bug
-  // somewhere, but crashing the device is too extreme of a reaction, and
-  // there's nothing that can be done to recover from this error.
-  if (response.result() != ServiceRegistrationResponse::SUCCESS) {
-    LOG(ERROR) << "Customer " << customer_server_address_
-               << " failed to register its HearbeatService with Libassistant";
-  }
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/external_services/customer_registration_client.h b/chromeos/ash/services/libassistant/grpc/external_services/customer_registration_client.h
deleted file mode 100644
index e550efe..0000000
--- a/chromeos/ash/services/libassistant/grpc/external_services/customer_registration_client.h
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_CUSTOMER_REGISTRATION_CLIENT_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_CUSTOMER_REGISTRATION_CLIENT_H_
-
-#include <memory>
-#include <string>
-
-#include "base/containers/flat_map.h"
-#include "base/functional/callback.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/time/time.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/customer_registration_interface.pb.h"
-#include "third_party/grpc/source/include/grpcpp/grpcpp.h"
-
-namespace ash::libassistant {
-
-class GrpcLibassistantClient;
-
-// Client of libassistant's CustomerRegistrationService. One
-// CustomerRegistrationClient should exist for each libassistant customer.
-// Has the following responsibilities:
-// - Registers the services that the customer supports. The heartbeat service
-//   is supported automatically.
-// - TODO(b/190645689): Re-registers with the CustomerRegistrationService if
-//   libassistant fails to send heartbeats for a period of time (implying that
-//   libassistant has crashed and is going through its bootup sequence again).
-class CustomerRegistrationClient {
- public:
-  using ServiceRegistrationResponseCb = base::OnceCallback<void(
-      const ::assistant::api::ServiceRegistrationResponse&)>;
-
-  // |customer_server_address|: The address of the server hosting the customer's
-  // grpc services.
-  // |heartbeat_period|: The period at which the customer would like to receive
-  // heartbeats from libassistant.
-  // |libassistant_client|: The gRPC client to invoke Libassistant service
-  // methods.
-  CustomerRegistrationClient(const std::string& customer_server_address,
-                             base::TimeDelta heartbeat_period,
-                             GrpcLibassistantClient* libassistant_client);
-  ~CustomerRegistrationClient();
-
-  // Adds a gRPC service that the customer supports (one that may be called by
-  // libassistant). Must be called before Start(). CustomerRegistrationClient
-  // will tell libassistant that this customer supports the specified service
-  // when Start() is called.
-  //
-  // |service_name|: Must match the auto-generated gRPC service_full_name()
-  // of the desired service.
-  //
-  // |service_registration_request|: The caller may set the appropriate metadata
-  // for the corresponding service in the request. May be empty/default if
-  // the service doesn't have any metadata.
-  //
-  // |on_service_registration_response|: Run whenever the customer service gets
-  // registered with libassistant and a response is received from the
-  // CustomerRegistrationService.
-  //
-  // All supported services must be registered before calling Start().
-  void AddSupportedService(
-      const std::string& service_name,
-      const ::assistant::api::ServiceRegistrationRequest&
-          service_registration_request,
-      ServiceRegistrationResponseCb on_service_registration_response);
-
-  // Starts trying to connect to libassistant's CustomerRegistrationService.
-  // All services added through AddSupportedService() shall be present in the
-  // registration request.
-  void Start();
-
- private:
-  void RegisterWithCustomerService();
-  void OnCustomerRegistrationResponse(
-      const grpc::Status& status,
-      const ::assistant::api::RegisterCustomerResponse& response);
-
-  void OnHeartbeatServiceRegistrationResponse(
-      const ::assistant::api::ServiceRegistrationResponse& response);
-
-  const std::string customer_server_address_;
-  const raw_ptr<GrpcLibassistantClient> libassistant_client_ = nullptr;
-
-  ::assistant::api::RegisterCustomerRequest customer_registration_request_;
-  bool is_started_ = false;
-  base::flat_map</*service_name=*/std::string, ServiceRegistrationResponseCb>
-      service_registration_response_cbs_;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-  base::WeakPtrFactory<CustomerRegistrationClient> weak_factory_{this};
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_CUSTOMER_REGISTRATION_CLIENT_H_
diff --git a/chromeos/ash/services/libassistant/grpc/external_services/event_handler_driver.cc b/chromeos/ash/services/libassistant/grpc/external_services/event_handler_driver.cc
deleted file mode 100644
index 89815ee4..0000000
--- a/chromeos/ash/services/libassistant/grpc/external_services/event_handler_driver.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/external_services/event_handler_driver.h"
-
-#include "chromeos/ash/services/libassistant/grpc/grpc_util.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/event_notification_interface.pb.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-constexpr char kAlarmTimerEventName[] = "AlarmTimerEvent";
-constexpr char kAssistantDisplayEventName[] = "AssistantDisplayEvent";
-constexpr char kConversationStateEventName[] = "ConversationStateEvent";
-constexpr char kDeviceStateEventName[] = "DeviceStateEvent";
-constexpr char kMediaActionFallbackEventName[] = "MediaActionFallbackEvent";
-constexpr char kSpeakerIdEnrollmentEventName[] = "SpeakerIdEnrollmentEvent";
-constexpr char kHandlerMethodName[] = "OnEventFromLibas";
-
-template <typename EventSelection>
-void PopulateRequest(const std::string& assistant_service_address,
-                     const std::string& event_name,
-                     ::assistant::api::RegisterEventHandlerRequest* request,
-                     EventSelection* event_selection) {
-  event_selection->set_select_all(true);
-  auto* external_handler = request->mutable_handler();
-  external_handler->set_server_address(assistant_service_address);
-  external_handler->set_service_name(GetLibassistGrpcServiceName(event_name));
-  external_handler->set_handler_method(kHandlerMethodName);
-}
-
-}  // namespace
-
-template <>
-::assistant::api::RegisterEventHandlerRequest
-CreateRegistrationRequest<::assistant::api::AlarmTimerEventHandlerInterface>(
-    const std::string& assistant_service_address) {
-  ::assistant::api::RegisterEventHandlerRequest request;
-  PopulateRequest(assistant_service_address, kAlarmTimerEventName, &request,
-                  request.mutable_alarm_timer_events_to_handle());
-  return request;
-}
-
-template <>
-::assistant::api::RegisterEventHandlerRequest CreateRegistrationRequest<
-    ::assistant::api::AssistantDisplayEventHandlerInterface>(
-    const std::string& assistant_service_address) {
-  ::assistant::api::RegisterEventHandlerRequest request;
-  PopulateRequest(assistant_service_address, kAssistantDisplayEventName,
-                  &request,
-                  request.mutable_assistant_display_events_to_handle());
-  return request;
-}
-
-template <>
-::assistant::api::RegisterEventHandlerRequest CreateRegistrationRequest<
-    ::assistant::api::ConversationStateEventHandlerInterface>(
-    const std::string& assistant_service_address) {
-  ::assistant::api::RegisterEventHandlerRequest request;
-  PopulateRequest(assistant_service_address, kConversationStateEventName,
-                  &request,
-                  request.mutable_conversation_state_events_to_handle());
-  return request;
-}
-
-template <>
-::assistant::api::RegisterEventHandlerRequest
-CreateRegistrationRequest<::assistant::api::DeviceStateEventHandlerInterface>(
-    const std::string& assistant_service_address) {
-  ::assistant::api::RegisterEventHandlerRequest request;
-  PopulateRequest(assistant_service_address, kDeviceStateEventName, &request,
-                  request.mutable_device_state_events_to_handle());
-  return request;
-}
-
-template <>
-::assistant::api::RegisterEventHandlerRequest CreateRegistrationRequest<
-    ::assistant::api::MediaActionFallbackEventHandlerInterface>(
-    const std::string& assistant_service_address) {
-  ::assistant::api::RegisterEventHandlerRequest request;
-  PopulateRequest(assistant_service_address, kMediaActionFallbackEventName,
-                  &request,
-                  request.mutable_media_action_fallback_events_to_handle());
-  return request;
-}
-
-template <>
-::assistant::api::RegisterEventHandlerRequest CreateRegistrationRequest<
-    ::assistant::api::SpeakerIdEnrollmentEventHandlerInterface>(
-    const std::string& assistant_service_address) {
-  ::assistant::api::RegisterEventHandlerRequest request;
-  PopulateRequest(assistant_service_address, kSpeakerIdEnrollmentEventName,
-                  &request,
-                  request.mutable_speaker_id_enrollment_events_to_handle());
-  return request;
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/external_services/event_handler_driver.h b/chromeos/ash/services/libassistant/grpc/external_services/event_handler_driver.h
deleted file mode 100644
index 64a25e8..0000000
--- a/chromeos/ash/services/libassistant/grpc/external_services/event_handler_driver.h
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_EVENT_HANDLER_DRIVER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_EVENT_HANDLER_DRIVER_H_
-
-#include <memory>
-#include <string>
-
-#include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "base/sequence_checker.h"
-#include "chromeos/ash/services/libassistant/grpc/async_service_driver.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/grpc_services_observer.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_libassistant_client.h"
-#include "chromeos/ash/services/libassistant/grpc/rpc_method_driver.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_service.grpc.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/event_notification_interface.pb.h"
-#include "third_party/grpc/source/include/grpcpp/grpcpp.h"
-
-namespace ash::libassistant {
-
-// Create request to register event handler, setting fields accordingly. It
-// cannot be a virtual method because it will be used in constructor. Derived
-// class should implement specialized function.
-template <typename THandlerInterface>
-::assistant::api::RegisterEventHandlerRequest CreateRegistrationRequest(
-    const std::string& assistant_service_address_);
-
-// EventHandlerDriver is template base class of each libassistant gRPC
-// event handler. There will be one instance for each event type. Whoever wants
-// to observe libassistant gRPC event should add themselves as observers.
-template <typename THandlerInterface>
-class EventHandlerDriver : public AsyncServiceDriver {
- public:
-  template <typename Func>
-  struct UnwrapTypeFromInterface;
-
-  template <typename TRequest, typename TResponse, typename Scope>
-  struct UnwrapTypeFromInterface<::grpc::Status (  // NOLINT(whitespace/parens)
-      Scope::*)(grpc::ServerContext*, const TRequest*, TResponse*)> {
-   private:
-    typedef TRequest RequestType;
-    typedef TResponse ResponseType;
-
-    friend class EventHandlerDriver;
-  };
-
-  typedef typename UnwrapTypeFromInterface<
-      decltype(&THandlerInterface::AsyncService::OnEventFromLibas)>::
-      ResponseType ResponseType;
-  typedef typename UnwrapTypeFromInterface<
-      decltype(&THandlerInterface::AsyncService::OnEventFromLibas)>::RequestType
-      RequestType;
-  using EventObserverType = GrpcServicesObserver<RequestType>;
-
-  EventHandlerDriver(::grpc::ServerBuilder* server_builder,
-                     GrpcLibassistantClient* libassistant_client,
-                     const std::string& assistant_service_address)
-      : AsyncServiceDriver(server_builder),
-        libassistant_client_(libassistant_client),
-        assistant_service_address_(assistant_service_address) {
-    DCHECK(server_builder);
-    DCHECK(libassistant_client_);
-
-    server_builder_->RegisterService(&service_);
-  }
-
-  ~EventHandlerDriver() override = default;
-
-  void StartRegistration() {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-    // Make request to libassistant, registering handler.
-    ::assistant::api::RegisterEventHandlerRequest request =
-        CreateRegistrationRequest<THandlerInterface>(
-            assistant_service_address_);
-    StateConfig config;
-    config.max_retries = 5;
-    config.timeout_in_ms = 3000;
-    libassistant_client_->CallServiceMethod(
-        request,
-        base::BindOnce(&EventHandlerDriver::OnRegisterEventHandlerDone,
-                       weak_factory_.GetWeakPtr()),
-        std::move(config));
-  }
-
-  void AddObserver(EventObserverType* const observer) {
-    observers_.AddObserver(observer);
-  }
-
-  void RemoveObserver(EventObserverType* const observer) {
-    observers_.RemoveObserver(observer);
-  }
-
- private:
-  void HandleEvent(
-      grpc::ServerContext* context,
-      const RequestType* request,
-      base::OnceCallback<void(const grpc::Status&, const ResponseType&)> done) {
-    for (auto& observer : observers_) {
-      observer.OnGrpcMessage(*request);
-    }
-
-    ResponseType response;
-    std::move(done).Run(grpc::Status::OK, response);
-  }
-
-  void OnRegisterEventHandlerDone(
-      const ::grpc::Status& status,
-      const ::assistant::api::RegisterEventHandlerResponse& response) {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-    if (!status.ok()) {
-      LOG(ERROR) << "Failed to register event handler. code: "
-                 << status.error_code() << ". Msg: " << status.error_message();
-    }
-  }
-
-  // AsyncServiceDriver implementation:
-  void StartCQ(::grpc::ServerCompletionQueue* cq) override {
-    rpc_event_driver_ =
-        std::make_unique<RpcMethodDriver<RequestType, ResponseType>>(
-            cq,
-            base::BindRepeating(
-                &THandlerInterface::AsyncService::RequestOnEventFromLibas,
-                async_service_weak_factory_.GetWeakPtr()),
-            base::BindRepeating(
-                &EventHandlerDriver<THandlerInterface>::HandleEvent,
-                weak_factory_.GetWeakPtr()));
-  }
-
-  std::unique_ptr<RpcMethodDriver<RequestType, ResponseType>> rpc_event_driver_;
-
-  typename THandlerInterface::AsyncService service_;
-
-  raw_ptr<GrpcLibassistantClient> libassistant_client_;
-  const std::string assistant_service_address_;
-
-  base::ObserverList<EventObserverType> observers_;
-
-  // This sequence checker ensures that all callbacks are called on the main
-  // sequence.
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  base::WeakPtrFactory<typename THandlerInterface::AsyncService>
-      async_service_weak_factory_{&service_};
-  base::WeakPtrFactory<EventHandlerDriver<THandlerInterface>> weak_factory_{
-      this};
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_EVENT_HANDLER_DRIVER_H_
diff --git a/chromeos/ash/services/libassistant/grpc/external_services/grpc_services_initializer.cc b/chromeos/ash/services/libassistant/grpc/external_services/grpc_services_initializer.cc
deleted file mode 100644
index c7da00cd..0000000
--- a/chromeos/ash/services/libassistant/grpc/external_services/grpc_services_initializer.cc
+++ /dev/null
@@ -1,229 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/external_services/grpc_services_initializer.h"
-
-#include <memory>
-
-#include "base/system/sys_info.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/time/time.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/action_service.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/customer_registration_client.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/heartbeat_event_handler_driver.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_http_connection_client.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_libassistant_client.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_util.h"
-#include "chromeos/assistant/internal/internal_constants.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_service.grpc.pb.h"
-#include "third_party/grpc/source/include/grpc/grpc_security_constants.h"
-#include "third_party/grpc/source/include/grpc/impl/codegen/grpc_types.h"
-#include "third_party/grpc/source/include/grpcpp/create_channel.h"
-#include "third_party/grpc/source/include/grpcpp/security/credentials.h"
-#include "third_party/grpc/source/include/grpcpp/security/server_credentials.h"
-#include "third_party/grpc/source/include/grpcpp/support/channel_arguments.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-// Desired time between consecutive heartbeats.
-constexpr base::TimeDelta kHeartbeatInterval = base::Seconds(2);
-
-}  // namespace
-
-GrpcServicesInitializer::GrpcServicesInitializer(
-    const std::string& libassistant_service_address,
-    const std::string& assistant_service_address)
-    : ServicesInitializerBase(
-          /*cq_thread_name=*/assistant_service_address + ".GrpcCQ",
-          /*main_task_runner=*/base::SequencedTaskRunner::GetCurrentDefault()),
-      assistant_service_address_(assistant_service_address),
-      libassistant_service_address_(libassistant_service_address) {
-  DCHECK(!libassistant_service_address.empty());
-  DCHECK(!assistant_service_address.empty());
-
-  InitLibassistGrpcClient();
-  InitAssistantGrpcServer();
-
-  customer_registration_client_ = std::make_unique<CustomerRegistrationClient>(
-      assistant_service_address_, kHeartbeatInterval,
-      libassistant_client_.get());
-}
-
-GrpcServicesInitializer::~GrpcServicesInitializer() {
-  if (assistant_grpc_server_)
-    assistant_grpc_server_->Shutdown();
-
-  StopCQ();
-}
-
-bool GrpcServicesInitializer::Start() {
-  // Starts the server after all drivers have been initiated.
-  assistant_grpc_server_ = server_builder_.BuildAndStart();
-
-  if (!assistant_grpc_server_) {
-    LOG(ERROR) << "Failed to start a server for ChromeOS Assistant gRPC.";
-    return false;
-  }
-
-  DVLOG(1) << "Started ChromeOS Assistant gRPC service";
-
-  RegisterEventHandlers();
-  StartCQ();
-  customer_registration_client_->Start();
-  return true;
-}
-
-void GrpcServicesInitializer::AddAlarmTimerEventObserver(
-    GrpcServicesObserver<::assistant::api::OnAlarmTimerEventRequest>*
-        observer) {
-  alarm_timer_event_handler_driver_->AddObserver(observer);
-}
-
-void GrpcServicesInitializer::AddAssistantDisplayEventObserver(
-    GrpcServicesObserver<::assistant::api::OnAssistantDisplayEventRequest>*
-        observer) {
-  assistant_display_event_handler_driver_->AddObserver(observer);
-}
-
-void GrpcServicesInitializer::AddConversationStateEventObserver(
-    GrpcServicesObserver<::assistant::api::OnConversationStateEventRequest>*
-        observer) {
-  conversation_state_event_handler_driver_->AddObserver(observer);
-}
-
-void GrpcServicesInitializer::AddDeviceStateEventObserver(
-    GrpcServicesObserver<::assistant::api::OnDeviceStateEventRequest>*
-        observer) {
-  device_state_event_handler_driver_->AddObserver(observer);
-}
-
-void GrpcServicesInitializer::AddMediaActionFallbackEventObserver(
-    GrpcServicesObserver<::assistant::api::OnMediaActionFallbackEventRequest>*
-        observer) {
-  media_action_fallback_event_handler_driver_->AddObserver(observer);
-}
-
-void GrpcServicesInitializer::AddSpeakerIdEnrollmentEventObserver(
-    GrpcServicesObserver<::assistant::api::OnSpeakerIdEnrollmentEventRequest>*
-        observer) {
-  speaker_id_enrollment_event_handler_driver_->AddObserver(observer);
-}
-
-void GrpcServicesInitializer::RemoveSpeakerIdEnrollmentEventObserver(
-    GrpcServicesObserver<::assistant::api::OnSpeakerIdEnrollmentEventRequest>*
-        observer) {
-  speaker_id_enrollment_event_handler_driver_->RemoveObserver(observer);
-}
-
-ActionService* GrpcServicesInitializer::GetActionService() {
-  return action_handler_driver_.get();
-}
-
-GrpcLibassistantClient& GrpcServicesInitializer::GrpcLibassistantClient() {
-  return *libassistant_client_;
-}
-
-void GrpcServicesInitializer::InitDrivers(grpc::ServerBuilder* server_builder) {
-  // Inits heartbeat driver.
-  heartbeat_driver_ =
-      std::make_unique<HeartbeatEventHandlerDriver>(&server_builder_);
-  heartbeat_event_observation_.Observe(heartbeat_driver_.get());
-  service_drivers_.emplace_back(heartbeat_driver_.get());
-
-  // Inits action service.
-  action_handler_driver_ = std::make_unique<ActionService>(
-      &server_builder_, libassistant_client_.get(), assistant_service_address_);
-  service_drivers_.emplace_back(action_handler_driver_.get());
-
-  // Inits other event handler drivers.
-  alarm_timer_event_handler_driver_ = std::make_unique<
-      EventHandlerDriver<::assistant::api::AlarmTimerEventHandlerInterface>>(
-      &server_builder_, libassistant_client_.get(), assistant_service_address_);
-  service_drivers_.emplace_back(alarm_timer_event_handler_driver_.get());
-
-  assistant_display_event_handler_driver_ = std::make_unique<EventHandlerDriver<
-      ::assistant::api::AssistantDisplayEventHandlerInterface>>(
-      &server_builder_, libassistant_client_.get(), assistant_service_address_);
-  service_drivers_.emplace_back(assistant_display_event_handler_driver_.get());
-
-  conversation_state_event_handler_driver_ =
-      std::make_unique<EventHandlerDriver<
-          ::assistant::api::ConversationStateEventHandlerInterface>>(
-          &server_builder_, libassistant_client_.get(),
-          assistant_service_address_);
-  service_drivers_.emplace_back(conversation_state_event_handler_driver_.get());
-
-  device_state_event_handler_driver_ = std::make_unique<
-      EventHandlerDriver<::assistant::api::DeviceStateEventHandlerInterface>>(
-      &server_builder_, libassistant_client_.get(), assistant_service_address_);
-  service_drivers_.emplace_back(device_state_event_handler_driver_.get());
-
-  media_action_fallback_event_handler_driver_ =
-      std::make_unique<EventHandlerDriver<
-          ::assistant::api::MediaActionFallbackEventHandlerInterface>>(
-          &server_builder_, libassistant_client_.get(),
-          assistant_service_address_);
-  service_drivers_.emplace_back(
-      media_action_fallback_event_handler_driver_.get());
-
-  speaker_id_enrollment_event_handler_driver_ =
-      std::make_unique<EventHandlerDriver<
-          ::assistant::api::SpeakerIdEnrollmentEventHandlerInterface>>(
-          &server_builder_, libassistant_client_.get(),
-          assistant_service_address_);
-  service_drivers_.emplace_back(
-      speaker_id_enrollment_event_handler_driver_.get());
-}
-
-void GrpcServicesInitializer::InitLibassistGrpcClient() {
-  grpc::ChannelArguments channel_args;
-  channel_args.SetInt(GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS, 200);
-  channel_args.SetInt(GRPC_ARG_MIN_RECONNECT_BACKOFF_MS, 200);
-  channel_args.SetInt(GRPC_ARG_MAX_RECONNECT_BACKOFF_MS, 2000);
-  grpc_local_connect_type connect_type =
-      GetGrpcLocalConnectType(libassistant_service_address_);
-
-  auto channel = grpc::CreateCustomChannel(
-      libassistant_service_address_,
-      ::grpc::experimental::LocalCredentials(connect_type), channel_args);
-
-  libassistant_client_ =
-      std::make_unique<ash::libassistant::GrpcLibassistantClient>(channel);
-}
-
-void GrpcServicesInitializer::StartGrpcHttpConnectionClient(
-    assistant_client::HttpConnectionFactory* factory) {
-  const bool is_chromeos_device = base::SysInfo::IsRunningOnChromeOS();
-  http_connection_client_ = std::make_unique<GrpcHttpConnectionClient>(
-      factory, GetHttpConnectionServiceAddress(is_chromeos_device));
-  http_connection_client_->Start();
-}
-
-void GrpcServicesInitializer::StopGrpcHttpConnectionClient() {
-  http_connection_client_.reset();
-}
-
-void GrpcServicesInitializer::InitAssistantGrpcServer() {
-  auto connect_type = GetGrpcLocalConnectType(assistant_service_address_);
-  // Listen on the given address with the specified credentials.
-  server_builder_.AddListeningPort(
-      assistant_service_address_,
-      ::grpc::experimental::LocalServerCredentials(connect_type));
-  RegisterServicesAndInitCQ(&server_builder_);
-}
-
-void GrpcServicesInitializer::RegisterEventHandlers() {
-  alarm_timer_event_handler_driver_->StartRegistration();
-  assistant_display_event_handler_driver_->StartRegistration();
-  conversation_state_event_handler_driver_->StartRegistration();
-  device_state_event_handler_driver_->StartRegistration();
-  media_action_fallback_event_handler_driver_->StartRegistration();
-  speaker_id_enrollment_event_handler_driver_->StartRegistration();
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/external_services/grpc_services_initializer.h b/chromeos/ash/services/libassistant/grpc/external_services/grpc_services_initializer.h
deleted file mode 100644
index 4921558..0000000
--- a/chromeos/ash/services/libassistant/grpc/external_services/grpc_services_initializer.h
+++ /dev/null
@@ -1,170 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_GRPC_SERVICES_INITIALIZER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_GRPC_SERVICES_INITIALIZER_H_
-
-#include <memory>
-#include <string>
-
-#include "base/scoped_observation.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/customer_registration_client.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/event_handler_driver.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/grpc_services_observer.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/heartbeat_event_handler_driver.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_client_thread.h"
-#include "chromeos/ash/services/libassistant/grpc/services_initializer_base.h"
-#include "chromeos/ash/services/libassistant/grpc/services_status_provider.h"
-#include "third_party/grpc/source/include/grpcpp/server_builder.h"
-
-namespace assistant {
-namespace api {
-class AlarmTimerEventHandlerInterface;
-class AssistantDisplayEventHandlerInterface;
-class ConversationStateEventHandlerInterface;
-class DeviceStateEventHandlerInterface;
-class MediaActionFallbackEventHandlerInterface;
-class SpeakerIdEnrollmentEventHandlerInterface;
-}  // namespace api
-}  // namespace assistant
-
-namespace assistant_client {
-class HttpConnectionFactory;
-}  // namespace assistant_client
-
-namespace ash::libassistant {
-
-class ActionService;
-class GrpcHttpConnectionClient;
-class GrpcLibassistantClient;
-
-// Component responsible for:
-// 1. Set up a gRPC client by establishing a new channel with Libassistant
-// server.
-// 2. Start and manage Libassistant V2 event observer gRPC services.
-class GrpcServicesInitializer : public ServicesInitializerBase {
- public:
-  GrpcServicesInitializer(const std::string& libassistant_service_address,
-                          const std::string& assistant_service_address);
-  GrpcServicesInitializer(const GrpcServicesInitializer&) = delete;
-  GrpcServicesInitializer& operator=(const GrpcServicesInitializer&) = delete;
-  ~GrpcServicesInitializer() override;
-
-  // Start assistant gRPC server. All supported services must be registered
-  // before this method is called. Client functionality is not impacted by this
-  // call. Returns false if the attempt to start a gRPC server failed.
-  bool Start();
-
-  void StartGrpcHttpConnectionClient(assistant_client::HttpConnectionFactory*);
-  void StopGrpcHttpConnectionClient();
-
-  // Add observer for each handler driver.
-  void AddAlarmTimerEventObserver(
-      GrpcServicesObserver<::assistant::api::OnAlarmTimerEventRequest>*
-          observer);
-  void AddAssistantDisplayEventObserver(
-      GrpcServicesObserver<::assistant::api::OnAssistantDisplayEventRequest>*
-          observer);
-  void AddConversationStateEventObserver(
-      GrpcServicesObserver<::assistant::api::OnConversationStateEventRequest>*
-          observer);
-  void AddDeviceStateEventObserver(
-      GrpcServicesObserver<::assistant::api::OnDeviceStateEventRequest>*
-          observer);
-  void AddMediaActionFallbackEventObserver(
-      GrpcServicesObserver<::assistant::api::OnMediaActionFallbackEventRequest>*
-          observer);
-  void AddSpeakerIdEnrollmentEventObserver(
-      GrpcServicesObserver<::assistant::api::OnSpeakerIdEnrollmentEventRequest>*
-          observer);
-  // SpeakerIdEnrollmentEvent requires a remove function because its lifecycle.
-  void RemoveSpeakerIdEnrollmentEventObserver(
-      GrpcServicesObserver<::assistant::api::OnSpeakerIdEnrollmentEventRequest>*
-          observer);
-
-  ActionService* GetActionService();
-
-  // Expose a reference to |GrpcLibassistantClient|.
-  GrpcLibassistantClient& GrpcLibassistantClient();
-
-  ServicesStatusProvider& GetServicesStatusProvider() {
-    return services_status_provider_;
-  }
-
- private:
-  // ServicesInitializerBase overrides:
-  void InitDrivers(grpc::ServerBuilder* server_builder) override;
-
-  // 1. Creates a channel object to obtain a handle to libassistant gRPC server
-  // services.
-  // 2. Creates a gRPC client using that channel and through which we can invoke
-  // service methods implemented in the server.
-  void InitLibassistGrpcClient();
-
-  // 1. Adds a listening port where server can receive traffic (via
-  // AddListeningPort).
-  // 2. Adds a completion queue to handle async operations (via
-  // AddCompletionQueue).
-  // 3. Registers all supported services (via RegisterService).
-  // This should be called before Start().
-  void InitAssistantGrpcServer();
-
-  void RegisterEventHandlers();
-
-  // Address of assistant gRPC server.
-  const std::string assistant_service_address_;
-  // Address of Libassistant gRPC server.
-  const std::string libassistant_service_address_;
-
-  grpc::ServerBuilder server_builder_;
-  std::unique_ptr<grpc::Server> assistant_grpc_server_;
-
-  // The entrypoint through which we can query Libassistant V2 APIs.
-  std::unique_ptr<ash::libassistant::GrpcLibassistantClient>
-      libassistant_client_;
-
-  std::unique_ptr<CustomerRegistrationClient> customer_registration_client_;
-
-  std::unique_ptr<HeartbeatEventHandlerDriver> heartbeat_driver_;
-
-  std::unique_ptr<ActionService> action_handler_driver_;
-
-  std::unique_ptr<
-      EventHandlerDriver<::assistant::api::AlarmTimerEventHandlerInterface>>
-      alarm_timer_event_handler_driver_;
-
-  std::unique_ptr<EventHandlerDriver<
-      ::assistant::api::AssistantDisplayEventHandlerInterface>>
-      assistant_display_event_handler_driver_;
-
-  std::unique_ptr<EventHandlerDriver<
-      ::assistant::api::ConversationStateEventHandlerInterface>>
-      conversation_state_event_handler_driver_;
-
-  std::unique_ptr<
-      EventHandlerDriver<::assistant::api::DeviceStateEventHandlerInterface>>
-      device_state_event_handler_driver_;
-
-  std::unique_ptr<EventHandlerDriver<
-      ::assistant::api::MediaActionFallbackEventHandlerInterface>>
-      media_action_fallback_event_handler_driver_;
-
-  std::unique_ptr<EventHandlerDriver<
-      ::assistant::api::SpeakerIdEnrollmentEventHandlerInterface>>
-      speaker_id_enrollment_event_handler_driver_;
-
-  std::unique_ptr<GrpcHttpConnectionClient> http_connection_client_;
-
-  // `heartbeat_event_observation_` observes `heartbeat_driver_`, and needs to
-  // be destroyed before `heartbeat_driver_`.
-  ServicesStatusProvider services_status_provider_;
-  base::ScopedObservation<
-      HeartbeatEventHandlerDriver,
-      GrpcServicesObserver<::assistant::api::OnHeartbeatEventRequest>>
-      heartbeat_event_observation_{&services_status_provider_};
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_GRPC_SERVICES_INITIALIZER_H_
diff --git a/chromeos/ash/services/libassistant/grpc/external_services/grpc_services_initializer_unittests.cc b/chromeos/ash/services/libassistant/grpc/external_services/grpc_services_initializer_unittests.cc
deleted file mode 100644
index 4c0741c..0000000
--- a/chromeos/ash/services/libassistant/grpc/external_services/grpc_services_initializer_unittests.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/external_services/grpc_services_initializer.h"
-
-#include "base/test/task_environment.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_util.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::libassistant {
-
-class GrpcServicesInitializerTest : public testing::Test {
- public:
-  GrpcServicesInitializerTest() = default;
-  GrpcServicesInitializerTest(const GrpcServicesInitializerTest&) = delete;
-  GrpcServicesInitializerTest& operator=(const GrpcServicesInitializerTest&) =
-      delete;
-  ~GrpcServicesInitializerTest() override = default;
-
- protected:
-  std::unique_ptr<GrpcServicesInitializer> grpc_services_;
-
- private:
-  base::test::SingleThreadTaskEnvironment environment_;
-};
-
-TEST_F(GrpcServicesInitializerTest, StartService) {
-  // Should not crash at the end of the test.
-  grpc_services_ = std::make_unique<GrpcServicesInitializer>(
-      GetLibassistantServiceAddress(
-          /*is_chromeos_device=*/false),
-      GetAssistantServiceAddress(
-          /*is_chromeos_device=*/false));
-  grpc_services_->Start();
-  grpc_services_.reset();
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/external_services/grpc_services_observer.h b/chromeos/ash/services/libassistant/grpc/external_services/grpc_services_observer.h
deleted file mode 100644
index 9423d86..0000000
--- a/chromeos/ash/services/libassistant/grpc/external_services/grpc_services_observer.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_GRPC_SERVICES_OBSERVER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_GRPC_SERVICES_OBSERVER_H_
-
-#include "base/observer_list_types.h"
-
-namespace ash::libassistant {
-
-// Observer class registered to event handler drivers.
-template <class TRequest>
-class GrpcServicesObserver : public base::CheckedObserver {
- public:
-  // Called when a new event of type |TRequest| has delivered.
-  virtual void OnGrpcMessage(const TRequest& request) = 0;
-
- protected:
-  ~GrpcServicesObserver() override = default;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_GRPC_SERVICES_OBSERVER_H_
diff --git a/chromeos/ash/services/libassistant/grpc/external_services/heartbeat_event_handler_driver.cc b/chromeos/ash/services/libassistant/grpc/external_services/heartbeat_event_handler_driver.cc
deleted file mode 100644
index db10cef..0000000
--- a/chromeos/ash/services/libassistant/grpc/external_services/heartbeat_event_handler_driver.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/external_services/heartbeat_event_handler_driver.h"
-
-#include <utility>
-
-#include "base/functional/bind.h"
-#include "base/sequence_checker.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/libas_server_status.pb.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-using ::assistant::api::HeartbeatEventHandlerInterface;
-using ::assistant::api::OnHeartbeatEventRequest;
-using ::assistant::api::OnHeartbeatEventResponse;
-
-}  // namespace
-
-HeartbeatEventHandlerDriver::HeartbeatEventHandlerDriver(
-    ::grpc::ServerBuilder* server_builder)
-    : AsyncServiceDriver(server_builder) {
-  server_builder_->RegisterService(&service_);
-}
-
-HeartbeatEventHandlerDriver::~HeartbeatEventHandlerDriver() = default;
-
-void HeartbeatEventHandlerDriver::AddObserver(
-    GrpcServicesObserver<::assistant::api::OnHeartbeatEventRequest>* observer) {
-  observers_.AddObserver(observer);
-}
-
-void HeartbeatEventHandlerDriver::RemoveObserver(
-    GrpcServicesObserver<::assistant::api::OnHeartbeatEventRequest>* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-void HeartbeatEventHandlerDriver::StartCQ(::grpc::ServerCompletionQueue* cq) {
-  on_event_rpc_method_driver_ = std::make_unique<
-      RpcMethodDriver<OnHeartbeatEventRequest, OnHeartbeatEventResponse>>(
-      cq,
-      base::BindRepeating(&HeartbeatEventHandlerInterface::AsyncService::
-                              RequestOnEventFromLibas,
-                          async_service_weak_factory_.GetWeakPtr()),
-      base::BindRepeating(&HeartbeatEventHandlerDriver::HandleEvent,
-                          weak_factory_.GetWeakPtr()));
-}
-
-void HeartbeatEventHandlerDriver::HandleEvent(
-    grpc::ServerContext* context,
-    const OnHeartbeatEventRequest* request,
-    base::OnceCallback<void(const grpc::Status&,
-                            const OnHeartbeatEventResponse&)> done) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  int heartbeat_count = request->heartbeat_num();
-  DVLOG(3) << "Heartbeat from libassistant : " << heartbeat_count;
-  OnHeartbeatEventResponse response;
-  std::move(done).Run(grpc::Status::OK, response);
-
-  // Parse heartbeat request.
-  if (!request->has_current_server_status()) {
-    LOG(ERROR) << "Received Libassistant heartbeat without server status";
-    return;
-  }
-
-  for (auto& observer : observers_)
-    observer.OnGrpcMessage(*request);
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/external_services/heartbeat_event_handler_driver.h b/chromeos/ash/services/libassistant/grpc/external_services/heartbeat_event_handler_driver.h
deleted file mode 100644
index e9f04baa..0000000
--- a/chromeos/ash/services/libassistant/grpc/external_services/heartbeat_event_handler_driver.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_HEARTBEAT_EVENT_HANDLER_DRIVER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_HEARTBEAT_EVENT_HANDLER_DRIVER_H_
-
-#include <memory>
-
-#include "base/memory/scoped_refptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "chromeos/ash/services/libassistant/grpc/async_service_driver.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/grpc_services_observer.h"
-#include "chromeos/ash/services/libassistant/grpc/rpc_method_driver.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_service.grpc.pb.h"
-
-namespace assistant {
-namespace api {
-class OnHeartbeatEventRequest;
-class OnHeartbeatEventResponse;
-}  // namespace api
-}  // namespace assistant
-
-namespace ash::libassistant {
-
-class HeartbeatEventHandlerDriver : public AsyncServiceDriver {
- public:
-  explicit HeartbeatEventHandlerDriver(::grpc::ServerBuilder* server_builder);
-  HeartbeatEventHandlerDriver(const HeartbeatEventHandlerDriver&) = delete;
-  HeartbeatEventHandlerDriver& operator=(const HeartbeatEventHandlerDriver&) =
-      delete;
-  ~HeartbeatEventHandlerDriver() override;
-
-  void AddObserver(
-      GrpcServicesObserver<::assistant::api::OnHeartbeatEventRequest>*
-          observer);
-  void RemoveObserver(
-      GrpcServicesObserver<::assistant::api::OnHeartbeatEventRequest>*
-          observer);
-
- private:
-  // Generally we should use fully qualified namespace inside classes to avoid
-  // potential conflict. We made an exception here to increase the readability
-  // with shorten names.
-  using OnHeartbeatEventRequest = ::assistant::api::OnHeartbeatEventRequest;
-  using OnHeartbeatEventResponse = ::assistant::api::OnHeartbeatEventResponse;
-  using HeartbeatEventHandlerInterface =
-      ::assistant::api::HeartbeatEventHandlerInterface;
-
-  // AsyncServiceDriver overrides:
-  void StartCQ(::grpc::ServerCompletionQueue* cq) override;
-
-  // Handles incoming heartbeat RPC event delivery.
-  void HandleEvent(
-      grpc::ServerContext* context,
-      const OnHeartbeatEventRequest* request,
-      base::OnceCallback<void(const grpc::Status& status,
-                              const OnHeartbeatEventResponse& response)> done);
-
-  HeartbeatEventHandlerInterface::AsyncService service_;
-
-  std::unique_ptr<
-      RpcMethodDriver<OnHeartbeatEventRequest, OnHeartbeatEventResponse>>
-      on_event_rpc_method_driver_;
-
-  base::ObserverList<
-      GrpcServicesObserver<::assistant::api::OnHeartbeatEventRequest>>
-      observers_;
-
-  // This sequence checker ensures that all callbacks are called on the main
-  // sequence.
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  base::WeakPtrFactory<HeartbeatEventHandlerInterface::AsyncService>
-      async_service_weak_factory_{&service_};
-  base::WeakPtrFactory<HeartbeatEventHandlerDriver> weak_factory_{this};
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_EXTERNAL_SERVICES_HEARTBEAT_EVENT_HANDLER_DRIVER_H_
diff --git a/chromeos/ash/services/libassistant/grpc/grpc_client_thread.cc b/chromeos/ash/services/libassistant/grpc/grpc_client_thread.cc
deleted file mode 100644
index 240ba4a..0000000
--- a/chromeos/ash/services/libassistant/grpc/grpc_client_thread.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/grpc_client_thread.h"
-
-#include <memory>
-
-#include "base/functional/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/task/single_thread_task_runner.h"
-#include "chromeos/assistant/internal/grpc_transport/grpc_client_cq_tag.h"
-
-namespace ash::libassistant {
-
-using ::chromeos::libassistant::GrpcClientCQTag;
-
-GrpcClientThread::GrpcClientThread(const std::string& thread_name,
-                                   base::ThreadType thread_type)
-    : thread_(thread_name) {
-  base::Thread::Options thread_options = {/*type=*/base::MessagePumpType::IO,
-                                          /*size=*/0};
-  thread_options.thread_type = thread_type;
-  thread_.StartWithOptions(std::move(thread_options));
-  StartCQ();
-}
-
-GrpcClientThread::~GrpcClientThread() {
-  StopCQ();
-}
-
-void GrpcClientThread::StartCQ() {
-  is_cq_shutdown_ = false;
-  thread_.task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&GrpcClientThread::ScanCQInternal,
-                                base::Unretained(this)));
-}
-
-void GrpcClientThread::StopCQ() {
-  {
-    // The lock prevents the following scenario (events listed in time order)
-    // 1. CQ thread takes a tag out from completion queue
-    // 2. CQ shutdowns
-    // 3. CQ thread schedules a gRPC call retry because the call failed
-    // Step 3 is problematic because CQ should not be used after shutdown
-    base::AutoLock lock(cq_shutdown_lock_);
-    completion_queue_.Shutdown();
-    is_cq_shutdown_ = true;
-  }
-
-  thread_.Stop();
-}
-
-void GrpcClientThread::ScanCQInternal() {
-  void* tag;
-  bool ok;
-  while (true) {
-    // Block waiting for the completion of the next operation in the completion
-    // queue. The completing operation is uniquely identified by its tag, which
-    // in this case is a pointer to |GrpcClientCQTag| implementing the next step
-    // of RPC execution. Next() is thread-safe, and will return true if an event
-    // is available, false if the queue is fully drained and shut down.
-    if (!completion_queue_.Next(&tag, &ok)) {
-      DVLOG(3) << "Completion queue shutdown.";
-      break;
-    }
-
-    DVLOG(3) << "Read a completion queue event. Invoking its callback.";
-    GrpcClientCQTag* callback_tag = static_cast<GrpcClientCQTag*>(tag);
-    {
-      base::AutoLock lock(cq_shutdown_lock_);
-      if (is_cq_shutdown_) {
-        callback_tag->OnCompleted(GrpcClientCQTag::State::kShutdown);
-      } else {
-        callback_tag->OnCompleted(ok ? GrpcClientCQTag::State::kOk
-                                     : GrpcClientCQTag::State::kFailed);
-      }
-    }
-  }
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/grpc_client_thread.h b/chromeos/ash/services/libassistant/grpc/grpc_client_thread.h
deleted file mode 100644
index e97e493..0000000
--- a/chromeos/ash/services/libassistant/grpc/grpc_client_thread.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_CLIENT_THREAD_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_CLIENT_THREAD_H_
-
-#include <memory>
-#include <string>
-
-#include "base/synchronization/lock.h"
-#include "base/threading/platform_thread.h"
-#include "base/threading/thread.h"
-#include "third_party/grpc/source/include/grpcpp/completion_queue.h"
-
-namespace ash::libassistant {
-
-// This thread could be shared by multiple grpc clients. It needs to be
-// destroyed after the clients.
-class GrpcClientThread {
- public:
-  explicit GrpcClientThread(
-      const std::string& thread_name,
-      base::ThreadType thread_type = base::ThreadType::kDefault);
-  GrpcClientThread(const GrpcClientThread&) = delete;
-  GrpcClientThread& operator=(const GrpcClientThread&) = delete;
-  ~GrpcClientThread();
-
-  grpc::CompletionQueue* completion_queue() { return &completion_queue_; }
-
- private:
-  // Start polling the completion queue.
-  void StartCQ();
-  // Shutdown the CQ, stop CQ thread, then drain CQ
-  void StopCQ();
-
-  void ScanCQInternal();
-
-  grpc::CompletionQueue completion_queue_;
-  // Thread to poll the completion queue. Unlike the CQ thread initiated in
-  // |ServicesInitializerBase| and used by assistant gRPC server, this thread
-  // will *not* be responsible for cleaning up tags returned by calling
-  // completion_queue_->Next(). Each tag object will need to delete itself
-  // once finished.
-  base::Thread thread_;
-
-  base::Lock cq_shutdown_lock_;
-  bool is_cq_shutdown_ = false;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_CLIENT_THREAD_H_
diff --git a/chromeos/ash/services/libassistant/grpc/grpc_http_connection_client.cc b/chromeos/ash/services/libassistant/grpc/grpc_http_connection_client.cc
deleted file mode 100644
index a6685fa8..0000000
--- a/chromeos/ash/services/libassistant/grpc/grpc_http_connection_client.cc
+++ /dev/null
@@ -1,310 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/grpc_http_connection_client.h"
-
-#include "base/functional/bind.h"
-#include "base/notreached.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_client_thread.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_http_connection_delegate.h"
-#include "chromeos/assistant/internal/grpc_transport/streaming/bidi_streaming_rpc_call.h"
-#include "chromeos/assistant/internal/grpc_transport/streaming/streaming_write_queue.h"
-#include "third_party/grpc/source/include/grpc/grpc_security_constants.h"
-#include "third_party/grpc/source/include/grpc/impl/codegen/grpc_types.h"
-#include "third_party/grpc/source/include/grpcpp/create_channel.h"
-#include "third_party/grpc/source/include/grpcpp/security/credentials.h"
-#include "third_party/grpc/source/include/grpcpp/security/server_credentials.h"
-#include "third_party/grpc/source/include/grpcpp/support/channel_arguments.h"
-
-namespace ash::libassistant {
-
-namespace {
-using ::assistant::api::StreamHttpConnectionRequest;
-using ::assistant::api::StreamHttpConnectionResponse;
-using assistant_client::HttpConnection;
-using ::chromeos::libassistant::BidiStreamingRpcCall;
-using ::chromeos::libassistant::StreamingWriteQueue;
-using ::chromeos::libassistant::StreamingWriter;
-
-HttpConnection::Method ConvertToHttpConnectionMethod(
-    StreamHttpConnectionResponse::Method method) {
-  switch (method) {
-    case StreamHttpConnectionResponse::GET:
-      return HttpConnection::GET;
-    case StreamHttpConnectionResponse::POST:
-      return HttpConnection::POST;
-    case StreamHttpConnectionResponse::HEAD:
-      return HttpConnection::HEAD;
-    case StreamHttpConnectionResponse::PATCH:
-      return HttpConnection::PATCH;
-    case StreamHttpConnectionResponse::PUT:
-      return HttpConnection::PUT;
-    case StreamHttpConnectionResponse::DELETE:
-      return HttpConnection::DELETE;
-    case StreamHttpConnectionResponse::METHOD_UNSPECIFIED:
-      NOTREACHED();
-  }
-}
-
-// A macro which ensures we are running on the calling sequence.
-#define ENSURE_CALLING_SEQUENCE(method, ...)                                \
-  DVLOG(3) << __func__;                                                     \
-  if (!task_runner_->RunsTasksInCurrentSequence()) {                        \
-    task_runner_->PostTask(                                                 \
-        FROM_HERE,                                                          \
-        base::BindOnce(method, weak_factory_.GetWeakPtr(), ##__VA_ARGS__)); \
-    return;                                                                 \
-  }
-
-}  // namespace
-
-GrpcHttpConnectionClient::GrpcHttpConnectionClient(
-    assistant_client::HttpConnectionFactory* http_connection_factory,
-    const std::string& server_address)
-    : http_connection_factory_(http_connection_factory),
-      cq_thread_(std::make_unique<GrpcClientThread>("http_connection_cq")),
-      task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {
-  // Make sure to turn off compression.
-  grpc::ChannelArguments channel_args;
-  channel_args.SetInt(GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS, 200);
-  channel_args.SetInt(GRPC_ARG_MIN_RECONNECT_BACKOFF_MS, 200);
-  channel_args.SetInt(GRPC_ARG_MAX_RECONNECT_BACKOFF_MS, 2000);
-  channel_args.SetCompressionAlgorithm(
-      grpc_compression_algorithm::GRPC_COMPRESS_NONE);
-  grpc_local_connect_type connect_type =
-      GetGrpcLocalConnectType(server_address);
-  channel_ = grpc::CreateCustomChannel(
-      server_address, grpc::experimental::LocalCredentials(connect_type),
-      channel_args);
-  stub_ = ::assistant::api::HttpConnectionService::NewStub(channel_);
-}
-
-GrpcHttpConnectionClient::~GrpcHttpConnectionClient() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-
-  CleanUp();
-
-  {
-    base::AutoLock lock(write_queue_lock_);
-    is_shutting_down_ = true;
-  }
-
-  if (call_) {
-    {
-      base::AutoLock lock(write_queue_lock_);
-      write_queue_.reset();
-    }
-
-    call_->TryCancel();
-    cq_thread_.reset();
-  }
-}
-
-void GrpcHttpConnectionClient::Start() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-
-  if (call_) {
-    {
-      base::AutoLock lock(write_queue_lock_);
-      write_queue_.reset();
-    }
-
-    call_->TryCancel();
-    call_.reset();
-  }
-
-  {
-    base::AutoLock lock(write_queue_lock_);
-    write_queue_ =
-        std::make_unique<StreamingWriteQueue<StreamHttpConnectionRequest>>();
-  }
-
-  // Create a bidi streaming call to relay http connection from Libassistant.
-  BidiStreamingRpcCall<StreamHttpConnectionRequest,
-                       StreamHttpConnectionResponse>::CallbackParams cb_params;
-  cb_params.write_available_cb = base::BindRepeating(
-      &GrpcHttpConnectionClient::OnRpcWriteAvailable, base::Unretained(this));
-  cb_params.read_available_cb = base::BindRepeating(
-      &GrpcHttpConnectionClient::OnRpcReadAvailable, base::Unretained(this));
-  cb_params.exited_cb = base::BindRepeating(
-      &GrpcHttpConnectionClient::OnRpcExited, base::Unretained(this));
-  call_ = std::make_unique<BidiStreamingRpcCall<StreamHttpConnectionRequest,
-                                                StreamHttpConnectionResponse>>(
-      std::move(cb_params));
-  auto stream = stub_->PrepareAsyncStreamHttpConnection(
-      call_->ctx(), cq_thread_->completion_queue());
-  call_->Start(std::move(stream));
-}
-
-void GrpcHttpConnectionClient::CleanUp() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-
-  // In case |http_connections_| is non-empty, make sure `Close()` is called.
-  for (auto iter = http_connections_.begin(); iter != http_connections_.end();
-       ++iter) {
-    iter->second->Close();
-  }
-  http_connections_.clear();
-  delegates_.clear();
-}
-
-void GrpcHttpConnectionClient::ScheduleRequest(
-    StreamHttpConnectionRequest request) {
-  base::AutoLock lock(write_queue_lock_);
-  if (is_shutting_down_) {
-    return;
-  }
-
-  if (write_queue_) {
-    write_queue_->ScheduleWrite(std::move(request));
-  }
-}
-
-// Called when the RPC channel is idle and ready to accept new write.
-void GrpcHttpConnectionClient::OnRpcWriteAvailable(
-    grpc::ClientContext* context,
-    StreamingWriter<StreamHttpConnectionRequest>* writer) {
-  {
-    base::AutoLock lock(write_queue_lock_);
-    if (is_shutting_down_) {
-      return;
-    }
-  }
-
-  if (!init_request_sent_) {
-    DVLOG(1) << "Sending GrpcHttpConnectionClient registration request.";
-    init_request_sent_ = true;
-    // Send initial request to signal readiness for streaming.
-    StreamHttpConnectionRequest request;
-    request.set_command(StreamHttpConnectionRequest::REGISTER);
-    writer->Write(std::move(request));
-    return;
-  }
-
-  {
-    base::AutoLock lock(write_queue_lock_);
-
-    if (write_queue_) {
-      write_queue_->OnRpcWriteAvailable(writer);
-    }
-  }
-}
-
-void GrpcHttpConnectionClient::OnRpcReadAvailable(
-    grpc::ClientContext* context,
-    const StreamHttpConnectionResponse& response) {
-  ENSURE_CALLING_SEQUENCE(&GrpcHttpConnectionClient::OnRpcReadAvailable,
-                          context, response);
-
-  DCHECK(response.has_id());
-  const int http_connection_id = response.id();
-  const auto iter = http_connections_.find(http_connection_id);
-  if (iter == http_connections_.end() &&
-      response.command() != StreamHttpConnectionResponse::CREATE) {
-    DVLOG(2) << "Ignoring the HttpConnection request because the http "
-                "connection does not exist.";
-    return;
-  }
-
-  switch (response.command()) {
-    case StreamHttpConnectionResponse::CREATE: {
-      DVLOG(1) << "StreamHttpConnectionResponse::CREATE";
-      if (iter != http_connections_.end()) {
-        LOG(ERROR) << "Failed to create the http connection because of "
-                      "duplicated id: "
-                   << http_connection_id;
-        return;
-      }
-      {
-        DVLOG(1) << "Ceate the http connection " << http_connection_id;
-        auto* delegate =
-            new GrpcHttpConnectionDelegate(http_connection_id, this);
-        auto* http_connection = http_connection_factory_->Create(delegate);
-        http_connections_.insert({http_connection_id, http_connection});
-        delegates_.insert({http_connection_id, delegate});
-      }
-      break;
-    }
-    case StreamHttpConnectionResponse::START: {
-      DVLOG(1) << "StreamHttpConnectionResponse::START";
-      DCHECK(response.has_parameters());
-      const auto& param = response.parameters();
-      auto* http_connection = iter->second.get();
-      http_connection->SetRequest(
-          param.url(), ConvertToHttpConnectionMethod(param.method()));
-      for (const auto& header : param.headers()) {
-        http_connection->AddHeader(header.name(), header.value());
-      }
-      if (!param.upload_content_type().empty()) {
-        DCHECK(param.chunked_upload_content_type().empty());
-        http_connection->SetUploadContent(param.upload_content(),
-                                          param.upload_content_type());
-      } else if (!param.chunked_upload_content_type().empty()) {
-        DCHECK(param.upload_content_type().empty());
-        http_connection->SetChunkedUploadContentType(
-            param.chunked_upload_content_type());
-      }
-      if (param.enable_header_response()) {
-        http_connection->EnableHeaderResponse();
-      }
-      if (param.enable_partial_response()) {
-        http_connection->EnablePartialResults();
-      }
-      http_connection->Start();
-      break;
-    }
-    case StreamHttpConnectionResponse::PAUSE:
-      DVLOG(1) << "StreamHttpConnectionResponse::PAUSE";
-      iter->second->Pause();
-      break;
-    case StreamHttpConnectionResponse::RESUME:
-      DVLOG(1) << "StreamHttpConnectionResponse::RESUME";
-      iter->second->Resume();
-      break;
-    case StreamHttpConnectionResponse::CLOSE: {
-      DVLOG(1) << "StreamHttpConnectionResponse::CLOSE";
-      iter->second->Close();
-      http_connections_.erase(iter);
-
-      const auto delegate_iter = delegates_.find(http_connection_id);
-      DCHECK(delegate_iter != delegates_.end());
-      delegates_.erase(delegate_iter);
-      break;
-    }
-    case StreamHttpConnectionResponse::UPLOAD_DATA:
-      DVLOG(1) << "StreamHttpConnectionResponse::UPLOAD_DATA";
-      iter->second->UploadData(response.chunked_data().data(),
-                               response.chunked_data().is_last_chunk());
-      break;
-    case StreamHttpConnectionResponse::COMMAND_UNSPECIFIED:
-      NOTREACHED();
-  }
-}
-
-void GrpcHttpConnectionClient::OnRpcExited(grpc::ClientContext* context,
-                                           const grpc::Status& status) {
-  ENSURE_CALLING_SEQUENCE(&GrpcHttpConnectionClient::OnRpcExited, context,
-                          status);
-  DVLOG(1) << "GrpcHttpConnectionClient streaming exited with status "
-           << (status.ok() ? "ok" : status.error_message());
-  init_request_sent_ = false;
-  // If the streaming session failed unexpectedly. Since client (this class) is
-  // the one who initiates the streaming connection, it's the only one who can
-  // repair a broken session. The server (Libassistant) is helpless in this
-  // case, so it's important that the client diligently maintains a healthy
-  // connection.
-  if (!status.ok()) {
-    DVLOG(2) << "Retry to establish GrpcHttpConnection streaming session.";
-    task_runner_->PostTask(FROM_HERE,
-                           base::BindOnce(&GrpcHttpConnectionClient::Start,
-                                          weak_factory_.GetWeakPtr()));
-  } else {
-    DVLOG(1) << "GrpcHttpConnection exited.";
-  }
-
-  CleanUp();
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/grpc_http_connection_client.h b/chromeos/ash/services/libassistant/grpc/grpc_http_connection_client.h
deleted file mode 100644
index 6c7073ea..0000000
--- a/chromeos/ash/services/libassistant/grpc/grpc_http_connection_client.h
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_HTTP_CONNECTION_CLIENT_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_HTTP_CONNECTION_CLIENT_H_
-
-#include <memory>
-#include <string>
-
-#include "base/containers/flat_map.h"
-#include "base/memory/raw_ptr.h"
-#include "base/synchronization/lock.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_client_thread.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_state.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_util.h"
-#include "chromeos/assistant/internal/grpc_transport/streaming/bidi_streaming_rpc_call.h"
-#include "chromeos/assistant/internal/grpc_transport/streaming/streaming_write_queue.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/http_connection_service.grpc.pb.h"
-#include "third_party/grpc/source/include/grpcpp/channel.h"
-
-namespace ash::libassistant {
-
-class GrpcHttpConnectionClient {
- public:
-  GrpcHttpConnectionClient(
-      assistant_client::HttpConnectionFactory* http_connection_factory,
-      const std::string& server_address);
-  GrpcHttpConnectionClient(const GrpcHttpConnectionClient&) = delete;
-  GrpcHttpConnectionClient& operator=(const GrpcHttpConnectionClient&) = delete;
-  ~GrpcHttpConnectionClient();
-
-  void set_http_connection_factory(
-      assistant_client::HttpConnectionFactory* http_connection_factory) {
-    http_connection_factory_ = http_connection_factory;
-  }
-
-  void ScheduleRequest(::assistant::api::StreamHttpConnectionRequest request);
-
-  // Starts to register itself as a client of Libassistant gRPC http connection
-  // service.
-  void Start();
-
- private:
-  friend class TestGrpcHttpConnectionService;
-
-  void CleanUp();
-
-  void OnRpcWriteAvailable(
-      grpc::ClientContext* context,
-      chromeos::libassistant::StreamingWriter<
-          ::assistant::api::StreamHttpConnectionRequest>* writer);
-  void OnRpcReadAvailable(
-      grpc::ClientContext* context,
-      const ::assistant::api::StreamHttpConnectionResponse& request);
-  void OnRpcExited(grpc::ClientContext* context, const grpc::Status& status);
-
-  // `http_connection_factory_` must outlive this class.
-  raw_ptr<assistant_client::HttpConnectionFactory> http_connection_factory_;
-
-  // The following section is only accessed by the constructor thread.
-  // Thread running the completion queue.  CQ has to be shutdown before we
-  // destroy |call_|.
-  // NOTE: All http connections share the same CQ. If there is any problem, e.g.
-  // latency, we probably can create one GrpcHttpConnectionClient for one http
-  // connection.
-  std::unique_ptr<GrpcClientThread> cq_thread_;
-  // This channel will be shared between all http connections used to
-  // communicate with server. All channels are reference counted and will be
-  // freed automatically.
-  std::shared_ptr<grpc::Channel> channel_;
-  std::unique_ptr<::assistant::api::HttpConnectionService::Stub> stub_;
-  std::unique_ptr<chromeos::libassistant::BidiStreamingRpcCall<
-      ::assistant::api::StreamHttpConnectionRequest,
-      ::assistant::api::StreamHttpConnectionResponse>>
-      call_;
-
-  // The following section is only accessed by the CQ thread.
-  // `init_request_sent_` is only modified by `OnRpcWriteAvailable()` which is
-  // guaranteed to be called in sequence by the gRPC runtime, so there's no
-  // concurrency issue. No lock needed.
-  bool init_request_sent_ = false;
-
-  // Lock for |write_queue_| which could be accessed from the different threads.
-  base::Lock write_queue_lock_;
-  std::unique_ptr<chromeos::libassistant::StreamingWriteQueue<
-      ::assistant::api::StreamHttpConnectionRequest>>
-      write_queue_ GUARDED_BY(write_queue_lock_);
-  bool is_shutting_down_ GUARDED_BY(write_queue_lock_) = false;
-
-  // `http_connection` owns itself and will be deleted when `Close()` is called.
-  // When clean up `http_connections_`, will call `Close()` on the elements.
-  base::flat_map<int,
-                 raw_ptr<assistant_client::HttpConnection, CtnExperimental>>
-      http_connections_;
-  // `delegate` owns itself.
-  base::flat_map<
-      int,
-      raw_ptr<assistant_client::HttpConnection::Delegate, CtnExperimental>>
-      delegates_;
-
-  const scoped_refptr<base::SequencedTaskRunner> task_runner_;
-  base::WeakPtrFactory<GrpcHttpConnectionClient> weak_factory_{this};
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_HTTP_CONNECTION_CLIENT_H_
diff --git a/chromeos/ash/services/libassistant/grpc/grpc_http_connection_client_unittests.cc b/chromeos/ash/services/libassistant/grpc/grpc_http_connection_client_unittests.cc
deleted file mode 100644
index 2897f43..0000000
--- a/chromeos/ash/services/libassistant/grpc/grpc_http_connection_client_unittests.cc
+++ /dev/null
@@ -1,454 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/grpc_http_connection_client.h"
-
-#include "base/memory/raw_ptr.h"
-#include "base/run_loop.h"
-#include "base/test/task_environment.h"
-#include "chromeos/assistant/internal/grpc_transport/streaming/streaming_writer.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/http_connection_interface.pb.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-using ::assistant::api::StreamHttpConnectionRequest;
-using ::assistant::api::StreamHttpConnectionResponse;
-using assistant_client::HttpConnection;
-
-MATCHER_P(SerializedProtoEquals, message, "") {
-  std::string expected_serialized, actual_serialized;
-  message.SerializeToString(&expected_serialized);
-  arg.SerializeToString(&actual_serialized);
-  return expected_serialized == actual_serialized;
-}
-
-class MockHttpConnection : public HttpConnection {
- public:
-  explicit MockHttpConnection(HttpConnection::Delegate* delegate)
-      : delegate_(delegate) {}
-  MockHttpConnection(const MockHttpConnection&) = delete;
-  MockHttpConnection& operator=(const MockHttpConnection&) = delete;
-  ~MockHttpConnection() override = default;
-
-  // assistant_client::HttpConnection implementation:
-  MOCK_METHOD(void,
-              SetRequest,
-              (const std::string& url, HttpConnection::Method),
-              (override));
-  MOCK_METHOD(void,
-              AddHeader,
-              (const std::string& name, const std::string& value),
-              (override));
-  MOCK_METHOD(void,
-              SetUploadContent,
-              (const std::string& content, const std::string& content_type),
-              (override));
-  MOCK_METHOD(void,
-              SetChunkedUploadContentType,
-              (const std::string& content_type),
-              (override));
-  MOCK_METHOD(void, EnableHeaderResponse, (), (override));
-  MOCK_METHOD(void, EnablePartialResults, (), (override));
-  MOCK_METHOD(void, Start, (), (override));
-  MOCK_METHOD(void, Pause, (), (override));
-  MOCK_METHOD(void, Resume, (), (override));
-  MOCK_METHOD(void, Close, (), (override));
-  MOCK_METHOD(void,
-              UploadData,
-              (const std::string& data, bool is_last_chunk),
-              (override));
-
-  void SendOnHeaderResponse(const std::string& raw_headers) {
-    delegate_->OnHeaderResponse(raw_headers);
-  }
-
-  void SendOnPartialResponse(const std::string& partial_response) {
-    delegate_->OnPartialResponse(partial_response);
-  }
-
-  void SendOnCompleteResponse(int http_status,
-                              const std::string& raw_headers,
-                              const std::string& response) {
-    delegate_->OnCompleteResponse(http_status, raw_headers, response);
-  }
-
-  void SendOnNetworkError(int error_code, const std::string& message) {
-    delegate_->OnNetworkError(error_code, message);
-  }
-
-  void SendOnConnectionDestroyed() { delegate_->OnConnectionDestroyed(); }
-
- private:
-  raw_ptr<HttpConnection::Delegate> delegate_;
-};
-
-class TestHttpConnectionFactory
-    : public assistant_client::HttpConnectionFactory {
- public:
-  TestHttpConnectionFactory() = default;
-  TestHttpConnectionFactory(const TestHttpConnectionFactory&) = delete;
-  TestHttpConnectionFactory& operator=(const TestHttpConnectionFactory&) =
-      delete;
-  ~TestHttpConnectionFactory() override = default;
-
-  // assistant_client::HttpConnectionFactory implementation:
-  HttpConnection* Create(HttpConnection::Delegate* delegate) override {
-    http_connection_ = std::make_unique<MockHttpConnection>(delegate);
-    return http_connection_.get();
-  }
-
-  MockHttpConnection* http_connection() { return http_connection_.get(); }
-
- private:
-  std::unique_ptr<MockHttpConnection> http_connection_;
-};
-
-class MockStreamingWriter : public chromeos::libassistant::StreamingWriter<
-                                StreamHttpConnectionRequest> {
- public:
-  MockStreamingWriter() = default;
-  ~MockStreamingWriter() override = default;
-
-  // StreamingWriter implementation:
-  MOCK_METHOD(void, Write, (StreamHttpConnectionRequest msg), (override));
-  MOCK_METHOD(void, WritesDone, (), (override));
-};
-
-}  // namespace
-
-class TestGrpcHttpConnectionService {
- public:
-  explicit TestGrpcHttpConnectionService(GrpcHttpConnectionClient* client)
-      : client_(client) {
-    CreateWriter();
-  }
-
-  TestGrpcHttpConnectionService(const TestGrpcHttpConnectionService&) = delete;
-  TestGrpcHttpConnectionService& operator=(
-      const TestGrpcHttpConnectionService&) = delete;
-  ~TestGrpcHttpConnectionService() = default;
-
-  void SendCreateCommand() {
-    StreamHttpConnectionResponse response;
-    response.set_id(1);
-    response.set_command(StreamHttpConnectionResponse::CREATE);
-    WriteResponse(std::move(response));
-  }
-
-  void SendStartCommand(
-      const std::string& url,
-      StreamHttpConnectionResponse::Method method,
-      const std::vector<std::pair<std::string, std::string>>& headers,
-      const std::string& upload_content,
-      const std::string& upload_content_type,
-      bool enable_header_response,
-      bool handle_partial_response) {
-    StreamHttpConnectionResponse response;
-    response.set_id(1);
-    response.set_command(StreamHttpConnectionResponse::START);
-    auto* parameters = response.mutable_parameters();
-    parameters->set_url(url);
-    parameters->set_method(method);
-    for (const auto& header : headers) {
-      auto* new_header = parameters->add_headers();
-      new_header->set_name(header.first);
-      new_header->set_value(header.second);
-    }
-    parameters->set_upload_content(upload_content);
-    parameters->set_upload_content_type(upload_content_type);
-    parameters->set_enable_header_response(enable_header_response);
-    parameters->set_enable_partial_response(handle_partial_response);
-    WriteResponse(std::move(response));
-  }
-
-  void SendPauseCommand() {
-    StreamHttpConnectionResponse response;
-    response.set_id(1);
-    response.set_command(StreamHttpConnectionResponse::PAUSE);
-    WriteResponse(std::move(response));
-  }
-
-  void SendResumeCommand() {
-    StreamHttpConnectionResponse response;
-    response.set_id(1);
-    response.set_command(StreamHttpConnectionResponse::RESUME);
-    WriteResponse(std::move(response));
-  }
-
-  void SendCloseCommand() {
-    StreamHttpConnectionResponse response;
-    response.set_id(1);
-    response.set_command(StreamHttpConnectionResponse::CLOSE);
-    WriteResponse(std::move(response));
-  }
-
-  void SendUploadDataCommand(const std::string& data, bool is_last_chunk) {
-    StreamHttpConnectionResponse response;
-    response.set_id(1);
-    response.set_command(StreamHttpConnectionResponse::UPLOAD_DATA);
-    auto* chunked_data = response.mutable_chunked_data();
-    chunked_data->set_data(data);
-    chunked_data->set_is_last_chunk(is_last_chunk);
-    WriteResponse(std::move(response));
-  }
-
-  void SetWriteAvailable() {
-    client_->OnRpcWriteAvailable(nullptr, writer_.get());
-  }
-  MockStreamingWriter& writer() { return *writer_; }
-  void CreateWriter() { writer_ = std::make_unique<MockStreamingWriter>(); }
-  void ResetWriter() { writer_.reset(); }
-
- private:
-  void WriteResponse(StreamHttpConnectionResponse response) {
-    client_->OnRpcReadAvailable(nullptr, response);
-  }
-
-  raw_ptr<GrpcHttpConnectionClient> client_;
-  std::unique_ptr<MockStreamingWriter> writer_;
-};
-
-class GrpcHttpConnectionClientTest : public testing::Test {
- public:
-  GrpcHttpConnectionClientTest() = default;
-  GrpcHttpConnectionClientTest(const GrpcHttpConnectionClientTest&) = delete;
-  GrpcHttpConnectionClientTest& operator=(const GrpcHttpConnectionClientTest&) =
-      delete;
-  ~GrpcHttpConnectionClientTest() override = default;
-
-  void SetUp() override {
-    client_ = std::make_unique<GrpcHttpConnectionClient>(
-        &http_connection_factory_,
-        /*server_address=*/"unix:///tmp/test.socket");
-    service_ = std::make_unique<TestGrpcHttpConnectionService>(client_.get());
-    client_->Start();
-  }
-
- protected:
-  MockHttpConnection* http_connection() {
-    return http_connection_factory_.http_connection();
-  }
-
-  base::test::SingleThreadTaskEnvironment environment_;
-  std::unique_ptr<TestGrpcHttpConnectionService> service_;
-  TestHttpConnectionFactory http_connection_factory_;
-  std::unique_ptr<GrpcHttpConnectionClient> client_;
-};
-
-TEST_F(GrpcHttpConnectionClientTest, CreateHttpConnection) {
-  service_->SendCreateCommand();
-  auto* connection = http_connection();
-  ASSERT_TRUE(connection);
-  EXPECT_CALL(*connection, Close());
-}
-
-TEST_F(GrpcHttpConnectionClientTest, StartHttpConnection) {
-  service_->SendCreateCommand();
-  auto* connection = http_connection();
-  ASSERT_TRUE(connection);
-
-  const std::string url = "url";
-  const auto method = StreamHttpConnectionResponse::POST;
-  std::vector<std::pair<std::string, std::string>> headers;
-  headers.push_back({"name", "value"});
-  const std::string upload_content = "upload_content";
-  const std::string upload_content_type = "upload_content_type";
-  const bool enable_header_response = true;
-  const bool handle_partial_response = true;
-
-  EXPECT_CALL(*connection, SetRequest(url, HttpConnection::POST));
-  EXPECT_CALL(*connection, AddHeader("name", "value"));
-  EXPECT_CALL(*connection,
-              SetUploadContent(upload_content, upload_content_type));
-  EXPECT_CALL(*connection, EnableHeaderResponse());
-  EXPECT_CALL(*connection, EnablePartialResults());
-  EXPECT_CALL(*connection, Start());
-  EXPECT_CALL(*connection, Close());
-  service_->SendStartCommand(url, method, headers, upload_content,
-                             upload_content_type, enable_header_response,
-                             handle_partial_response);
-}
-
-TEST_F(GrpcHttpConnectionClientTest, PauseHttpConnection) {
-  service_->SendCreateCommand();
-  auto* connection = http_connection();
-  ASSERT_TRUE(connection);
-
-  EXPECT_CALL(*connection, Pause());
-  EXPECT_CALL(*connection, Close());
-  service_->SendPauseCommand();
-}
-
-TEST_F(GrpcHttpConnectionClientTest, ResumeHttpConnection) {
-  service_->SendCreateCommand();
-  auto* connection = http_connection();
-  ASSERT_TRUE(connection);
-
-  EXPECT_CALL(*connection, Resume());
-  EXPECT_CALL(*connection, Close());
-  service_->SendResumeCommand();
-}
-
-TEST_F(GrpcHttpConnectionClientTest, CloseHttpConnection) {
-  service_->SendCreateCommand();
-  auto* connection = http_connection();
-  ASSERT_TRUE(connection);
-
-  EXPECT_CALL(*connection, Close()).Times(1);
-  service_->SendCloseCommand();
-}
-
-TEST_F(GrpcHttpConnectionClientTest, UploadData) {
-  service_->SendCreateCommand();
-  auto* connection = http_connection();
-  ASSERT_TRUE(connection);
-
-  const std::string data = "data";
-  const bool is_last_chunk = true;
-  EXPECT_CALL(*connection, UploadData(data, is_last_chunk));
-  EXPECT_CALL(*connection, Close());
-  service_->SendUploadDataCommand(data, is_last_chunk);
-}
-
-TEST_F(GrpcHttpConnectionClientTest, RegisterOnTheFirstWriteAvailable) {
-  StreamHttpConnectionRequest request;
-  request.set_command(StreamHttpConnectionRequest::REGISTER);
-  EXPECT_CALL(service_->writer(), Write(SerializedProtoEquals(request)));
-  // Will trigger registering client.
-  service_->SetWriteAvailable();
-}
-
-TEST_F(GrpcHttpConnectionClientTest, ReceiveOnHeaderResponse) {
-  StreamHttpConnectionRequest request;
-  request.set_command(StreamHttpConnectionRequest::REGISTER);
-  EXPECT_CALL(service_->writer(), Write(SerializedProtoEquals(request)));
-  // Will trigger registering client.
-  service_->SetWriteAvailable();
-
-  service_->SendCreateCommand();
-  auto* connection = http_connection();
-  ASSERT_TRUE(connection);
-  EXPECT_CALL(*connection, Close());
-
-  const std::string raw_headers = "raw_headers";
-  request.Clear();
-  request.set_id(1);
-  request.set_command(StreamHttpConnectionRequest::HANDLE_HEADER_RESPONSE);
-  request.set_raw_headers(raw_headers);
-  EXPECT_CALL(service_->writer(), Write(SerializedProtoEquals(request)));
-  service_->SetWriteAvailable();
-  connection->SendOnHeaderResponse(raw_headers);
-  base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(GrpcHttpConnectionClientTest, ReceiveOnPartialResponse) {
-  StreamHttpConnectionRequest request;
-  request.set_command(StreamHttpConnectionRequest::REGISTER);
-  EXPECT_CALL(service_->writer(), Write(SerializedProtoEquals(request)));
-  // Will trigger registering client.
-  service_->SetWriteAvailable();
-
-  service_->SendCreateCommand();
-  auto* connection = http_connection();
-  ASSERT_TRUE(connection);
-  EXPECT_CALL(*connection, Close());
-
-  const std::string partial_response = "partial_response";
-  request.Clear();
-  request.set_id(1);
-  request.set_command(StreamHttpConnectionRequest::HANDLE_PARTIAL_RESPONSE);
-  request.set_partial_response(partial_response);
-  EXPECT_CALL(service_->writer(), Write(SerializedProtoEquals(request)));
-  service_->SetWriteAvailable();
-  connection->SendOnPartialResponse(partial_response);
-  base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(GrpcHttpConnectionClientTest, ReceiveOnCompleteResponse) {
-  StreamHttpConnectionRequest request;
-  request.set_command(StreamHttpConnectionRequest::REGISTER);
-  EXPECT_CALL(service_->writer(), Write(SerializedProtoEquals(request)));
-  // Will trigger registering client.
-  service_->SetWriteAvailable();
-
-  service_->SendCreateCommand();
-  auto* connection = http_connection();
-  ASSERT_TRUE(connection);
-  EXPECT_CALL(*connection, Close());
-
-  int http_status = 200;
-  const std::string raw_headers = "raw_headers";
-  const std::string response = "response";
-  request.Clear();
-  request.set_id(1);
-  request.set_command(StreamHttpConnectionRequest::HANDLE_COMPLETE_RESPONSE);
-  auto* res = request.mutable_complete_response();
-  res->set_response_code(http_status);
-  res->set_raw_headers(raw_headers);
-  res->set_response(response);
-  EXPECT_CALL(service_->writer(), Write(SerializedProtoEquals(request)));
-  service_->SetWriteAvailable();
-  connection->SendOnCompleteResponse(http_status, raw_headers, response);
-  base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(GrpcHttpConnectionClientTest, ReceiveOnNetworkError) {
-  StreamHttpConnectionRequest request;
-  request.set_command(StreamHttpConnectionRequest::REGISTER);
-  EXPECT_CALL(service_->writer(), Write(SerializedProtoEquals(request)));
-  // Will trigger registering client.
-  service_->SetWriteAvailable();
-
-  service_->SendCreateCommand();
-  auto* connection = http_connection();
-  ASSERT_TRUE(connection);
-  EXPECT_CALL(*connection, Close());
-
-  int error_code = 501;
-  const std::string message = "message";
-  request.Clear();
-  request.set_id(1);
-  request.set_command(StreamHttpConnectionRequest::HANDLE_NETWORK_ERROR);
-  auto* error = request.mutable_error();
-  error->set_error_code(error_code);
-  error->set_error_message(message);
-  EXPECT_CALL(service_->writer(), Write(SerializedProtoEquals(request)));
-  service_->SetWriteAvailable();
-  connection->SendOnNetworkError(error_code, message);
-  base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(GrpcHttpConnectionClientTest, NotCrashWhenWriterGone) {
-  StreamHttpConnectionRequest request;
-  request.set_command(StreamHttpConnectionRequest::REGISTER);
-  EXPECT_CALL(service_->writer(), Write(SerializedProtoEquals(request)));
-  // Will trigger registering client.
-  service_->SetWriteAvailable();
-  base::RunLoop().RunUntilIdle();
-
-  service_->SendCreateCommand();
-  auto* connection = http_connection();
-  ASSERT_TRUE(connection);
-  EXPECT_CALL(*connection, Close());
-
-  const std::string raw_headers = "raw_headers";
-  request.Clear();
-  request.set_id(1);
-  request.set_command(StreamHttpConnectionRequest::HANDLE_HEADER_RESPONSE);
-  request.set_raw_headers(raw_headers);
-  connection->SendOnHeaderResponse(raw_headers);
-  EXPECT_CALL(service_->writer(), Write(SerializedProtoEquals(request)));
-
-  // Simulate the case that the writer becomes nullptr. Should not crash.
-  service_->SetWriteAvailable();
-  service_->ResetWriter();
-  base::RunLoop().RunUntilIdle();
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/grpc_http_connection_delegate.cc b/chromeos/ash/services/libassistant/grpc/grpc_http_connection_delegate.cc
deleted file mode 100644
index 20a20d9..0000000
--- a/chromeos/ash/services/libassistant/grpc/grpc_http_connection_delegate.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/grpc_http_connection_delegate.h"
-#include "base/task/sequenced_task_runner.h"
-
-namespace ash::libassistant {
-
-using ::assistant::api::StreamHttpConnectionRequest;
-
-GrpcHttpConnectionDelegate::GrpcHttpConnectionDelegate(
-    int id,
-    GrpcHttpConnectionClient* client)
-    : id_(id),
-      grpc_http_connection_client_(client),
-      task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {}
-
-GrpcHttpConnectionDelegate::~GrpcHttpConnectionDelegate() = default;
-
-void GrpcHttpConnectionDelegate::OnHeaderResponse(
-    const std::string& raw_headers) {
-  StreamHttpConnectionRequest request;
-  request.set_id(id_);
-  request.set_command(StreamHttpConnectionRequest::HANDLE_HEADER_RESPONSE);
-  request.set_raw_headers(raw_headers);
-  grpc_http_connection_client_->ScheduleRequest(request);
-}
-
-void GrpcHttpConnectionDelegate::OnPartialResponse(
-    const std::string& partial_response) {
-  StreamHttpConnectionRequest request;
-  request.set_id(id_);
-  request.set_command(StreamHttpConnectionRequest::HANDLE_PARTIAL_RESPONSE);
-  request.set_partial_response(partial_response);
-  grpc_http_connection_client_->ScheduleRequest(request);
-}
-
-void GrpcHttpConnectionDelegate::OnCompleteResponse(
-    int http_status,
-    const std::string& raw_headers,
-    const std::string& response) {
-  StreamHttpConnectionRequest request;
-  request.set_id(id_);
-  request.set_command(StreamHttpConnectionRequest::HANDLE_COMPLETE_RESPONSE);
-  auto* res = request.mutable_complete_response();
-  res->set_response_code(http_status);
-  res->set_raw_headers(raw_headers);
-  res->set_response(response);
-  grpc_http_connection_client_->ScheduleRequest(request);
-}
-
-void GrpcHttpConnectionDelegate::OnNetworkError(int error_code,
-                                                const std::string& message) {
-  StreamHttpConnectionRequest request;
-  request.set_id(id_);
-  request.set_command(StreamHttpConnectionRequest::HANDLE_NETWORK_ERROR);
-  auto* error = request.mutable_error();
-  error->set_error_code(error_code);
-  error->set_error_message(message);
-  grpc_http_connection_client_->ScheduleRequest(request);
-}
-
-void GrpcHttpConnectionDelegate::OnConnectionDestroyed() {
-  // Do not inform server to delete the delegate, which is handled by the server
-  // side.
-  task_runner_->DeleteSoon(FROM_HERE, this);
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/grpc_http_connection_delegate.h b/chromeos/ash/services/libassistant/grpc/grpc_http_connection_delegate.h
deleted file mode 100644
index 683c7b2..0000000
--- a/chromeos/ash/services/libassistant/grpc/grpc_http_connection_delegate.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_HTTP_CONNECTION_DELEGATE_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_HTTP_CONNECTION_DELEGATE_H_
-
-#include "base/memory/raw_ptr.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_http_connection_client.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-
-namespace ash::libassistant {
-
-// An interface invoked by GrpcHttpConnectionDelegate to relay the HTTP
-// responses to gRPC HttpConnectionService.
-class GrpcHttpConnectionDelegate
-    : public assistant_client::HttpConnection::Delegate {
- public:
-  GrpcHttpConnectionDelegate(int id, GrpcHttpConnectionClient* client);
-  GrpcHttpConnectionDelegate(const GrpcHttpConnectionDelegate&) = delete;
-  GrpcHttpConnectionDelegate& operator=(const GrpcHttpConnectionDelegate&) =
-      delete;
-  ~GrpcHttpConnectionDelegate() override;
-
-  // HttpConnection::Delegate:
-  void OnHeaderResponse(const std::string& raw_headers) override;
-  void OnPartialResponse(const std::string& partial_response) override;
-  void OnCompleteResponse(int http_status,
-                          const std::string& raw_headers,
-                          const std::string& response) override;
-  void OnNetworkError(int error_code, const std::string& message) override;
-  void OnConnectionDestroyed() override;
-
- private:
-  const int id_;
-  const raw_ptr<GrpcHttpConnectionClient> grpc_http_connection_client_ =
-      nullptr;
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_HTTP_CONNECTION_DELEGATE_H_
diff --git a/chromeos/ash/services/libassistant/grpc/grpc_libassistant_client.cc b/chromeos/ash/services/libassistant/grpc/grpc_libassistant_client.cc
deleted file mode 100644
index 14c1bd0..0000000
--- a/chromeos/ash/services/libassistant/grpc/grpc_libassistant_client.cc
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/grpc_libassistant_client.h"
-
-#include <memory>
-
-#include "base/check.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_util.h"
-#include "chromeos/assistant/internal/internal_constants.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/alarm_timer_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/audio_utils_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/bootup_settings_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/config_settings_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/customer_registration_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/action_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/display_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/event_notification_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/experiment_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/speaker_id_enrollment_interface.pb.h"
-
-namespace ash::libassistant {
-
-template <>
-std::string
-GetLibassistGrpcMethodName<::assistant::api::RegisterCustomerRequest>() {
-  // CustomerRegistrationService handles CustomerRegistrationRequest sent from
-  // libassistant customers to register themselves before allowing to use
-  // libassistant services.
-  return GetLibassistGrpcMethodName("CustomerRegistrationService",
-                                    "RegisterCustomer");
-}
-
-template <>
-std::string
-GetLibassistGrpcMethodName<::assistant::api::UpdateExperimentIdsRequest>() {
-  // ExperimentService.
-  return GetLibassistGrpcMethodName("ExperimentService", "UpdateExperimentIds");
-}
-
-template <>
-std::string
-GetLibassistGrpcMethodName<::assistant::api::RegisterEventHandlerRequest>() {
-  // EventNotificationService handles RegisterEventHandler sent from
-  // libassistant customers to register themselves for events.
-  return GetLibassistGrpcMethodName("EventNotificationService",
-                                    "RegisterEventHandler");
-}
-
-template <>
-std::string
-GetLibassistGrpcMethodName<::assistant::api::ResetAllDataAndShutdownRequest>() {
-  // ConfigSettingsService.
-  return GetLibassistGrpcMethodName("ConfigSettingsService",
-                                    "ResetAllDataAndShutdown");
-}
-
-template <>
-std::string
-GetLibassistGrpcMethodName<::assistant::api::OnDisplayRequestRequest>() {
-  // DisplayService handles display requests sent from libassistant customers.
-  return GetLibassistGrpcMethodName("DisplayService", "OnDisplayRequest");
-}
-
-template <>
-std::string GetLibassistGrpcMethodName<::assistant::api::SendQueryRequest>() {
-  // QueryService handles queries sent from libassistant customers.
-  return GetLibassistGrpcMethodName(chromeos::assistant::kQueryServiceName,
-                                    chromeos::assistant::kSendQueryMethodName);
-}
-
-template <>
-std::string
-GetLibassistGrpcMethodName<::assistant::api::RegisterActionModuleRequest>() {
-  // QueryService handles RegisterActionModule sent from
-  // libassistant customers to register themselves to handle actions.
-  return GetLibassistGrpcMethodName(
-      chromeos::assistant::kQueryServiceName,
-      chromeos::assistant::kRegisterActionModuleMethodName);
-}
-
-template <>
-std::string
-GetLibassistGrpcMethodName<::assistant::api::StartVoiceQueryRequest>() {
-  return GetLibassistGrpcMethodName(
-      chromeos::assistant::kQueryServiceName,
-      chromeos::assistant::kStartVoiceQueryMethodName);
-}
-
-template <>
-std::string GetLibassistGrpcMethodName<::assistant::api::StopQueryRequest>() {
-  return GetLibassistGrpcMethodName(chromeos::assistant::kQueryServiceName,
-                                    chromeos::assistant::kStopQueryMethodName);
-}
-
-template <>
-std::string GetLibassistGrpcMethodName<::assistant::api::SetAuthInfoRequest>() {
-  // Returns method used for sending authentication information to Libassistant.
-  // Can be called during or after bootup is completed.
-  return GetLibassistGrpcMethodName("BootupSettingsService", "SetAuthInfo");
-}
-
-template <>
-std::string
-GetLibassistGrpcMethodName<::assistant::api::SetInternalOptionsRequest>() {
-  // Return method used for sending internal options to Libassistant. Can be
-  // called during or after bootup is completed.
-  return GetLibassistGrpcMethodName("BootupSettingsService",
-                                    "SetInternalOptions");
-}
-
-template <>
-std::string
-GetLibassistGrpcMethodName<::assistant::api::UpdateAssistantSettingsRequest>() {
-  // Updates assistant settings on the server.
-  return GetLibassistGrpcMethodName("ConfigSettingsService",
-                                    "UpdateAssistantSettings");
-}
-
-template <>
-std::string
-GetLibassistGrpcMethodName<::assistant::api::GetAssistantSettingsRequest>() {
-  // Returns assistant settings from the server.
-  return GetLibassistGrpcMethodName("ConfigSettingsService",
-                                    "GetAssistantSettings");
-}
-
-template <>
-std::string
-GetLibassistGrpcMethodName<::assistant::api::SetLocaleOverrideRequest>() {
-  // Set the locale override of the device. This will override the locale
-  // obtained from user's assistant settings.
-  return GetLibassistGrpcMethodName("ConfigSettingsService",
-                                    "SetLocaleOverride");
-}
-
-template <>
-std::string
-GetLibassistGrpcMethodName<::assistant::api::EnableListeningRequest>() {
-  // Enables or disables Assistant listening on the device.
-  return GetLibassistGrpcMethodName("AudioUtilsService", "EnableListening");
-}
-
-template <>
-std::string
-GetLibassistGrpcMethodName<::assistant::api::AddTimeToTimerRequest>() {
-  return GetLibassistGrpcMethodName("AlarmTimerService", "AddTimeToTimer");
-}
-
-template <>
-std::string GetLibassistGrpcMethodName<::assistant::api::PauseTimerRequest>() {
-  return GetLibassistGrpcMethodName("AlarmTimerService", "PauseTimer");
-}
-
-template <>
-std::string GetLibassistGrpcMethodName<::assistant::api::RemoveTimerRequest>() {
-  return GetLibassistGrpcMethodName("AlarmTimerService", "RemoveTimer");
-}
-
-template <>
-std::string GetLibassistGrpcMethodName<::assistant::api::ResumeTimerRequest>() {
-  return GetLibassistGrpcMethodName("AlarmTimerService", "ResumeTimer");
-}
-
-template <>
-std::string GetLibassistGrpcMethodName<::assistant::api::GetTimersRequest>() {
-  return GetLibassistGrpcMethodName("AlarmTimerService", "GetTimers");
-}
-
-template <>
-std::string GetLibassistGrpcMethodName<
-    ::assistant::api::StartSpeakerIdEnrollmentRequest>() {
-  return GetLibassistGrpcMethodName("SpeakerIdEnrollmentService",
-                                    "StartSpeakerIdEnrollment");
-}
-
-template <>
-std::string GetLibassistGrpcMethodName<
-    ::assistant::api::CancelSpeakerIdEnrollmentRequest>() {
-  return GetLibassistGrpcMethodName("SpeakerIdEnrollmentService",
-                                    "CancelSpeakerIdEnrollment");
-}
-
-template <>
-std::string GetLibassistGrpcMethodName<
-    ::assistant::api::GetSpeakerIdEnrollmentInfoRequest>() {
-  return GetLibassistGrpcMethodName("SpeakerIdEnrollmentService",
-                                    "GetSpeakerIdEnrollmentInfo");
-}
-
-GrpcLibassistantClient::GrpcLibassistantClient(
-    std::shared_ptr<grpc::Channel> channel)
-    : channel_(std::move(channel)), client_thread_("gRPCLibassistantClient") {
-  DCHECK(channel_);
-}
-
-GrpcLibassistantClient::~GrpcLibassistantClient() = default;
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/grpc_libassistant_client.h b/chromeos/ash/services/libassistant/grpc/grpc_libassistant_client.h
deleted file mode 100644
index 3e15b01..0000000
--- a/chromeos/ash/services/libassistant/grpc/grpc_libassistant_client.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_LIBASSISTANT_CLIENT_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_LIBASSISTANT_CLIENT_H_
-
-#include <memory>
-#include <string>
-
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_client_thread.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_state.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_util.h"
-#include "third_party/grpc/source/include/grpcpp/channel.h"
-
-namespace ash::libassistant {
-
-// Return gRPC method names.
-template <typename Request>
-std::string GetLibassistGrpcMethodName();
-
-// Interface for all methods we as a client can invoke from Libassistant gRPC
-// services. All client methods should be implemented here to send the requests
-// to server. We only introduce methods that are currently in use.
-class GrpcLibassistantClient {
- public:
-  explicit GrpcLibassistantClient(std::shared_ptr<grpc::Channel> channel);
-  GrpcLibassistantClient(const GrpcLibassistantClient&) = delete;
-  GrpcLibassistantClient& operator=(const GrpcLibassistantClient&) = delete;
-  ~GrpcLibassistantClient();
-
-  // Calls an async client method. ResponseCallback will be invoked from
-  // caller's sequence. The raw pointer will be handled by |RPCState| internally
-  // and gets deleted upon completion of the RPC call.
-  template <typename Request, typename Response>
-  void CallServiceMethod(const Request& request,
-                         ResponseCallback<grpc::Status, Response> done,
-                         StateConfig state_config) {
-    new RPCState<Response>(
-        channel_, client_thread_.completion_queue(),
-        GetLibassistGrpcMethodName<Request>(), request, std::move(done),
-        /*callback_task_runner=*/base::SequencedTaskRunner::GetCurrentDefault(),
-        state_config);
-  }
-
- private:
-  // This channel will be shared between all stubs used to communicate with
-  // multiple services. All channels are reference counted and will be freed
-  // automatically.
-  std::shared_ptr<grpc::Channel> channel_;
-
-  // Thread running the completion queue.
-  GrpcClientThread client_thread_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_LIBASSISTANT_CLIENT_H_
diff --git a/chromeos/ash/services/libassistant/grpc/grpc_state.h b/chromeos/ash/services/libassistant/grpc/grpc_state.h
deleted file mode 100644
index fa0e821..0000000
--- a/chromeos/ash/services/libassistant/grpc/grpc_state.h
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_STATE_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_STATE_H_
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/check.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/raw_ptr.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_util.h"
-#include "chromeos/assistant/internal/grpc_transport/grpc_client_cq_tag.h"
-#include "third_party/grpc/source/include/grpcpp/client_context.h"
-#include "third_party/grpc/source/include/grpcpp/generic/generic_stub.h"
-#include "third_party/grpc/source/include/grpcpp/grpcpp.h"
-#include "third_party/grpc/source/include/grpcpp/impl/codegen/client_context.h"
-#include "third_party/grpc/source/include/grpcpp/support/status.h"
-
-namespace google {
-namespace protobuf {
-class MessageLite;
-}  // namespace protobuf
-}  // namespace google
-
-namespace ash::libassistant {
-
-// Configs which dictate options for an RPCState instance.
-struct StateConfig {
-  StateConfig() = default;
-  ~StateConfig() = default;
-  StateConfig(int32_t retries, int64_t timeout_in_ms)
-      : max_retries(retries), timeout_in_ms(timeout_in_ms) {}
-
-  // The maximum retry attempts for the client call if it failed.
-  int32_t max_retries = 0;
-
-  // Deadline for the client call.
-  int64_t timeout_in_ms = 2000;
-
-  // If set to true, the RPC will be queued and not "fail fast" if the channel
-  // is in TRANSIENT_FAILURE or CONNECTING state, and wait until the channel
-  // turns READY. Otherwise, such gRPCs will be failed immediately.
-  bool wait_for_ready = true;
-};
-
-// Object allocated per active RPC.
-// Manage the state of a single asynchronous RPC request. If `max_retries`
-// is greater than 0, the request will be retried for any transient failures
-// as long as the overall deadline has not elapsed.
-template <class Response>
-class RPCState : public chromeos::libassistant::GrpcClientCQTag {
- public:
-  // Async RPCState constructor.
-  // Default behavior is to set wait_for_ready = true and handle timeouts
-  // manually.
-  RPCState(std::shared_ptr<grpc::Channel> channel,
-           grpc::CompletionQueue* cq,
-           const grpc::string& method,
-           const google::protobuf::MessageLite& request,
-           ResponseCallback<grpc::Status, Response> done,
-           scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
-           StateConfig config)
-      : async_cb_(std::move(done)),
-        callback_task_runner_(callback_task_runner),
-        cq_(cq),
-        stub_(channel),
-        method_(method),
-        timeout_in_ms_(config.timeout_in_ms),
-        max_retries_(config.max_retries),
-        wait_for_ready_(config.wait_for_ready) {
-    DCHECK(cq);
-    DCHECK(callback_task_runner);
-
-    grpc::Status s = GrpcSerializeProto(request, &request_buf_);
-    if (!s.ok()) {
-      LOG(ERROR) << "GrpcSerializeProto returned with non-ok status: "
-                 << s.error_message();
-      // Skip retry logic if we fail to parse our request.
-      StateDone();
-      return;
-    }
-
-    StartCall();
-  }
-
-  RPCState(const RPCState&) = delete;
-  RPCState& operator=(const RPCState&) = delete;
-  ~RPCState() override = default;
-
-  void StartCall() {
-    context_ = std::make_unique<grpc::ClientContext>();
-    context_->set_wait_for_ready(wait_for_ready_);
-
-    if (timeout_in_ms_ > 0) {
-      context_->set_deadline(
-          gpr_time_from_millis(timeout_in_ms_, GPR_TIMESPAN));
-    }
-
-    VLOG(3) << "Starting call: " << method_;
-    call_ = stub_.PrepareUnaryCall(context_.get(), method_, request_buf_, cq_);
-    call_->StartCall();
-    // Request that upon the completion of an RPC call, |response_buf_| will be
-    // updated with server's response. Tag the call with |this| to identify this
-    // request.
-    call_->Finish(&response_buf_, &status_, /*tag=*/this);
-  }
-
-  // GrpcClientCQTag overrides:
-  // Invoked from the completion queue thread.
-  void OnCompleted(State state) override {
-    VLOG(3) << "Completed call: " << method_;
-
-    if (state == State::kShutdown) {
-      LOG(WARNING) << "Unary RPC done with CQ has been shutting down.";
-      ParseAndCallDone();
-      return;
-    }
-
-    if (status_.ok() || status_.error_code() == grpc::StatusCode::CANCELLED) {
-      ParseAndCallDone();
-      return;
-    }
-
-    LOG_IF(WARNING, ShouldLogGrpcError())
-        << method_ << " returned with non-ok status: " << status_.error_code()
-        << " Retries: " << num_retries_ << " Max: " << max_retries_ << "\n";
-    // TODO(nanping): Retry only for logical errors by having them in the
-    // config.
-    // Retry if we have any attempts left
-    if (num_retries_ < max_retries_) {
-      ++num_retries_;
-      response_buf_.Clear();
-      LOG_IF(WARNING, ShouldLogGrpcError())
-          << "Retrying call for " << method_ << "Retry: " << num_retries_
-          << " of " << max_retries_;
-      StartCall();
-    } else {
-      // Attach additional GRPC error information if any to the final status
-      LOG_IF(ERROR, ShouldLogGrpcError()) << "RPC call failed :\n";
-      StateDone();
-    }
-  }
-
-  // Runs on the completion queue thread.
-  void ParseAndCallDone() {
-    if (!GrpcParseProto(&response_buf_, &async_response_)) {
-      LOG(ERROR) << "RPC parse response failed.";
-    }
-    StateDone();
-  }
-
-  // Run on the completion queue thread.
-  void StateDone() {
-    DCHECK(async_cb_);
-    // |async_cb_| must be invoked from its original sequence.
-    callback_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(std::move(async_cb_), status_, async_response_));
-
-    delete this;
-  }
-
- private:
-  bool ShouldLogGrpcError() {
-    // Some grpc errors are legitimate/expected. Ex: ReadSecureFile() may return
-    // NOT_FOUND if the file doesn't exist. Do not log warning/errors since it's
-    // just spam. The caller can log the error if desired.
-    return status_.error_code() != grpc::StatusCode::NOT_FOUND;
-  }
-
-  // An instance managing the context settings, e.g. deadline, relevant to the
-  // call they are invoked with. Same object should not be reused across RPCs.
-  std::unique_ptr<::grpc::ClientContext> context_;
-
-  // Message response of type |Response| received from the server.
-  Response async_response_;
-
-  // Buffer filled in with request/response.
-  grpc::ByteBuffer request_buf_;
-  grpc::ByteBuffer response_buf_;
-
-  // Status of a RPC call. The status is OK if the call finished with no errors.
-  grpc::Status status_;
-
-  // |async_cb_| must always be called from the main thread.
-  ResponseCallback<grpc::Status, Response> async_cb_;
-  scoped_refptr<base::SequencedTaskRunner> callback_task_runner_;
-
-  // An instance used by an async gRPC client to manage asynchronous rpc
-  // operations. An RPC call is bound to a CompletionQueue when performed
-  // using the stub.
-  raw_ptr<grpc::CompletionQueue> cq_ = nullptr;
-
-  // An instance used by a gRPC client to invoke rpc methods implemented in
-  // the server.
-  grpc::GenericStub stub_;
-
-  // An instance held a unary RPC call and exposes methods to start and finish
-  // the call with server's response.
-  std::unique_ptr<::grpc::GenericClientAsyncResponseReader> call_;
-
-  // The name of a RPC method.
-  grpc::string method_;
-
-  // Config options for a RPC call.
-  int64_t timeout_in_ms_;
-  size_t max_retries_;
-  bool wait_for_ready_;
-  size_t num_retries_ = 0;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_STATE_H_
diff --git a/chromeos/ash/services/libassistant/grpc/grpc_util.cc b/chromeos/ash/services/libassistant/grpc/grpc_util.cc
deleted file mode 100644
index fd77b0cc..0000000
--- a/chromeos/ash/services/libassistant/grpc/grpc_util.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/grpc_util.h"
-
-#include "base/check_op.h"
-#include "chromeos/assistant/internal/internal_constants.h"
-#include "third_party/grpc/source/include/grpcpp/impl/codegen/proto_utils.h"
-#include "third_party/grpc/source/include/grpcpp/support/proto_buffer_reader.h"
-#include "third_party/grpc/source/include/grpcpp/support/proto_buffer_writer.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-constexpr char kForwardSlash[] = "/";
-constexpr char kDomainPrefix[] = "unix://";
-
-std::string GetBaseDirectory(bool is_chromeos_device) {
-  return is_chromeos_device ? chromeos::assistant::kSocketDirectory
-                            : chromeos::assistant::kSocketTempDirectory;
-}
-
-}  // namespace
-
-grpc_local_connect_type GetGrpcLocalConnectType(
-    const std::string& server_address) {
-  // We only support unix socket on our platform.
-  DCHECK_EQ(server_address.compare(0, 4, "unix"), 0);
-  return UDS;
-}
-
-grpc::Status GrpcSerializeProto(const google::protobuf::MessageLite& src,
-                                grpc::ByteBuffer* dst) {
-  bool own_buffer;
-  return grpc::GenericSerialize<grpc::ProtoBufferWriter,
-                                google::protobuf::MessageLite>(src, dst,
-                                                               &own_buffer);
-}
-
-bool GrpcParseProto(grpc::ByteBuffer* src, google::protobuf::MessageLite* dst) {
-  grpc::ProtoBufferReader reader(src);
-  return dst->ParseFromZeroCopyStream(&reader);
-}
-
-std::string GetLibassistGrpcMethodName(const std::string& service,
-                                       const std::string& method) {
-  return std::string(kForwardSlash) +
-         chromeos::assistant::kLibassistGrpcServicePrefix + service +
-         kForwardSlash + method;
-}
-
-std::string GetLibassistGrpcServiceName(const std::string& event) {
-  return chromeos::assistant::kLibassistGrpcServicePrefix + event +
-         chromeos::assistant::kHandlerInterface;
-}
-
-std::string GetAssistantSocketFileName(bool is_chromeos_device) {
-  return GetBaseDirectory(is_chromeos_device) +
-         chromeos::assistant::kAssistantSocketName;
-}
-
-std::string GetLibassistantSocketFileName(bool is_chromeos_device) {
-  return GetBaseDirectory(is_chromeos_device) +
-         chromeos::assistant::kLibassistantSocketName;
-}
-
-std::string GetHttpConnectionSocketFileName(bool is_chromeos_device) {
-  return GetBaseDirectory(is_chromeos_device) +
-         chromeos::assistant::kHttpConnectionSocketName;
-}
-
-std::string GetAssistantServiceAddress(bool is_chromeos_device) {
-  return std::string(kDomainPrefix) +
-         GetAssistantSocketFileName(is_chromeos_device);
-}
-
-std::string GetLibassistantServiceAddress(bool is_chromeos_device) {
-  return std::string(kDomainPrefix) +
-         GetLibassistantSocketFileName(is_chromeos_device);
-}
-
-std::string GetHttpConnectionServiceAddress(bool is_chromeos_device) {
-  return std::string(kDomainPrefix) +
-         GetHttpConnectionSocketFileName(is_chromeos_device);
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/grpc_util.h b/chromeos/ash/services/libassistant/grpc/grpc_util.h
deleted file mode 100644
index 5362532..0000000
--- a/chromeos/ash/services/libassistant/grpc/grpc_util.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_UTIL_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_UTIL_H_
-
-#include <string>
-
-#include "base/functional/callback.h"
-#include "third_party/grpc/source/include/grpc/grpc_security_constants.h"
-#include "third_party/grpc/source/include/grpcpp/support/byte_buffer.h"
-#include "third_party/grpc/source/include/grpcpp/support/status.h"
-#include "third_party/protobuf/src/google/protobuf/message_lite.h"
-
-namespace ash::libassistant {
-
-template <class Status, class Response>
-using ResponseCallback =
-    base::OnceCallback<void(const Status&, const Response&)>;
-
-// Returns the local connection type for the given server address.
-grpc_local_connect_type GetGrpcLocalConnectType(
-    const std::string& server_address);
-
-// Serialize src and store in *dst.
-grpc::Status GrpcSerializeProto(const google::protobuf::MessageLite& src,
-                                grpc::ByteBuffer* dst);
-
-// Parse contents of src and initialize *dst with them.
-bool GrpcParseProto(grpc::ByteBuffer* src, google::protobuf::MessageLite* dst);
-
-// Creates a gRPC method name.
-std::string GetLibassistGrpcMethodName(const std::string& service,
-                                       const std::string& method);
-
-// Creates a gRPC event handler service name.
-std::string GetLibassistGrpcServiceName(const std::string& event);
-
-// `is_chromeos_device` indicates if it is running on a chromeos device or
-// linux.
-std::string GetAssistantSocketFileName(bool is_chromeos_device);
-std::string GetLibassistantSocketFileName(bool is_chromeos_device);
-std::string GetHttpConnectionSocketFileName(bool is_chromeos_device);
-
-std::string GetAssistantServiceAddress(bool is_chromeos_device);
-std::string GetLibassistantServiceAddress(bool is_chromeos_device);
-std::string GetHttpConnectionServiceAddress(bool is_chromeos_device);
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_GRPC_UTIL_H_
diff --git a/chromeos/ash/services/libassistant/grpc/rpc_method_driver.h b/chromeos/ash/services/libassistant/grpc/rpc_method_driver.h
deleted file mode 100644
index f22093c0..0000000
--- a/chromeos/ash/services/libassistant/grpc/rpc_method_driver.h
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_RPC_METHOD_DRIVER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_RPC_METHOD_DRIVER_H_
-
-#include <memory>
-
-#include "base/check.h"
-#include "base/functional/bind.h"
-#include "base/logging.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/sequence_checker.h"
-#include "base/threading/thread.h"
-#include "third_party/grpc/source/include/grpcpp/grpcpp.h"
-#include "third_party/grpc/source/include/grpcpp/server_context.h"
-
-namespace ash::libassistant {
-
-// Implements async RPC driver for an RPC method.
-// Request and Response are the RPC method's request and response protos.
-//
-// Sample usage for handling SetCapabilities() RPC method from service
-// ConversationInterface:
-//
-//  set_capabilities_rpc_driver_.reset(
-//      std::make_unique<RpcMethodDriver<SetCapabilitiesRequest,
-//      SetCapabilitiesResponse>>(
-//          cq,
-//          base::BindRepeating(
-//              &ConversationInterface::AsyncService::RequestSetCapabilities,
-//              service_.WeakPtr()),
-//          base::BindRepeating(
-//              &ConversationInterfaceImpl::SetCapabilities,
-//              conversation_interface_impl_.WeakPtr())));
-//
-template <class Request, class Response>
-class RpcMethodDriver {
- public:
-  // Callback object encapsulating service.Request##RpcMethod() which looks
-  // for next incoming RPC.
-  using ServiceRpcCallFn =
-      base::RepeatingCallback<void(grpc::ServerContext*,
-                                   Request*,
-                                   grpc::ServerAsyncResponseWriter<Response>*,
-                                   grpc::CompletionQueue*,
-                                   grpc::ServerCompletionQueue*,
-                                   void*)>;
-
-  // Callback object for calling RPC async business logic implementation.
-  using RpcImplAsyncFn = base::RepeatingCallback<void(
-      grpc::ServerContext*,
-      const Request*,
-      base::OnceCallback<void(const grpc::Status&, const Response&)>)>;
-
-  // Constructs the class and initializes the completion queue.
-  // cq: CompletionQueue
-  // service_rpc_call_fn: Callback object encapsulating
-  //         service.Request##RpcMethod() which looks for next incoming RPC.
-  // rpc_impl_async_fn: Callback object for calling implementation of
-  //              business logic of the RPC.
-  RpcMethodDriver(grpc::ServerCompletionQueue* cq,
-                  ServiceRpcCallFn service_rpc_call_fn,
-                  RpcImplAsyncFn rpc_impl_async_fn)
-      : cq_(cq),
-        service_rpc_call_fn_(service_rpc_call_fn),
-        rpc_impl_async_fn_(rpc_impl_async_fn) {
-    DCHECK(cq);
-    RequestNextRpc();
-  }
-
-  ~RpcMethodDriver() = default;
-  RpcMethodDriver(const RpcMethodDriver&) = delete;
-  RpcMethodDriver& operator=(const RpcMethodDriver&) = delete;
-
- private:
-  // Look for the next incoming RPC.
-  void RequestNextRpc() {
-    // Owned by CleanupAfterRpc() run at the end of the lifecycle of current
-    // RPC.
-    auto ctx = std::make_unique<grpc::ServerContext>();
-    auto request = std::make_unique<Request>();
-    auto responder =
-        std::make_unique<grpc::ServerAsyncResponseWriter<Response>>(ctx.get());
-
-    // Prestore valid pointers before std::move() nulls the smart pointers.
-    auto* ctx_ptr = ctx.get();
-    auto* request_ptr = request.get();
-    auto* responder_ptr = responder.get();
-
-    // A raw pointer has to be used here since |service_rpc_call_fn_| is
-    // expecting void* as the parameter. It will be deleted by server cq
-    // after being executed.
-    auto* process_rpc_cb = new base::OnceCallback<void(bool)>(
-        base::BindOnce(&RpcMethodDriver<Request, Response>::ProcessRpc,
-                       weak_factory_.GetWeakPtr(), std::move(ctx),
-                       std::move(request), std::move(responder)));
-
-    DCHECK(service_rpc_call_fn_);
-    service_rpc_call_fn_.Run(ctx_ptr, request_ptr, responder_ptr, cq_.get(),
-                             cq_.get(), process_rpc_cb);
-  }
-
-  // Process the RPC received.
-  void ProcessRpc(
-      std::unique_ptr<grpc::ServerContext> ctx,
-      std::unique_ptr<Request> request,
-      std::unique_ptr<grpc::ServerAsyncResponseWriter<Response>> responder,
-      bool ok) {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-    if (!ok) {
-      // If not okay, logs error and returns. Used data, i.e. ctx, will be
-      // cleaned up automatically when unique_ptrs go out of scope.
-      LOG(ERROR) << "OnEventFromLibas request not ok.";
-      return;
-    }
-
-    // Start waiting for the next RPC.
-    RequestNextRpc();
-
-    ExecuteRpc(std::move(ctx), std::move(request), std::move(responder));
-  }
-
-  // Execute the RPC received.
-  void ExecuteRpc(
-      std::unique_ptr<grpc::ServerContext> ctx,
-      std::unique_ptr<Request> request,
-      std::unique_ptr<grpc::ServerAsyncResponseWriter<Response>> responder) {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-    // Prestore valid pointers before std::move() nulls the smart pointers.
-    auto* ctx_ptr = ctx.get();
-    auto* request_ptr = request.get();
-    auto* responder_ptr = responder.get();
-
-    auto* finish_rpc_cb = new base::OnceCallback<void(bool)>(
-        base::BindOnce(&RpcMethodDriver<Request, Response>::CleanupAfterRpc,
-                       weak_factory_.GetWeakPtr(), std::move(ctx),
-                       std::move(request), std::move(responder)));
-
-    auto async_cb = base::BindOnce(
-        [](grpc::ServerAsyncResponseWriter<Response>* responder,
-           base::OnceCallback<void(bool)>* finish_rpc_cb,
-           const grpc::Status& status, const Response& response) {
-          responder->Finish(response, status, finish_rpc_cb);
-        },
-        responder_ptr, finish_rpc_cb);
-
-    DCHECK(rpc_impl_async_fn_);
-    // Call the async implementation of the RPC business logic.
-    rpc_impl_async_fn_.Run(ctx_ptr, request_ptr, std::move(async_cb));
-  }
-
-  void CleanupAfterRpc(
-      std::unique_ptr<grpc::ServerContext> ctx,
-      std::unique_ptr<Request> request,
-      std::unique_ptr<grpc::ServerAsyncResponseWriter<Response>> responder,
-      bool ignored_ok) {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-    DVLOG(3) << "OnEventFromLibas is finished.";
-
-    // Unique_ptrs will delete the objects after they go out of scope
-    // so no manual data clean-up needed here.
-  }
-
-  // Owned by |ServicesInitializerBase|.
-  raw_ptr<grpc::ServerCompletionQueue> cq_ = nullptr;
-
-  ServiceRpcCallFn service_rpc_call_fn_;
-  RpcImplAsyncFn rpc_impl_async_fn_;
-
-  // This sequence checker ensures that all callbacks are called on the
-  // main sequence.
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  base::WeakPtrFactory<RpcMethodDriver> weak_factory_{this};
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_RPC_METHOD_DRIVER_H_
diff --git a/chromeos/ash/services/libassistant/grpc/services_initializer_base.cc b/chromeos/ash/services/libassistant/grpc/services_initializer_base.cc
deleted file mode 100644
index eca173a..0000000
--- a/chromeos/ash/services/libassistant/grpc/services_initializer_base.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/services_initializer_base.h"
-
-#include <string>
-
-#include "base/functional/bind.h"
-#include "base/functional/callback_forward.h"
-#include "base/task/sequenced_task_runner.h"
-
-namespace ash::libassistant {
-
-ServicesInitializerBase::ServicesInitializerBase(
-    const std::string& cq_thread_name,
-    scoped_refptr<base::SequencedTaskRunner> main_task_runner)
-    : cq_thread_(cq_thread_name), main_task_runner_(main_task_runner) {
-  base::Thread::Options options(base::MessagePumpType::IO,
-                                0 /* default maximum stack size */);
-  options.thread_type = base::ThreadType::kDefault;
-  cq_thread_.StartWithOptions(std::move(options));
-}
-
-ServicesInitializerBase::~ServicesInitializerBase() {
-  StopCQ();
-}
-
-void ServicesInitializerBase::RegisterServicesAndInitCQ(
-    grpc::ServerBuilder* server_builder) {
-  // Register all services.
-  InitDrivers(server_builder);
-  // Get hold of the completion queue used for async gRPC runtime.
-  cq_ = server_builder->AddCompletionQueue();
-}
-
-void ServicesInitializerBase::StartCQ() {
-  // Initialize completion queues for each service.
-  for (auto* const driver : service_drivers_) {
-    driver->StartCQ(cq_.get());
-  }
-  cq_thread_.task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&ServicesInitializerBase::ScanCQInternal,
-                                base::Unretained(this)));
-}
-
-void ServicesInitializerBase::StopCQ() {
-  if (cq_) {
-    // Make sure |cq_thread_| quits before draining CQ in order to prevent race.
-    cq_->Shutdown();
-    cq_thread_.Stop();
-    // Drain CQ
-    void* ignored_tag;
-    bool ignored_ok;
-    while (cq_->Next(&ignored_tag, &ignored_ok)) {
-    }
-    cq_ = nullptr;
-  }
-
-  // If |cq_| was not created, no need to explicitly stop |cq_thread_| since
-  // Stop() will be called in its destructor.
-}
-
-// Runs on the cq polling thread.
-void ServicesInitializerBase::ScanCQInternal() {
-  // Poll the completion queue.
-  while (true) {
-    void* tag = nullptr;
-    bool ok = false;
-    if (!cq_->Next(&tag, &ok)) {
-      // Completion queue is shutting down.
-      DVLOG(3) << "Completion queue shutdown.";
-      break;
-    }
-    if (!tag) {
-      LOG(ERROR) << "Failed to fetch tag from completion queue.";
-      continue;
-    }
-    auto* cb_ptr = static_cast<base::OnceCallback<void(bool)>*>(tag);
-    // Use PostTask() to ensure callbacks are run on the same sequence on which
-    // they are bound.
-    main_task_runner_->PostTask(FROM_HERE,
-                                base::BindOnce(std::move(*cb_ptr), ok));
-    delete cb_ptr;
-  }
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/services_initializer_base.h b/chromeos/ash/services/libassistant/grpc/services_initializer_base.h
deleted file mode 100644
index 861b275a..0000000
--- a/chromeos/ash/services/libassistant/grpc/services_initializer_base.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_SERVICES_INITIALIZER_BASE_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_SERVICES_INITIALIZER_BASE_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/task/sequenced_task_runner.h"
-#include "base/threading/thread.h"
-#include "chromeos/ash/services/libassistant/grpc/async_service_driver.h"
-#include "third_party/grpc/source/include/grpcpp/completion_queue.h"
-#include "third_party/grpc/source/include/grpcpp/server_builder.h"
-
-namespace ash::libassistant {
-
-// Initializes all services exposed by libassistant.
-class ServicesInitializerBase {
- public:
-  ServicesInitializerBase(
-      const std::string& cq_thread_name,
-      scoped_refptr<base::SequencedTaskRunner> main_task_runner);
-  ServicesInitializerBase(const ServicesInitializerBase&) = delete;
-  ServicesInitializerBase& operator=(const ServicesInitializerBase&) = delete;
-  virtual ~ServicesInitializerBase();
-
-  // Registers all supported services and initializes completion queue.
-  // All services share the same completion queue.
-  // Does not take ownership of server_builder.
-  void RegisterServicesAndInitCQ(grpc::ServerBuilder* server_builder);
-
-  // Start polling the completion queue.
-  void StartCQ();
-  // Shutdown the CQ, stop CQ thread, then drain CQ
-  void StopCQ();
-
- protected:
-  // Registers all services with server_builder.
-  // Does not take ownership of server_builder.
-  virtual void InitDrivers(grpc::ServerBuilder* server_builder) = 0;
-
-  void ScanCQInternal();
-
-  std::unique_ptr<grpc::ServerCompletionQueue> cq_;
-
-  // Drivers are owned by the subclass that creates them, e.g.
-  // `GrpcServicesInitializer`.
-  std::vector<AsyncServiceDriver*> service_drivers_;
-
-  // Use a dedicated thread to poll completion queue. Will also responsible
-  // for cleaning up the tags returned by calling cq_->Next() after they are
-  // executed.
-  base::Thread cq_thread_;
-
-  // The task runner for the main thread.
-  scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_SERVICES_INITIALIZER_BASE_H_
diff --git a/chromeos/ash/services/libassistant/grpc/services_status_observer.h b/chromeos/ash/services/libassistant/grpc/services_status_observer.h
deleted file mode 100644
index 6f78c33..0000000
--- a/chromeos/ash/services/libassistant/grpc/services_status_observer.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_SERVICES_STATUS_OBSERVER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_SERVICES_STATUS_OBSERVER_H_
-
-#include "base/observer_list_types.h"
-
-namespace ash::libassistant {
-
-// Enums representing states of Libassistant services in the order of the
-// bootup progession. States are monotonic and cannot get reverted back to
-// any previous states once a state is reached.
-enum class ServicesStatus {
-  // Connection to the libassistant's gRPC service is not available.
-  OFFLINE,
-
-  // Services are booting up. Only a few core gRPC services will be available
-  // at this stage.
-  ONLINE_BOOTING_UP,
-
-  // All services are available and ready to take requests.
-  ONLINE_ALL_SERVICES_AVAILABLE,
-};
-
-class ServicesStatusObserver : public base::CheckedObserver {
- public:
-  virtual void OnServicesStatusChanged(ServicesStatus status) = 0;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_SERVICES_STATUS_OBSERVER_H_
diff --git a/chromeos/ash/services/libassistant/grpc/services_status_provider.cc b/chromeos/ash/services/libassistant/grpc/services_status_provider.cc
deleted file mode 100644
index f1e5ab6d..0000000
--- a/chromeos/ash/services/libassistant/grpc/services_status_provider.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/services_status_provider.h"
-
-#include "base/logging.h"
-#include "chromeos/ash/services/libassistant/grpc/services_status_observer.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-bool ConvertServerStatus(::assistant::api::LibasServerStatus input,
-                         ServicesStatus* output) {
-  switch (input) {
-    // We consider both states as booting up as a customer.
-    case ::assistant::api::CUSTOMER_REGISTRATION_SERVICE_AVAILABLE:
-    case ::assistant::api::ESSENTIAL_SERVICES_AVAILABLE:
-      *output = ServicesStatus::ONLINE_BOOTING_UP;
-      return true;
-    case ::assistant::api::ALL_SERVICES_AVAILABLE:
-      *output = ServicesStatus::ONLINE_ALL_SERVICES_AVAILABLE;
-      return true;
-    case ::assistant::api::UNKNOWN_LIBAS_SERVER_STATUS:
-      return false;
-  }
-}
-
-std::string GetServerStatusLogString(ServicesStatus status) {
-  switch (status) {
-    case ServicesStatus::OFFLINE:
-      return "Libassistant service is OFFLINE.";
-    case ServicesStatus::ONLINE_BOOTING_UP:
-      return "Libassistant service is BOOTING UP.";
-    case ServicesStatus::ONLINE_ALL_SERVICES_AVAILABLE:
-      return "Libassistant service is ALL READY.";
-  }
-}
-
-}  // namespace
-
-ServicesStatusProvider::ServicesStatusProvider() = default;
-
-ServicesStatusProvider::~ServicesStatusProvider() = default;
-
-void ServicesStatusProvider::OnGrpcMessage(
-    const ::assistant::api::OnHeartbeatEventRequest& request) {
-  if (!request.has_current_server_status()) {
-    LOG(ERROR) << "Heartbeat signal does not contain server status";
-    return;
-  }
-
-  auto old_status = status_;
-  if (!ConvertServerStatus(request.current_server_status(), &status_)) {
-    LOG(ERROR) << "Received unknown Libassistant server status";
-    return;
-  }
-
-  if (old_status != status_) {
-    DVLOG(3) << GetServerStatusLogString(status_);
-
-    // Notify observers on service status change.
-    for (auto& observer : observers_)
-      observer.OnServicesStatusChanged(status_);
-  }
-}
-
-void ServicesStatusProvider::AddObserver(ServicesStatusObserver* observer) {
-  observers_.AddObserver(observer);
-}
-
-void ServicesStatusProvider::RemoveObserver(ServicesStatusObserver* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/services_status_provider.h b/chromeos/ash/services/libassistant/grpc/services_status_provider.h
deleted file mode 100644
index c4d915b..0000000
--- a/chromeos/ash/services/libassistant/grpc/services_status_provider.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_SERVICES_STATUS_PROVIDER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_SERVICES_STATUS_PROVIDER_H_
-
-#include "base/observer_list.h"
-#include "base/observer_list_types.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/grpc_services_observer.h"
-#include "chromeos/ash/services/libassistant/grpc/services_status_observer.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_interface.pb.h"
-
-namespace ash::libassistant {
-
-// Component monitoring Libassistant gRPC services status, exposing method to
-// get current services status and notify observers on status change.
-class ServicesStatusProvider
-    : public GrpcServicesObserver<::assistant::api::OnHeartbeatEventRequest> {
- public:
-  ServicesStatusProvider();
-  ServicesStatusProvider(const ServicesStatusProvider&) = delete;
-  ServicesStatusProvider& operator=(const ServicesStatusProvider&) = delete;
-  ~ServicesStatusProvider() override;
-
-  // GrpcServiceObserver implementation:
-  void OnGrpcMessage(
-      const ::assistant::api::OnHeartbeatEventRequest& request) override;
-
-  void AddObserver(ServicesStatusObserver* observer);
-  void RemoveObserver(ServicesStatusObserver* observer);
-
- private:
-  ServicesStatus status_ = ServicesStatus::OFFLINE;
-
-  base::ObserverList<ServicesStatusObserver> observers_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_SERVICES_STATUS_PROVIDER_H_
diff --git a/chromeos/ash/services/libassistant/grpc/utils/media_status_utils.cc b/chromeos/ash/services/libassistant/grpc/utils/media_status_utils.cc
deleted file mode 100644
index edd03ea..0000000
--- a/chromeos/ash/services/libassistant/grpc/utils/media_status_utils.cc
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/utils/media_status_utils.h"
-
-#include "chromeos/ash/services/libassistant/public/mojom/media_controller.mojom.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-using PlaybackState = assistant_client::MediaStatus::PlaybackState;
-using TrackType = assistant_client::TrackType;
-
-PlaybackState ConvertPlaybackStateEnumToV1FromV2(
-    const MediaStatus::PlaybackState& state_proto) {
-  switch (state_proto) {
-    // New value in V2, treat as IDLE.
-    case MediaStatus::UNSPECIFIED:
-      return PlaybackState::IDLE;
-    case MediaStatus::IDLE:
-      return PlaybackState::IDLE;
-    case MediaStatus::NEW_TRACK:
-      return PlaybackState::NEW_TRACK;
-    case MediaStatus::PLAYING:
-      return PlaybackState::PLAYING;
-    case MediaStatus::PAUSED:
-      return PlaybackState::PAUSED;
-    case MediaStatus::ERROR:
-      return PlaybackState::ERROR;
-  }
-}
-
-TrackType ConvertTrackTypeEnumToV1FromV2(
-    const MediaStatus::TrackType& track_type_proto) {
-  switch (track_type_proto) {
-    // New value in V2, treat as NONE.
-    case MediaStatus::UNSUPPORTED:
-      return TrackType::MEDIA_TRACK_NONE;
-    case MediaStatus::MEDIA_TRACK_NONE:
-      return TrackType::MEDIA_TRACK_NONE;
-    case MediaStatus::MEDIA_TRACK_TTS:
-      return TrackType::MEDIA_TRACK_TTS;
-    case MediaStatus::MEDIA_TRACK_CONTENT:
-      return TrackType::MEDIA_TRACK_CONTENT;
-  }
-}
-
-MediaStatus::PlaybackState ConvertPlaybackStateEnumToV2FromV1(
-    const PlaybackState& state) {
-  switch (state) {
-    case PlaybackState::IDLE:
-      return MediaStatus::IDLE;
-    case PlaybackState::NEW_TRACK:
-      return MediaStatus::NEW_TRACK;
-    case PlaybackState::PLAYING:
-      return MediaStatus::PLAYING;
-    case PlaybackState::PAUSED:
-      return MediaStatus::PAUSED;
-    case PlaybackState::ERROR:
-      return MediaStatus::ERROR;
-  }
-}
-
-MediaStatus::TrackType ConvertTrackTypeEnumToV2FromV1(
-    const TrackType& track_type) {
-  switch (track_type) {
-    case TrackType::MEDIA_TRACK_NONE:
-      return MediaStatus::MEDIA_TRACK_NONE;
-    case TrackType::MEDIA_TRACK_TTS:
-      return MediaStatus::MEDIA_TRACK_TTS;
-    case TrackType::MEDIA_TRACK_CONTENT:
-      return MediaStatus::MEDIA_TRACK_CONTENT;
-  }
-}
-
-MediaStatus::PlaybackState ConvertPlaybackStateEnumToV2FromMojom(
-    const mojom::PlaybackState& state) {
-  switch (state) {
-    case mojom::PlaybackState::kIdle:
-      return MediaStatus::IDLE;
-    case mojom::PlaybackState::kNewTrack:
-      return MediaStatus::NEW_TRACK;
-    case mojom::PlaybackState::kPlaying:
-      return MediaStatus::PLAYING;
-    case mojom::PlaybackState::kPaused:
-      return MediaStatus::PAUSED;
-    case mojom::PlaybackState::kError:
-      return MediaStatus::ERROR;
-  }
-}
-
-mojom::PlaybackState ConvertPlaybackStateEnumToMojomFromV2(
-    const MediaStatus::PlaybackState& state) {
-  switch (state) {
-    // New value in V2, treat as kIdle.
-    case MediaStatus::UNSPECIFIED:
-      return mojom::PlaybackState::kIdle;
-    case MediaStatus::IDLE:
-      return mojom::PlaybackState::kIdle;
-    case MediaStatus::NEW_TRACK:
-      return mojom::PlaybackState::kNewTrack;
-    case MediaStatus::PLAYING:
-      return mojom::PlaybackState::kPlaying;
-    case MediaStatus::PAUSED:
-      return mojom::PlaybackState::kPaused;
-    case MediaStatus::ERROR:
-      return mojom::PlaybackState::kError;
-  }
-}
-
-}  // namespace
-
-void ConvertMediaStatusToV1FromV2(const MediaStatus& media_status_proto,
-                                  assistant_client::MediaStatus* media_status) {
-  media_status->playback_state =
-      ConvertPlaybackStateEnumToV1FromV2(media_status_proto.playback_state());
-
-  assistant_client::MediaMetadata media_metadata;
-  const auto& metadata_proto = media_status_proto.metadata();
-  media_metadata.album = metadata_proto.album();
-  media_metadata.album_art_url = metadata_proto.album_art_url();
-  media_metadata.artist = metadata_proto.artist();
-  media_metadata.title = metadata_proto.title();
-  media_metadata.duration_ms = metadata_proto.duration_ms();
-  media_status->metadata = std::move(media_metadata);
-
-  media_status->track_type =
-      ConvertTrackTypeEnumToV1FromV2(media_status_proto.track_type());
-  media_status->position_ms = media_status_proto.position_ms();
-}
-
-void ConvertMediaStatusToV2FromV1(
-    const assistant_client::MediaStatus& media_status,
-    MediaStatus* media_status_proto) {
-  media_status_proto->set_playback_state(
-      ConvertPlaybackStateEnumToV2FromV1(media_status.playback_state));
-
-  auto* media_metadata_proto = media_status_proto->mutable_metadata();
-  auto media_metadata = media_status.metadata;
-  media_metadata_proto->set_album(media_metadata.album);
-  media_metadata_proto->set_album_art_url(media_metadata.album_art_url);
-  media_metadata_proto->set_artist(media_metadata.artist);
-  media_metadata_proto->set_title(media_metadata.title);
-  media_metadata_proto->set_duration_ms(media_metadata.duration_ms);
-
-  media_status_proto->set_track_type(
-      ConvertTrackTypeEnumToV2FromV1(media_status.track_type));
-  media_status_proto->set_position_ms(media_status.position_ms);
-}
-
-mojom::MediaStatePtr ConvertMediaStatusToMojomFromV2(
-    const MediaStatus& media_status_proto) {
-  mojom::MediaStatePtr state_ptr = mojom::MediaState::New();
-
-  if (!media_status_proto.metadata().album().empty() ||
-      !media_status_proto.metadata().title().empty() ||
-      !media_status_proto.metadata().artist().empty()) {
-    state_ptr->metadata = mojom::MediaMetadata::New();
-    state_ptr->metadata->album = media_status_proto.metadata().album();
-    state_ptr->metadata->title = media_status_proto.metadata().title();
-    state_ptr->metadata->artist = media_status_proto.metadata().artist();
-  }
-  state_ptr->playback_state = ConvertPlaybackStateEnumToMojomFromV2(
-      media_status_proto.playback_state());
-  return state_ptr;
-}
-
-void ConvertMediaStatusToV2FromMojom(const mojom::MediaState& state,
-                                     MediaStatus* media_status_proto) {
-  media_status_proto->set_playback_state(
-      ConvertPlaybackStateEnumToV2FromMojom(state.playback_state));
-
-  if (state.metadata) {
-    auto* media_metadata_proto = media_status_proto->mutable_metadata();
-    media_metadata_proto->set_album(state.metadata->album);
-    media_metadata_proto->set_artist(state.metadata->artist);
-    media_metadata_proto->set_title(state.metadata->title);
-  }
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/utils/media_status_utils.h b/chromeos/ash/services/libassistant/grpc/utils/media_status_utils.h
deleted file mode 100644
index a5e8e31..0000000
--- a/chromeos/ash/services/libassistant/grpc/utils/media_status_utils.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_UTILS_MEDIA_STATUS_UTILS_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_UTILS_MEDIA_STATUS_UTILS_H_
-
-#include "chromeos/ash/services/libassistant/public/mojom/media_controller.mojom-forward.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/device_state_event.pb.h"
-
-namespace assistant_client {
-struct MediaStatus;
-}  // namespace assistant_client
-
-namespace ash::libassistant {
-
-using MediaStatus = ::assistant::api::events::DeviceState::MediaStatus;
-
-void ConvertMediaStatusToV1FromV2(const MediaStatus& media_status_proto,
-                                  assistant_client::MediaStatus* media_status);
-
-void ConvertMediaStatusToV2FromV1(
-    const assistant_client::MediaStatus& media_status,
-    MediaStatus* media_status_proto);
-
-mojom::MediaStatePtr ConvertMediaStatusToMojomFromV2(
-    const MediaStatus& media_status_proto);
-
-void ConvertMediaStatusToV2FromMojom(const mojom::MediaState& state,
-                                     MediaStatus* media_status_proto);
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_UTILS_MEDIA_STATUS_UTILS_H_
diff --git a/chromeos/ash/services/libassistant/grpc/utils/settings_utils.cc b/chromeos/ash/services/libassistant/grpc/utils/settings_utils.cc
deleted file mode 100644
index de65b40..0000000
--- a/chromeos/ash/services/libassistant/grpc/utils/settings_utils.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/utils/settings_utils.h"
-
-#include "base/check.h"
-#include "base/logging.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/proto/shared/proto/settings_ui.pb.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-using ::assistant::api::GetAssistantSettingsResponse;
-using ::assistant::api::ResponseDetails;
-using ::assistant::api::UpdateAssistantSettingsResponse;
-
-}  // namespace
-
-std::string UnwrapGetAssistantSettingsResponse(
-    const GetAssistantSettingsResponse& response,
-    bool include_header) {
-  const auto& response_details = response.response_details();
-  if (response_details.has_status() &&
-      response_details.status() ==
-          ::assistant::api::ResponseDetails_Status_SUCCESS) {
-    DCHECK(response.has_get_settings_ui_response() &&
-           response.get_settings_ui_response().has_settings());
-
-    // Upon success, returns a serialized proto |SettingsUi|
-    // or |GetSettingsUiResponse| based on the value of |include_header|.
-    return include_header
-               ? response.get_settings_ui_response().SerializeAsString()
-               : response.get_settings_ui_response()
-                     .settings()
-                     .SerializeAsString();
-  }
-
-  // TODO(xiaohuic): figure out how to log through libassistant.
-  LOG(ERROR) << "GetAssistantSettings request failed.";
-  if (response_details.has_status()) {
-    LOG(ERROR) << "Failed with status: "
-               << static_cast<int>(response_details.status());
-  }
-  if (response_details.has_error_message()) {
-    LOG(ERROR) << "Error message: " << response_details.error_message();
-  }
-
-  // Upon failure, returns an empty string.
-  return "";
-}
-
-std::string UnwrapUpdateAssistantSettingsResponse(
-    const UpdateAssistantSettingsResponse& response) {
-  const auto& response_details = response.response_details();
-  if (response_details.has_status() &&
-      response_details.status() ==
-          ::assistant::api::ResponseDetails_Status_SUCCESS) {
-    DCHECK(response.has_update_settings_ui_response() &&
-           response.update_settings_ui_response().has_update_result());
-
-    // Upon success, returns a serialized proto |SettingsUiUpdateResult|.
-    return response.update_settings_ui_response()
-        .update_result()
-        .SerializeAsString();
-  }
-
-  // TODO(xiaohuic): figure out how to log through libassistant.
-  LOG(ERROR) << "UpdateAssistantSettings request failed.";
-  if (response_details.has_status()) {
-    LOG(ERROR) << "Failed with status: "
-               << static_cast<int>(response_details.status());
-  }
-  if (response_details.has_error_message()) {
-    LOG(ERROR) << "ERROR message: " << response_details.error_message();
-  }
-
-  // Upon failure, returns an empty string.
-  return "";
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/utils/settings_utils.h b/chromeos/ash/services/libassistant/grpc/utils/settings_utils.h
deleted file mode 100644
index 6a7535f..0000000
--- a/chromeos/ash/services/libassistant/grpc/utils/settings_utils.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_UTILS_SETTINGS_UTILS_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_UTILS_SETTINGS_UTILS_H_
-
-#include "chromeos/assistant/internal/proto/shared/proto/v2/config_settings_interface.pb.h"
-
-namespace ash::libassistant {
-
-// Returns a serialized proto of |SettingsUi| by default (or a serialized proto
-// of |GetSettingsUiResponse| if |include_header| is true) if the response
-// status is ok, otherwise returns an empty string.
-std::string UnwrapGetAssistantSettingsResponse(
-    const ::assistant::api::GetAssistantSettingsResponse& response,
-    bool include_header = false);
-
-// Returns a serialized proto of |SettingsUiUpdateResult| if the response
-// status is ok, otherwise returns an empty string.
-std::string UnwrapUpdateAssistantSettingsResponse(
-    const ::assistant::api::UpdateAssistantSettingsResponse& response);
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_UTILS_SETTINGS_UTILS_H_
diff --git a/chromeos/ash/services/libassistant/grpc/utils/timer_utils.cc b/chromeos/ash/services/libassistant/grpc/utils/timer_utils.cc
deleted file mode 100644
index c34a485ea..0000000
--- a/chromeos/ash/services/libassistant/grpc/utils/timer_utils.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/grpc/utils/timer_utils.h"
-
-#include "base/time/time.h"
-#include "chromeos/ash/services/libassistant/public/cpp/assistant_timer.h"
-#include "chromeos/assistant/internal/proto/shared/proto/timer_params.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_interface.pb.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-using assistant::AssistantTimer;
-using assistant::AssistantTimerState;
-
-}  // namespace
-
-std::vector<AssistantTimer> ConstructAssistantTimersFromProto(
-    const ::assistant::api::params::TimerParams& timer_params) {
-  std::vector<AssistantTimer> assistant_timers;
-  for (const auto& proto_timer : timer_params.timer()) {
-    AssistantTimer assistant_timer;
-    ConvertProtoTimerToAssistantTimer(proto_timer, &assistant_timer);
-    assistant_timers.emplace_back(std::move(assistant_timer));
-  }
-
-  return assistant_timers;
-}
-
-void ConvertProtoTimerToAssistantTimer(
-    const ::assistant::api::params::Timer& input,
-    AssistantTimer* output) {
-  output->id = input.timer_id();
-  output->state = static_cast<AssistantTimerState>(input.status());
-  output->original_duration = base::Milliseconds(input.original_duration());
-
-  if (input.has_remaining_duration()) {
-    // Remaining time in ms when paused or used in timer.CREATE_TIMER.
-    output->remaining_time = base::Milliseconds(input.remaining_duration());
-  } else {
-    // Time the timer is scheduled to expire in ms since the unix epoch
-    // when not paused or used in timer.UPDATE_TIMER.
-    output->fire_time =
-        base::Time::UnixEpoch() + base::Milliseconds(input.expire_time());
-
-    // This is a workaround for not breaking the current timer functionality.
-    // We have to make sure that |remaining_time| is always set since it is
-    // used to update the timer. In V2 proto, |remaining_time| and |fire_time|
-    // are mutally exclusive.
-    output->remaining_time = output->fire_time - base::Time::Now();
-  }
-
-  output->label = input.label();
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/grpc/utils/timer_utils.h b/chromeos/ash/services/libassistant/grpc/utils/timer_utils.h
deleted file mode 100644
index 6e34b9f..0000000
--- a/chromeos/ash/services/libassistant/grpc/utils/timer_utils.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_UTILS_TIMER_UTILS_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_UTILS_TIMER_UTILS_H_
-
-#include "chromeos/ash/services/libassistant/public/cpp/assistant_timer.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-
-namespace assistant {
-namespace api {
-
-namespace params {
-class Timer;
-class TimerParams;
-}  // namespace params
-
-}  // namespace api
-}  // namespace assistant
-
-namespace ash::libassistant {
-
-// `timer_params` contains the information of all the current timers.
-std::vector<assistant::AssistantTimer> ConstructAssistantTimersFromProto(
-    const ::assistant::api::params::TimerParams& timer_params);
-
-void ConvertProtoTimerToAssistantTimer(
-    const ::assistant::api::params::Timer& input,
-    assistant::AssistantTimer* output);
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_GRPC_UTILS_TIMER_UTILS_H_
diff --git a/chromeos/ash/services/libassistant/libassistant_factory.h b/chromeos/ash/services/libassistant/libassistant_factory.h
deleted file mode 100644
index 56a75f4..0000000
--- a/chromeos/ash/services/libassistant/libassistant_factory.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_LIBASSISTANT_FACTORY_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_LIBASSISTANT_FACTORY_H_
-
-#include <memory>
-#include <optional>
-#include <string>
-
-namespace assistant_client {
-class AssistantManager;
-}  // namespace assistant_client
-
-namespace ash::libassistant {
-
-// Factory class that creates the main actual Libassistant classes.
-// Can be replaced with a fake for unittests.
-class LibassistantFactory {
- public:
-  virtual ~LibassistantFactory() = default;
-
-  virtual std::unique_ptr<assistant_client::AssistantManager>
-  CreateAssistantManager(const std::string& lib_assistant_config) = 0;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_LIBASSISTANT_FACTORY_H_
diff --git a/chromeos/ash/services/libassistant/libassistant_loader_impl.cc b/chromeos/ash/services/libassistant/libassistant_loader_impl.cc
deleted file mode 100644
index fb4d448..0000000
--- a/chromeos/ash/services/libassistant/libassistant_loader_impl.cc
+++ /dev/null
@@ -1,232 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/libassistant_loader_impl.h"
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/functional/bind.h"
-#include "base/functional/callback_helpers.h"
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/no_destructor.h"
-#include "base/system/sys_info.h"
-#include "base/task/task_traits.h"
-#include "base/task/thread_pool.h"
-#include "base/time/time.h"
-#include "chromeos/ash/components/dbus/dlcservice/dlcservice_client.h"
-#include "chromeos/ash/services/assistant/public/cpp/assistant_enums.h"
-#include "chromeos/ash/services/assistant/public/cpp/features.h"
-#include "chromeos/ash/services/libassistant/constants.h"
-#include "third_party/cros_system_api/dbus/dlcservice/dbus-constants.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-using InstallResult = assistant::LibassistantDlcInstallResult;
-using LoadStatus = assistant::LibassistantDlcLoadStatus;
-
-base::TaskTraits GetTaskTraits() {
-  return {base::MayBlock(), base::TaskPriority::USER_BLOCKING,
-          base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN};
-}
-
-inline constexpr char kDlcInstallResultHistogram[] =
-    "Assistant.Libassistant.DlcInstallResult";
-
-inline constexpr char kDlcLoadStatusHistogram[] =
-    "Assistant.Libassistant.DlcLoadStatus";
-
-// The DLC ID of Libassistant.so, used to download and mount the library.
-inline constexpr char kLibassistantDlcId[] = "assistant-dlc";
-
-base::FilePath GetLibassisantPath(const std::string& root_path) {
-  DCHECK(root_path == kLibAssistantDlcRootPath);
-  base::FilePath libassistant_dlc_root =
-      base::FilePath(root_path).AsEndingWithSeparator();
-  return libassistant_dlc_root.Append(base::FilePath(kLibAssistantV2DlcPath));
-}
-
-void RecordLibassistantDlcInstallResult(
-    const DlcserviceClient::InstallResult& result) {
-  InstallResult install_result = InstallResult::kErrorInternal;
-  if (result.error == dlcservice::kErrorNone) {
-    install_result = InstallResult::kSuccess;
-  }
-  if (result.error == dlcservice::kErrorInternal) {
-    install_result = InstallResult::kErrorInternal;
-  }
-  if (result.error == dlcservice::kErrorBusy) {
-    install_result = InstallResult::kErrorBusy;
-  }
-  if (result.error == dlcservice::kErrorNeedReboot) {
-    install_result = InstallResult::kErrorNeedReboot;
-  }
-  if (result.error == dlcservice::kErrorInvalidDlc) {
-    install_result = InstallResult::kErrorInvalidDlc;
-  }
-  if (result.error == dlcservice::kErrorAllocation) {
-    install_result = InstallResult::kErrorAllocation;
-  }
-  if (result.error == dlcservice::kErrorNoImageFound) {
-    install_result = InstallResult::kErrorNoImageFound;
-  }
-  base::UmaHistogramEnumeration(kDlcInstallResultHistogram, install_result);
-}
-
-void RecordLibassistantDlcLoadStatus(const LoadStatus& status) {
-  base::UmaHistogramEnumeration(kDlcLoadStatusHistogram, status);
-}
-
-}  // namespace
-
-void LibassistantLoaderImpl::Load(LoadCallback callback) {
-  if (entry_point_) {
-    std::move(callback).Run(/*success=*/true);
-    return;
-  }
-
-  InstallDlc(std::move(callback));
-}
-
-void LibassistantLoaderImpl::LoadBlocking(const std::string& root_path) {
-  // We will load the libassistant before the sandbox initializes.
-  // Since we are not in the main thread, we can call the blocking method.
-  DCHECK(!entry_point_);
-
-  // If the gRPC socket files exist, libassistant gRPC server could not start
-  // because the binding to the new socket files will fail, with error message
-  // that the files already exist.
-  const bool is_chromeos_device = base::SysInfo::IsRunningOnChromeOS();
-  DVLOG(3) << "Clean up temporary libassistant directory.";
-  auto socket_path = base::FilePath(kLibAssistantSocketPath);
-  base::DeletePathRecursively(socket_path);
-  if (!is_chromeos_device) {
-    // Make sure the directory exists. On a real device, this directory will be
-    // created on the OS side when Chrome starts.
-    CHECK(base::CreateDirectory(socket_path));
-  }
-
-  base::FilePath path = GetLibassisantPath(root_path);
-  base::ScopedNativeLibrary library = base::ScopedNativeLibrary(path);
-  OnLibraryLoaded(std::move(library));
-}
-
-EntryPoint* LibassistantLoaderImpl::GetEntryPoint() {
-  DCHECK(entry_point_);
-  return entry_point_.get();
-}
-
-LibassistantLoaderImpl::LibassistantLoaderImpl()
-    : task_runner_(
-          base::ThreadPool::CreateSequencedTaskRunner(GetTaskTraits())) {}
-
-LibassistantLoaderImpl::~LibassistantLoaderImpl() = default;
-
-void LibassistantLoaderImpl::InstallDlc(LoadCallback callback) {
-  callback_ = std::move(callback);
-
-  // Install libassistant.so from DLC.
-  auto* client = DlcserviceClient::Get();
-  if (!client) {
-    DVLOG(1) << "DlcService client is not available";
-    RunCallback(/*success=*/false);
-    return;
-  }
-
-  DVLOG(3) << "Installing libassistant.so from DLC";
-  dlcservice::InstallRequest install_request;
-  install_request.set_id(kLibassistantDlcId);
-  client->Install(install_request,
-                  base::BindOnce(&LibassistantLoaderImpl::OnInstallDlcComplete,
-                                 weak_factory_.GetWeakPtr()),
-                  /*ProgressCallback=*/base::DoNothing());
-}
-
-void LibassistantLoaderImpl::OnInstallDlcComplete(
-    const DlcserviceClient::InstallResult& result) {
-  RecordLibassistantDlcInstallResult(result);
-
-  if (result.error != dlcservice::kErrorNone) {
-    DVLOG(1) << "Failed to install libassistant.so from DLC: " << result.error;
-    RunCallback(/*success=*/false);
-    return;
-  }
-
-  if (assistant::features::IsLibAssistantSandboxEnabled()) {
-    // Will load the library later in the utility process.
-    RunCallback(/*success=*/true);
-    return;
-  }
-
-  // `ScopedNativeLibrary` will call `LoadNativeLibraryWithOptions()`, which is
-  // a blocking call. We need to send to a background thread to load it.
-  base::FilePath path = GetLibassisantPath(result.root_path);
-  DVLOG(3) << "Loading libassistant.so DLC from: " << path;
-  task_runner_->PostTaskAndReplyWithResult(
-      FROM_HERE,
-      base::BindOnce(
-          [](const base::FilePath& path) {
-            const bool is_chromeos_device =
-                base::SysInfo::IsRunningOnChromeOS();
-            if (!is_chromeos_device) {
-              // Make sure the directory exists. On a real device, this
-              // directory will be created on the OS side when Chrome starts.
-              auto socket_path = base::FilePath(kLibAssistantSocketPath);
-              CHECK(base::CreateDirectory(socket_path));
-            }
-            return base::ScopedNativeLibrary(path);
-          },
-          path),
-      base::BindOnce(&LibassistantLoaderImpl::OnLibraryLoaded,
-                     weak_factory_.GetWeakPtr()));
-}
-
-void LibassistantLoaderImpl::OnLibraryLoaded(
-    base::ScopedNativeLibrary library) {
-  if (!library.is_valid()) {
-    DVLOG(1) << "Failed to load libassistant.so DLC,  error: "
-             << library.GetError()->ToString();
-    RecordLibassistantDlcLoadStatus(LoadStatus::kNotLoaded);
-    RunCallback(/*success=*/false);
-    return;
-  }
-
-  // Call exported function in libassistant.so.
-  NewLibassistantEntrypointFn entrypoint =
-      reinterpret_cast<NewLibassistantEntrypointFn>(
-          library.GetFunctionPointer(kNewLibassistantEntrypointFnName));
-  C_API_LibassistantEntrypoint* c_entrypoint = entrypoint(0);
-  auto* entry_point =
-      assistant_client::internal_api::LibassistantEntrypointFromC(c_entrypoint);
-
-  DVLOG(3) << "Loaded libassistant.so.";
-  RecordLibassistantDlcLoadStatus(LoadStatus::kLoaded);
-
-  dlc_library_ = std::move(library);
-  entry_point_ = base::WrapUnique(entry_point);
-  RunCallback(/*success=*/true);
-}
-
-void LibassistantLoaderImpl::RunCallback(bool success) {
-  if (callback_) {
-    std::move(callback_).Run(success);
-  }
-}
-
-// static
-LibassistantLoaderImpl* LibassistantLoaderImpl::GetInstance() {
-  // TODO(b/242098785): Investigate if we could remove NoDestructor.
-  static base::NoDestructor<LibassistantLoaderImpl> instance;
-  return instance.get();
-}
-
-// static
-void LibassistantLoader::Load(LoadCallback callback) {
-  LibassistantLoaderImpl::GetInstance()->Load(std::move(callback));
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/libassistant_loader_impl.h b/chromeos/ash/services/libassistant/libassistant_loader_impl.h
deleted file mode 100644
index e123489..0000000
--- a/chromeos/ash/services/libassistant/libassistant_loader_impl.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_LIBASSISTANT_LOADER_IMPL_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_LIBASSISTANT_LOADER_IMPL_H_
-
-#include <optional>
-
-#include "base/component_export.h"
-#include "base/gtest_prod_util.h"
-#include "base/no_destructor.h"
-#include "base/scoped_native_library.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/timer/timer.h"
-#include "chromeos/ash/components/dbus/dlcservice/dlcservice_client.h"
-#include "chromeos/ash/services/libassistant/public/cpp/libassistant_loader.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "net/base/backoff_entry.h"
-
-namespace ash::libassistant {
-
-using EntryPoint = assistant_client::internal_api::LibassistantEntrypoint;
-
-inline constexpr char kNewLibassistantEntrypointFnName[] =
-    "NewLibassistantEntrypoint";
-
-typedef C_API_LibassistantEntrypoint* (*NewLibassistantEntrypointFn)(
-    int version);
-
-// Implementation of `LibassistantLoader` to load libassistant.so for different
-// situations.
-class COMPONENT_EXPORT(LIBASSISTANT_LOADER) LibassistantLoaderImpl
-    : public LibassistantLoader {
- public:
-  static LibassistantLoaderImpl* GetInstance();
-
-  LibassistantLoaderImpl(const LibassistantLoaderImpl&) = delete;
-  LibassistantLoaderImpl& operator=(const LibassistantLoaderImpl&) = delete;
-
-  // Load libassistant.so. Will skip if the library has been loaded.
-  void Load(LoadCallback callback);
-
-  // Load libassistant.so for sandbox. This is a blocking method.
-  void LoadBlocking(const std::string& root_path);
-
-  // Return the LibassistantEntrypoint.
-  EntryPoint* GetEntryPoint();
-
- private:
-  friend class base::NoDestructor<LibassistantLoaderImpl>;
-
-  LibassistantLoaderImpl();
-  ~LibassistantLoaderImpl() override;
-
-  // Call DlcServiceClient to install libassistant DLC.
-  void InstallDlc(LoadCallback callback);
-  void OnInstallDlcComplete(const DlcserviceClient::InstallResult& result);
-
-  // Called when the libassistant DLC is loaded.
-  void OnLibraryLoaded(base::ScopedNativeLibrary library);
-
-  void RunCallback(bool success);
-
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
-
-  LoadCallback callback_;
-
-  std::optional<base::ScopedNativeLibrary> dlc_library_;
-  std::unique_ptr<EntryPoint> entry_point_;
-
-  base::WeakPtrFactory<LibassistantLoaderImpl> weak_factory_{this};
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_LIBASSISTANT_LOADER_IMPL_H_
diff --git a/chromeos/ash/services/libassistant/libassistant_loader_impl_unittest.cc b/chromeos/ash/services/libassistant/libassistant_loader_impl_unittest.cc
deleted file mode 100644
index 083e684..0000000
--- a/chromeos/ash/services/libassistant/libassistant_loader_impl_unittest.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/libassistant_loader_impl.h"
-
-#include "base/functional/bind.h"
-#include "base/functional/callback_helpers.h"
-#include "base/run_loop.h"
-#include "base/test/task_environment.h"
-#include "chromeos/ash/components/dbus/dlcservice/dlcservice_client.h"
-#include "chromeos/ash/services/assistant/public/cpp/features.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::libassistant {
-
-class LibassistantLoaderImplTest : public ::testing::Test {
- public:
-  LibassistantLoaderImplTest() = default;
-  LibassistantLoaderImplTest(const LibassistantLoaderImplTest&) = delete;
-  LibassistantLoaderImplTest& operator=(const LibassistantLoaderImplTest&) =
-      delete;
-  ~LibassistantLoaderImplTest() override = default;
-
- private:
-  base::test::TaskEnvironment environment_;
-};
-
-TEST_F(LibassistantLoaderImplTest, ShouldCreateInstance) {
-  auto* loader = LibassistantLoaderImpl::GetInstance();
-  EXPECT_TRUE(loader);
-}
-
-TEST_F(LibassistantLoaderImplTest, ShouldRunCallbackWithDlcFeature) {
-  auto* loader = LibassistantLoaderImpl::GetInstance();
-  EXPECT_TRUE(loader);
-
-  // Should fail without dlcservice client.
-  base::RunLoop run_loop1;
-  loader->Load(base::BindOnce(
-      [](base::RunLoop* run_loop, bool success) {
-        EXPECT_FALSE(success);
-        run_loop->Quit();
-      },
-      &run_loop1));
-  run_loop1.Run();
-
-  // Should success with dlcservice client.
-  base::RunLoop run_loop2;
-  DlcserviceClient::InitializeFake();
-  loader->Load(base::BindOnce(
-      [](base::RunLoop* run_loop, bool success) {
-        EXPECT_TRUE(success);
-        run_loop->Quit();
-      },
-      &run_loop2));
-  run_loop2.Run();
-  DlcserviceClient::Shutdown();
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/libassistant_sandbox_hook.cc b/chromeos/ash/services/libassistant/libassistant_sandbox_hook.cc
deleted file mode 100644
index b2dd065..0000000
--- a/chromeos/ash/services/libassistant/libassistant_sandbox_hook.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/libassistant_sandbox_hook.h"
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/system/sys_info.h"
-#include "chromeos/ash/services/libassistant/constants.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_util.h"
-#include "chromeos/ash/services/libassistant/libassistant_loader_impl.h"
-#include "sandbox/linux/syscall_broker/broker_command.h"
-#include "sandbox/linux/syscall_broker/broker_file_permission.h"
-#include "sandbox/policy/linux/sandbox_linux.h"
-
-using sandbox::syscall_broker::BrokerFilePermission;
-using sandbox::syscall_broker::MakeBrokerCommandSet;
-
-namespace ash::libassistant {
-
-namespace {
-
-sandbox::syscall_broker::BrokerCommandSet GetLibassistantBrokerCommandSet() {
-  return MakeBrokerCommandSet({
-      sandbox::syscall_broker::COMMAND_ACCESS,
-      sandbox::syscall_broker::COMMAND_MKDIR,
-      sandbox::syscall_broker::COMMAND_OPEN,
-      sandbox::syscall_broker::COMMAND_RENAME,
-      sandbox::syscall_broker::COMMAND_STAT,
-      sandbox::syscall_broker::COMMAND_STAT64,
-  });
-}
-
-std::vector<BrokerFilePermission> GetLibassistantFilePermissions() {
-  base::FilePath assistant_path =
-      base::FilePath(kAssistantBaseDirPath).AsEndingWithSeparator();
-  CHECK(base::CreateDirectory(assistant_path));
-  // Save Libassistant logs.
-  base::FilePath log_path =
-      assistant_path.Append(FILE_PATH_LITERAL("log")).AsEndingWithSeparator();
-  CHECK(base::CreateDirectory(log_path));
-
-  // Socket files used for gRPC.
-  const bool is_chromeos_device = base::SysInfo::IsRunningOnChromeOS();
-  base::FilePath assistant_socket =
-      base::FilePath(GetAssistantSocketFileName(is_chromeos_device));
-  base::FilePath libassistant_socket =
-      base::FilePath(GetLibassistantSocketFileName(is_chromeos_device));
-  base::FilePath http_connection_socket =
-      base::FilePath(GetHttpConnectionSocketFileName(is_chromeos_device));
-
-  std::vector<BrokerFilePermission> permissions{
-      // Required by Libassistant to generate random string.
-      BrokerFilePermission::ReadOnly("/dev/urandom"),
-      BrokerFilePermission::ReadWriteCreateRecursive(assistant_path.value()),
-      BrokerFilePermission::ReadWriteCreate(assistant_socket.value()),
-      BrokerFilePermission::ReadWriteCreate(libassistant_socket.value()),
-      BrokerFilePermission::ReadWriteCreate(http_connection_socket.value()),
-  };
-  return permissions;
-}
-
-}  // namespace
-
-bool LibassistantPreSandboxHook(
-    sandbox::policy::SandboxLinux::Options options) {
-  // Load libassistant DLC before the sandbox initializes.
-  LibassistantLoaderImpl::GetInstance()->LoadBlocking(kLibAssistantDlcRootPath);
-
-  auto* instance = sandbox::policy::SandboxLinux::GetInstance();
-  instance->StartBrokerProcess(GetLibassistantBrokerCommandSet(),
-                               GetLibassistantFilePermissions(), options);
-
-  return true;
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/libassistant_sandbox_hook.h b/chromeos/ash/services/libassistant/libassistant_sandbox_hook.h
deleted file mode 100644
index 783395d..0000000
--- a/chromeos/ash/services/libassistant/libassistant_sandbox_hook.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_LIBASSISTANT_SANDBOX_HOOK_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_LIBASSISTANT_SANDBOX_HOOK_H_
-
-#include "sandbox/policy/linux/sandbox_linux.h"
-
-namespace ash::libassistant {
-
-bool LibassistantPreSandboxHook(sandbox::policy::SandboxLinux::Options options);
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_LIBASSISTANT_SANDBOX_HOOK_H_
diff --git a/chromeos/ash/services/libassistant/libassistant_service.cc b/chromeos/ash/services/libassistant/libassistant_service.cc
deleted file mode 100644
index 69cc916c..0000000
--- a/chromeos/ash/services/libassistant/libassistant_service.cc
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/libassistant_service.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/check.h"
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/raw_ptr.h"
-#include "chromeos/ash/services/libassistant/libassistant_factory.h"
-#include "chromeos/ash/services/libassistant/libassistant_loader_impl.h"
-#include "chromeos/ash/services/libassistant/public/mojom/speech_recognition_observer.mojom.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-class LibassistantFactoryImpl : public LibassistantFactory {
- public:
-  explicit LibassistantFactoryImpl(assistant_client::PlatformApi* platform_api)
-      : platform_api_(platform_api) {}
-  LibassistantFactoryImpl(const LibassistantFactoryImpl&) = delete;
-  LibassistantFactoryImpl& operator=(const LibassistantFactoryImpl&) = delete;
-  ~LibassistantFactoryImpl() override = default;
-
-  // LibassistantFactory implementation:
-  std::unique_ptr<assistant_client::AssistantManager> CreateAssistantManager(
-      const std::string& lib_assistant_config) override {
-    auto* entrypoint = LibassistantLoaderImpl::GetInstance()->GetEntryPoint();
-    assistant_client::AssistantManager* assistant_manager =
-        entrypoint->NewAssistantManager(lib_assistant_config, platform_api_);
-    return base::WrapUnique(assistant_manager);
-  }
-
- private:
-  const raw_ptr<assistant_client::PlatformApi> platform_api_;
-};
-
-std::unique_ptr<LibassistantFactory> FactoryOrDefault(
-    std::unique_ptr<LibassistantFactory> factory,
-    assistant_client::PlatformApi* platform_api) {
-  if (factory)
-    return factory;
-
-  return std::make_unique<LibassistantFactoryImpl>(platform_api);
-}
-
-}  // namespace
-
-LibassistantService::LibassistantService(
-    mojo::PendingReceiver<mojom::LibassistantService> receiver,
-    std::unique_ptr<LibassistantFactory> factory)
-    : receiver_(this, std::move(receiver)),
-      libassistant_factory_(
-          FactoryOrDefault(std::move(factory), &platform_api_)),
-      service_controller_(libassistant_factory_.get()),
-      conversation_state_listener_(
-          &speech_recognition_observers_,
-          conversation_controller_.conversation_observers(),
-          &audio_input_controller_),
-      display_controller_(&speech_recognition_observers_),
-      speaker_id_enrollment_controller_(&audio_input_controller_) {
-  service_controller_.AddAndFireAssistantClientObserver(
-      &conversation_controller_);
-  service_controller_.AddAndFireAssistantClientObserver(
-      &conversation_state_listener_);
-  service_controller_.AddAndFireAssistantClientObserver(
-      &device_settings_controller_);
-  service_controller_.AddAndFireAssistantClientObserver(&display_controller_);
-  service_controller_.AddAndFireAssistantClientObserver(&media_controller_);
-  service_controller_.AddAndFireAssistantClientObserver(
-      &speaker_id_enrollment_controller_);
-  service_controller_.AddAndFireAssistantClientObserver(&settings_controller_);
-  service_controller_.AddAndFireAssistantClientObserver(&timer_controller_);
-
-  conversation_controller_.AddActionObserver(&device_settings_controller_);
-  conversation_controller_.AddActionObserver(&display_controller_);
-  display_controller_.SetActionModule(conversation_controller_.action_module());
-  platform_api_.SetAudioInputProvider(
-      &audio_input_controller_.audio_input_provider());
-}
-
-LibassistantService::~LibassistantService() {
-  // We explicitly stop the Libassistant service before destroying anything,
-  // to prevent use-after-free bugs.
-  service_controller_.Stop();
-  service_controller_.RemoveAllAssistantClientObservers();
-}
-
-void LibassistantService::Bind(
-    mojo::PendingReceiver<mojom::AudioInputController> audio_input_controller,
-    mojo::PendingReceiver<mojom::ConversationController>
-        conversation_controller,
-    mojo::PendingReceiver<mojom::DisplayController> display_controller,
-    mojo::PendingReceiver<mojom::MediaController> media_controller,
-    mojo::PendingReceiver<mojom::ServiceController> service_controller,
-    mojo::PendingReceiver<mojom::SettingsController> settings_controller,
-    mojo::PendingReceiver<mojom::SpeakerIdEnrollmentController>
-        speaker_id_enrollment_controller,
-    mojo::PendingReceiver<mojom::TimerController> timer_controller,
-    mojo::PendingRemote<mojom::AudioOutputDelegate> audio_output_delegate,
-    mojo::PendingRemote<mojom::DeviceSettingsDelegate> device_settings_delegate,
-    mojo::PendingRemote<mojom::MediaDelegate> media_delegate,
-    mojo::PendingRemote<mojom::NotificationDelegate> notification_delegate,
-    mojo::PendingRemote<mojom::PlatformDelegate> platform_delegate,
-    mojo::PendingRemote<mojom::TimerDelegate> timer_delegate) {
-  platform_delegate_.Bind(std::move(platform_delegate));
-  audio_input_controller_.Bind(std::move(audio_input_controller),
-                               platform_delegate_.get());
-  conversation_controller_.Bind(std::move(conversation_controller),
-                                std::move(notification_delegate));
-  device_settings_controller_.Bind(std::move(device_settings_delegate));
-  display_controller_.Bind(std::move(display_controller));
-  media_controller_.Bind(std::move(media_controller),
-                         std::move(media_delegate));
-  platform_api_.Bind(std::move(audio_output_delegate),
-                     platform_delegate_.get());
-  settings_controller_.Bind(std::move(settings_controller));
-  service_controller_.Bind(std::move(service_controller),
-                           &settings_controller_);
-  speaker_id_enrollment_controller_.Bind(
-      std::move(speaker_id_enrollment_controller));
-  timer_controller_.Bind(std::move(timer_controller),
-                         std::move(timer_delegate));
-}
-
-void LibassistantService::AddSpeechRecognitionObserver(
-    mojo::PendingRemote<mojom::SpeechRecognitionObserver> observer) {
-  speech_recognition_observers_.Add(std::move(observer));
-}
-
-void LibassistantService::AddAuthenticationStateObserver(
-    mojo::PendingRemote<mojom::AuthenticationStateObserver> observer) {
-  conversation_controller_.AddAuthenticationStateObserver(std::move(observer));
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/libassistant_service.h b/chromeos/ash/services/libassistant/libassistant_service.h
deleted file mode 100644
index b672f3a..0000000
--- a/chromeos/ash/services/libassistant/libassistant_service.h
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_LIBASSISTANT_SERVICE_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_LIBASSISTANT_SERVICE_H_
-
-#include <memory>
-
-#include "base/component_export.h"
-#include "chromeos/ash/services/libassistant/audio_input_controller.h"
-#include "chromeos/ash/services/libassistant/conversation_controller.h"
-#include "chromeos/ash/services/libassistant/conversation_state_listener_impl.h"
-#include "chromeos/ash/services/libassistant/device_settings_controller.h"
-#include "chromeos/ash/services/libassistant/display_controller.h"
-#include "chromeos/ash/services/libassistant/libassistant_factory.h"
-#include "chromeos/ash/services/libassistant/media_controller.h"
-#include "chromeos/ash/services/libassistant/platform_api.h"
-#include "chromeos/ash/services/libassistant/public/mojom/notification_delegate.mojom-forward.h"
-#include "chromeos/ash/services/libassistant/public/mojom/service.mojom.h"
-#include "chromeos/ash/services/libassistant/service_controller.h"
-#include "chromeos/ash/services/libassistant/settings_controller.h"
-#include "chromeos/ash/services/libassistant/speaker_id_enrollment_controller.h"
-#include "chromeos/ash/services/libassistant/timer_controller.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote_set.h"
-
-namespace ash::libassistant {
-
-class COMPONENT_EXPORT(LIBASSISTANT_SERVICE) LibassistantService
-    : public mojom::LibassistantService {
- public:
-  explicit LibassistantService(
-      mojo::PendingReceiver<mojom::LibassistantService> receiver,
-      // Allows to inject a custom instance during unittests.
-      std::unique_ptr<LibassistantFactory> factory = nullptr);
-  LibassistantService(LibassistantService&) = delete;
-  LibassistantService& operator=(LibassistantService&) = delete;
-  ~LibassistantService() override;
-
-  // mojom::LibassistantService implementation:
-  void Bind(
-      mojo::PendingReceiver<mojom::AudioInputController> audio_input_controller,
-      mojo::PendingReceiver<mojom::ConversationController>
-          conversation_controller,
-      mojo::PendingReceiver<mojom::DisplayController> display_controller,
-      mojo::PendingReceiver<mojom::MediaController> media_controller,
-      mojo::PendingReceiver<mojom::ServiceController> service_controller,
-      mojo::PendingReceiver<mojom::SettingsController> settings_controller,
-      mojo::PendingReceiver<mojom::SpeakerIdEnrollmentController>
-          speaker_id_enrollment_controller,
-      mojo::PendingReceiver<mojom::TimerController> timer_controller,
-      mojo::PendingRemote<mojom::AudioOutputDelegate> audio_output_delegate,
-      mojo::PendingRemote<mojom::DeviceSettingsDelegate>
-          device_settings_delegate,
-      mojo::PendingRemote<mojom::MediaDelegate> media_delegate,
-      mojo::PendingRemote<mojom::NotificationDelegate> notification_delegate,
-      mojo::PendingRemote<mojom::PlatformDelegate> platform_delegate,
-      mojo::PendingRemote<mojom::TimerDelegate> timer_delegate) override;
-  void AddSpeechRecognitionObserver(
-      mojo::PendingRemote<mojom::SpeechRecognitionObserver> observer) override;
-  void AddAuthenticationStateObserver(
-      mojo::PendingRemote<mojom::AuthenticationStateObserver> observer)
-      override;
-
-  ConversationController& conversation_controller() {
-    return conversation_controller_;
-  }
-
-  ServiceController& service_controller() { return service_controller_; }
-
-  DisplayController& GetDisplayControllerForTesting() {
-    return display_controller_;
-  }
-
-  SpeakerIdEnrollmentController&
-  speaker_id_enrollment_controller_for_testing() {
-    return speaker_id_enrollment_controller_;
-  }
-
- private:
-  mojo::Receiver<mojom::LibassistantService> receiver_;
-  mojo::Remote<mojom::PlatformDelegate> platform_delegate_;
-
-  mojo::RemoteSet<mojom::SpeechRecognitionObserver>
-      speech_recognition_observers_;
-
-  // These controllers are part of the platform api which is called from
-  // Libassistant, and thus they must outlive |service_controller_|.
-  PlatformApi platform_api_;
-  AudioInputController audio_input_controller_;
-
-  std::unique_ptr<LibassistantFactory> libassistant_factory_;
-  ServiceController service_controller_;
-
-  // These controllers call Libassistant, and thus they must *not* outlive
-  // |service_controller_|.
-  ConversationController conversation_controller_;
-  ConversationStateListenerImpl conversation_state_listener_;
-  DeviceSettingsController device_settings_controller_;
-  DisplayController display_controller_;
-  MediaController media_controller_;
-  SettingsController settings_controller_;
-  SpeakerIdEnrollmentController speaker_id_enrollment_controller_;
-  TimerController timer_controller_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_LIBASSISTANT_SERVICE_H_
diff --git a/chromeos/ash/services/libassistant/media_controller.cc b/chromeos/ash/services/libassistant/media_controller.cc
deleted file mode 100644
index 4d93e34..0000000
--- a/chromeos/ash/services/libassistant/media_controller.cc
+++ /dev/null
@@ -1,267 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/media_controller.h"
-
-#include "base/memory/raw_ptr.h"
-#include "base/strings/string_util.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/grpc_services_observer.h"
-#include "chromeos/ash/services/libassistant/grpc/utils/media_status_utils.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/device_state_event.pb.h"
-#include "chromeos/assistant/internal/util_headers.h"
-#include "chromeos/services/assistant/public/shared/utils.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-constexpr char kNextTrackClientOp[] = "media.NEXT";
-constexpr char kPauseTrackClientOp[] = "media.PAUSE";
-constexpr char kPlayMediaClientOp[] = "media.PLAY_MEDIA";
-constexpr char kPrevTrackClientOp[] = "media.PREVIOUS";
-constexpr char kResumeTrackClientOp[] = "media.RESUME";
-constexpr char kStopTrackClientOp[] = "media.STOP";
-
-constexpr char kIntentActionView[] = "android.intent.action.VIEW";
-
-constexpr char kWebUrlPrefix[] = "http";
-
-using assistant::AndroidAppInfo;
-using chromeos::assistant::shared::PlayMediaArgs;
-
-// A macro which ensures we are running on the mojom thread.
-#define ENSURE_MOJOM_THREAD(method, ...)                                    \
-  if (!mojom_task_runner_->RunsTasksInCurrentSequence()) {                  \
-    mojom_task_runner_->PostTask(                                           \
-        FROM_HERE,                                                          \
-        base::BindOnce(method, weak_factory_.GetWeakPtr(), ##__VA_ARGS__)); \
-    return;                                                                 \
-  }
-
-std::string GetAndroidIntentUrlFromMediaArgs(
-    const std::string& play_media_args_proto) {
-  PlayMediaArgs play_media_args;
-  if (play_media_args.ParseFromString(play_media_args_proto)) {
-    for (auto media_item : play_media_args.media_item()) {
-      if (!media_item.has_uri())
-        continue;
-
-      return media_item.uri();
-    }
-  }
-  return std::string();
-}
-
-std::optional<AndroidAppInfo> GetAppInfoFromMediaArgs(
-    const std::string& play_media_args_proto) {
-  PlayMediaArgs play_media_args;
-  if (play_media_args.ParseFromString(play_media_args_proto)) {
-    for (auto& media_item : play_media_args.media_item()) {
-      if (media_item.has_provider() &&
-          media_item.provider().has_android_app_info()) {
-        auto& app_info = media_item.provider().android_app_info();
-        AndroidAppInfo result;
-        result.package_name = app_info.package_name();
-        result.version = app_info.app_version();
-        result.localized_app_name = app_info.localized_app_name();
-        result.intent = app_info.android_intent();
-        return result;
-      }
-    }
-  }
-  return std::nullopt;
-}
-
-std::string GetWebUrlFromMediaArgs(const std::string& play_media_args_proto) {
-  PlayMediaArgs play_media_args;
-  if (play_media_args.ParseFromString(play_media_args_proto)) {
-    for (auto media_item : play_media_args.media_item()) {
-      if (!media_item.has_uri())
-        continue;
-
-      // For web url in browser.
-      if (base::StartsWith(media_item.uri(), kWebUrlPrefix))
-        return media_item.uri();
-    }
-  }
-
-  return std::string();
-}
-
-}  // namespace
-
-class MediaController::GrpcEventsObserver
-    : public GrpcServicesObserver<::assistant::api::OnDeviceStateEventRequest>,
-      public GrpcServicesObserver<
-          ::assistant::api::OnMediaActionFallbackEventRequest> {
- public:
-  explicit GrpcEventsObserver(MediaController* parent) : parent_(parent) {}
-  GrpcEventsObserver(const GrpcEventsObserver&) = delete;
-  GrpcEventsObserver& operator=(const GrpcEventsObserver&) = delete;
-  ~GrpcEventsObserver() override = default;
-
-  // GrpcServicesObserver:
-  // Invoked when a device state event has been received.
-  void OnGrpcMessage(
-      const ::assistant::api::OnDeviceStateEventRequest& request) override {
-    VLOG(1) << "Sending playback state update";
-
-    if (!request.event().has_on_state_changed())
-      return;
-
-    const auto& new_state = request.event().on_state_changed().new_state();
-    if (!new_state.has_media_status())
-      return;
-
-    delegate().OnPlaybackStateChanged(
-        ConvertMediaStatusToMojomFromV2(new_state.media_status()));
-  }
-
-  // Invoked when a media action fallack event has been received.
-  void OnGrpcMessage(const ::assistant::api::OnMediaActionFallbackEventRequest&
-                         request) override {
-    if (!request.event().has_on_media_action_event())
-      return;
-
-    auto media_action_event = request.event().on_media_action_event();
-    HandleMediaAction(media_action_event.action_name(),
-                      media_action_event.action_args());
-  }
-
- private:
-  void HandleMediaAction(const std::string& action_name,
-                         const std::string& media_action_args_proto) {
-    if (action_name == kPlayMediaClientOp)
-      OnPlayMedia(media_action_args_proto);
-    else
-      OnMediaControlAction(action_name, media_action_args_proto);
-  }
-
-  void OnPlayMedia(const std::string& play_media_args_proto) {
-    std::optional<AndroidAppInfo> app_info =
-        GetAppInfoFromMediaArgs(play_media_args_proto);
-    if (app_info) {
-      OnOpenMediaAndroidIntent(play_media_args_proto,
-                               std::move(app_info.value()));
-    } else {
-      OnOpenUrl(play_media_args_proto);
-    }
-  }
-
-  // Handle android media playback intent.
-  void OnOpenMediaAndroidIntent(const std::string& play_media_args_proto,
-                                AndroidAppInfo app_info) {
-    app_info.action = kIntentActionView;
-    if (app_info.intent.empty()) {
-      std::string url = GetAndroidIntentUrlFromMediaArgs(play_media_args_proto);
-      if (!url.empty())
-        app_info.intent = url;
-    }
-    VLOG(1) << "Playing android media";
-    delegate().PlayAndroidMedia(std::move(app_info));
-  }
-
-  void OnOpenUrl(const std::string& play_media_args_proto) {
-    std::string url = GetWebUrlFromMediaArgs(play_media_args_proto);
-    // Fallback to web URL.
-    if (!url.empty()) {
-      VLOG(1) << "Playing web media";
-      delegate().PlayWebMedia(url);
-    }
-  }
-
-  void OnMediaControlAction(const std::string& action_name,
-                            const std::string& media_action_args_proto) {
-    if (action_name == kPauseTrackClientOp) {
-      VLOG(1) << "Pausing media playback";
-      delegate().Pause();
-      return;
-    }
-
-    if (action_name == kResumeTrackClientOp) {
-      VLOG(1) << "Resuming media playback";
-      delegate().Resume();
-      return;
-    }
-
-    if (action_name == kNextTrackClientOp) {
-      VLOG(1) << "Playing next track";
-      delegate().NextTrack();
-      return;
-    }
-
-    if (action_name == kPrevTrackClientOp) {
-      VLOG(1) << "Playing previous track";
-      delegate().PreviousTrack();
-      return;
-    }
-
-    if (action_name == kStopTrackClientOp) {
-      VLOG(1) << "Stop media playback";
-      delegate().Stop();
-      return;
-    }
-  }
-
-  mojom::MediaDelegate& delegate() { return *parent_->delegate_; }
-
-  const raw_ptr<MediaController> parent_;
-};
-
-MediaController::MediaController()
-    : events_observer_(std::make_unique<GrpcEventsObserver>(this)) {}
-
-MediaController::~MediaController() = default;
-
-void MediaController::Bind(
-    mojo::PendingReceiver<mojom::MediaController> receiver,
-    mojo::PendingRemote<mojom::MediaDelegate> delegate) {
-  receiver_.Bind(std::move(receiver));
-  delegate_.Bind(std::move(delegate));
-}
-
-void MediaController::ResumeInternalMediaPlayer() {
-  VLOG(1) << "Resume internal media player";
-  if (assistant_client_)
-    assistant_client_->ResumeCurrentStream();
-}
-
-void MediaController::PauseInternalMediaPlayer() {
-  VLOG(1) << "Pause internal media player";
-  if (assistant_client_)
-    assistant_client_->PauseCurrentStream();
-}
-
-void MediaController::SetExternalPlaybackState(mojom::MediaStatePtr state) {
-  DCHECK(!state.is_null());
-  VLOG(1) << "Update external playback state to " << state->playback_state;
-  if (assistant_client_) {
-    MediaStatus media_status_proto;
-    ConvertMediaStatusToV2FromMojom(*state, &media_status_proto);
-    assistant_client_->SetExternalPlaybackState(media_status_proto);
-  }
-}
-
-void MediaController::OnAssistantClientRunning(
-    AssistantClient* assistant_client) {
-  assistant_client_ = assistant_client;
-  // `events_observer_` outlives `assistant_client_`.
-  assistant_client->AddDeviceStateEventObserver(events_observer_.get());
-  assistant_client->AddMediaActionFallbackEventObserver(events_observer_.get());
-}
-
-void MediaController::SendGrpcMessageForTesting(
-    const ::assistant::api::OnDeviceStateEventRequest& request) {
-  events_observer_->OnGrpcMessage(request);
-}
-
-void MediaController::SendGrpcMessageForTesting(
-    const ::assistant::api::OnMediaActionFallbackEventRequest& request) {
-  events_observer_->OnGrpcMessage(request);
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/media_controller.h b/chromeos/ash/services/libassistant/media_controller.h
deleted file mode 100644
index d5de2b6a..0000000
--- a/chromeos/ash/services/libassistant/media_controller.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_MEDIA_CONTROLLER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_MEDIA_CONTROLLER_H_
-
-#include "base/memory/raw_ptr.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client_observer.h"
-#include "chromeos/ash/services/libassistant/public/mojom/media_controller.mojom.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/device_state_event.pb.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
-
-namespace ash::libassistant {
-
-class MediaController : public mojom::MediaController,
-                        public AssistantClientObserver {
- public:
-  MediaController();
-  MediaController(const MediaController&) = delete;
-  MediaController& operator=(const MediaController&) = delete;
-  ~MediaController() override;
-
-  void Bind(mojo::PendingReceiver<mojom::MediaController> receiver,
-            mojo::PendingRemote<mojom::MediaDelegate> delegate);
-
-  // mojom::MediaController implementation:
-  void ResumeInternalMediaPlayer() override;
-  void PauseInternalMediaPlayer() override;
-  void SetExternalPlaybackState(mojom::MediaStatePtr state) override;
-
-  // AssistantClientObserver implementation:
-  void OnAssistantClientRunning(AssistantClient* assistant_client) override;
-
-  void SendGrpcMessageForTesting(
-      const ::assistant::api::OnDeviceStateEventRequest& request);
-  void SendGrpcMessageForTesting(
-      const ::assistant::api::OnMediaActionFallbackEventRequest& request);
-
- private:
-  class GrpcEventsObserver;
-
-  raw_ptr<AssistantClient> assistant_client_ = nullptr;
-
-  mojo::Receiver<mojom::MediaController> receiver_{this};
-  mojo::Remote<mojom::MediaDelegate> delegate_;
-  std::unique_ptr<GrpcEventsObserver> events_observer_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_MEDIA_CONTROLLER_H_
diff --git a/chromeos/ash/services/libassistant/media_controller_unittest.cc b/chromeos/ash/services/libassistant/media_controller_unittest.cc
deleted file mode 100644
index f28ca3e9..0000000
--- a/chromeos/ash/services/libassistant/media_controller_unittest.cc
+++ /dev/null
@@ -1,381 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/media_controller.h"
-
-#include "base/memory/raw_ptr.h"
-#include "base/strings/stringprintf.h"
-#include "base/test/task_environment.h"
-#include "chromeos/ash/services/libassistant/grpc/utils/media_status_utils.h"
-#include "chromeos/ash/services/libassistant/public/mojom/media_controller.mojom.h"
-#include "chromeos/ash/services/libassistant/test_support/fake_assistant_client.h"
-#include "chromeos/ash/services/libassistant/test_support/libassistant_service_tester.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_interface.pb.h"
-#include "chromeos/assistant/internal/test_support/fake_assistant_manager.h"
-#include "chromeos/assistant/internal/util_headers.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-using LibassistantPlaybackState = assistant_client::MediaStatus::PlaybackState;
-using ProtoAndroidAppInfo = chromeos::assistant::shared::AndroidAppInfo;
-using assistant::AndroidAppInfo;
-using chromeos::assistant::shared::PlayMediaArgs;
-using mojom::PlaybackState;
-
-#define EXPECT_NO_CALLS(args...) EXPECT_CALL(args).Times(0);
-
-std::string MediaStatusToString(
-    const assistant_client::MediaStatus& media_status) {
-  return base::StringPrintf(R"(
-          MediaStatus {
-              playback_state '%i'
-              metadata.album '%s'
-              metadata.artist '%s'
-              metadata.title '%s'
-          )",
-                            static_cast<int>(media_status.playback_state),
-                            media_status.metadata.album.c_str(),
-                            media_status.metadata.artist.c_str(),
-                            media_status.metadata.title.c_str());
-}
-
-MATCHER_P(MatchesMediaStatus, expected, "") {
-  if (MediaStatusToString(arg) == MediaStatusToString(expected))
-    return true;
-
-  *result_listener << "\nExpected: " << MediaStatusToString(expected);
-  *result_listener << "\nActual: " << MediaStatusToString(arg);
-  return false;
-}
-
-class MediaDelegateMock : public mojom::MediaDelegate {
- public:
-  MediaDelegateMock() = default;
-  MediaDelegateMock(const MediaDelegateMock&) = delete;
-  MediaDelegateMock& operator=(const MediaDelegateMock&) = delete;
-  ~MediaDelegateMock() override = default;
-
-  mojo::PendingRemote<mojom::MediaDelegate> BindNewPipeAndPassRemote() {
-    return receiver_.BindNewPipeAndPassRemote();
-  }
-
-  void FlushForTesting() { receiver_.FlushForTesting(); }
-
-  // mojom::MediaDelegate implementation:
-  MOCK_METHOD(void, OnPlaybackStateChanged, (mojom::MediaStatePtr new_state));
-  MOCK_METHOD(void, PlayAndroidMedia, (const AndroidAppInfo& app_info));
-  MOCK_METHOD(void, PlayWebMedia, (const std::string& url));
-  MOCK_METHOD(void, NextTrack, ());
-  MOCK_METHOD(void, PreviousTrack, ());
-  MOCK_METHOD(void, Pause, ());
-  MOCK_METHOD(void, Resume, ());
-  MOCK_METHOD(void, Stop, ());
-
- private:
-  mojo::Receiver<mojom::MediaDelegate> receiver_{this};
-};
-
-class MediaManagerMock : public assistant_client::MediaManager {
- public:
-  MediaManagerMock() = default;
-  MediaManagerMock(const MediaManagerMock&) = delete;
-  MediaManagerMock& operator=(const MediaManagerMock&) = delete;
-  ~MediaManagerMock() override = default;
-
-  // assistant_client::MediaManager implementation:
-  void AddListener(Listener* listener) override { listener_ = listener; }
-  MOCK_METHOD(void, Next, ());
-  MOCK_METHOD(void, Previous, ());
-  MOCK_METHOD(void, Resume, ());
-  MOCK_METHOD(void, Pause, ());
-  MOCK_METHOD(void, PlayPause, ());
-  MOCK_METHOD(void, StopAndClearPlaylist, ());
-  MOCK_METHOD(void,
-              SetExternalPlaybackState,
-              (const assistant_client::MediaStatus& new_status));
-
-  Listener& listener() {
-    DCHECK(listener_);
-    return *listener_;
-  }
-
- private:
-  raw_ptr<Listener> listener_ = nullptr;
-};
-
-}  // namespace
-
-class AssistantMediaControllerTest : public testing::Test {
- public:
-  AssistantMediaControllerTest()
-      : media_controller_(std::make_unique<MediaController>()) {
-    media_controller_->Bind(client_.BindNewPipeAndPassReceiver(),
-                            delegate_.BindNewPipeAndPassRemote());
-  }
-
-  void SetUp() override {
-    service_tester_.Start();
-    service_tester_.assistant_manager().SetMediaManager(&media_manager_);
-    media_controller_->OnAssistantClientRunning(&assistant_client());
-  }
-
-  MediaManagerMock& libassistant_media_manager() { return media_manager_; }
-
-  mojo::Remote<mojom::MediaController>& client() { return client_; }
-
-  MediaDelegateMock& delegate() { return delegate_; }
-
-  MediaController& media_controller() {
-    DCHECK(media_controller_);
-    return *media_controller_;
-  }
-
-  void SendPlaybackState(const assistant_client::MediaStatus& input) {
-    ::assistant::api::OnDeviceStateEventRequest request;
-    auto* status = request.mutable_event()
-                       ->mutable_on_state_changed()
-                       ->mutable_new_state()
-                       ->mutable_media_status();
-    ConvertMediaStatusToV2FromV1(input, status);
-    media_controller().SendGrpcMessageForTesting(request);
-  }
-
-  void CallFallbackMediaHandler(const std::string& action,
-                                const std::string& action_proto) {
-    ::assistant::api::OnMediaActionFallbackEventRequest request;
-    auto* media_action =
-        request.mutable_event()->mutable_on_media_action_event();
-    media_action->set_action_name(action);
-    media_action->set_action_args(action_proto);
-    media_controller().SendGrpcMessageForTesting(request);
-  }
-
-  void FlushMojomPipes() {
-    delegate_.FlushForTesting();
-    client_.FlushForTesting();
-    service_tester_.FlushForTesting();
-  }
-
-  void RemoveAssistantManager() {
-    media_controller_->OnDestroyingAssistantClient(&assistant_client());
-  }
-
- private:
-  AssistantClient& assistant_client() {
-    return service_tester_.assistant_client();
-  }
-
-  base::test::SingleThreadTaskEnvironment environment_;
-
-  MediaManagerMock media_manager_;
-  mojo::Remote<mojom::MediaController> client_;
-  testing::StrictMock<MediaDelegateMock> delegate_;
-  std::unique_ptr<MediaController> media_controller_;
-  LibassistantServiceTester service_tester_;
-};
-
-TEST_F(AssistantMediaControllerTest,
-       ShouldSendResumeToLibassistantMediaPlayer) {
-  EXPECT_CALL(libassistant_media_manager(), Resume);
-
-  media_controller().ResumeInternalMediaPlayer();
-}
-
-TEST_F(AssistantMediaControllerTest, ShouldSendPauseToLibassistantMediaPlayer) {
-  EXPECT_CALL(libassistant_media_manager(), Pause);
-
-  media_controller().PauseInternalMediaPlayer();
-}
-
-TEST_F(AssistantMediaControllerTest, ShouldSendMediaStatusToLibassistant) {
-  EXPECT_CALL(libassistant_media_manager(), SetExternalPlaybackState);
-
-  auto input = mojom::MediaState::New();
-  media_controller().SetExternalPlaybackState(std::move(input));
-}
-
-TEST_F(AssistantMediaControllerTest, ShouldSendMediaMetadataToLibassistant) {
-  assistant_client::MediaStatus expected;
-  expected.metadata.album = "album";
-  expected.metadata.artist = "artist";
-  expected.metadata.title = "title";
-  EXPECT_CALL(libassistant_media_manager(),
-              SetExternalPlaybackState(MatchesMediaStatus(expected)));
-
-  auto input = mojom::MediaState::New();
-  input->metadata = mojom::MediaMetadata::New();
-  input->metadata->album = "album";
-  input->metadata->artist = "artist";
-  input->metadata->title = "title";
-  media_controller().SetExternalPlaybackState(std::move(input));
-}
-
-TEST_F(AssistantMediaControllerTest,
-       ShouldSendMediaPlaybackStateToLibassistant) {
-  std::vector<std::pair<PlaybackState, LibassistantPlaybackState>> pairs = {
-      {PlaybackState::kError, LibassistantPlaybackState::ERROR},
-      {PlaybackState::kIdle, LibassistantPlaybackState::IDLE},
-      {PlaybackState::kPaused, LibassistantPlaybackState::PAUSED},
-      {PlaybackState::kNewTrack, LibassistantPlaybackState::NEW_TRACK},
-      {PlaybackState::kPlaying, LibassistantPlaybackState::PLAYING},
-  };
-
-  for (auto pair : pairs) {
-    assistant_client::MediaStatus expected;
-    expected.playback_state = pair.second;
-    EXPECT_CALL(libassistant_media_manager(),
-                SetExternalPlaybackState(MatchesMediaStatus(expected)));
-
-    auto input = mojom::MediaState::New();
-    input->playback_state = pair.first;
-    media_controller().SetExternalPlaybackState(std::move(input));
-
-    testing::Mock::VerifyAndClearExpectations(&libassistant_media_manager());
-  }
-}
-
-TEST_F(AssistantMediaControllerTest,
-       ShouldNotCrashIfAssistantManagerIsNotPresent) {
-  RemoveAssistantManager();
-
-  media_controller().ResumeInternalMediaPlayer();
-  media_controller().PauseInternalMediaPlayer();
-  media_controller().SetExternalPlaybackState(mojom::MediaState::New());
-}
-
-TEST_F(AssistantMediaControllerTest, ShouldSendPlaybackStateChangeToDelegate) {
-  mojom::MediaStatePtr actual;
-  EXPECT_CALL(delegate(), OnPlaybackStateChanged)
-      .WillOnce([&](mojom::MediaStatePtr state) { actual = std::move(state); });
-
-  assistant_client::MediaStatus input;
-  input.metadata.album = "album";
-  input.metadata.artist = "artist";
-  input.metadata.title = "title";
-  SendPlaybackState(input);
-  FlushMojomPipes();
-
-  ASSERT_FALSE(actual.is_null());
-  ASSERT_FALSE(actual->metadata.is_null());
-  EXPECT_EQ(actual->metadata->album, "album");
-  EXPECT_EQ(actual->metadata->artist, "artist");
-  EXPECT_EQ(actual->metadata->title, "title");
-}
-
-TEST_F(AssistantMediaControllerTest, ShouldSendPlaybackStateToDelegate) {
-  std::vector<std::pair<PlaybackState, LibassistantPlaybackState>> pairs = {
-      {PlaybackState::kError, LibassistantPlaybackState::ERROR},
-      {PlaybackState::kIdle, LibassistantPlaybackState::IDLE},
-      {PlaybackState::kPaused, LibassistantPlaybackState::PAUSED},
-      {PlaybackState::kNewTrack, LibassistantPlaybackState::NEW_TRACK},
-      {PlaybackState::kPlaying, LibassistantPlaybackState::PLAYING},
-  };
-
-  for (auto pair : pairs) {
-    mojom::MediaStatePtr actual;
-    EXPECT_CALL(delegate(), OnPlaybackStateChanged)
-        .WillOnce(
-            [&](mojom::MediaStatePtr state) { actual = std::move(state); });
-
-    assistant_client::MediaStatus input;
-    input.playback_state = pair.second;
-    SendPlaybackState(input);
-    FlushMojomPipes();
-
-    ASSERT_FALSE(actual.is_null());
-    EXPECT_EQ(actual->playback_state, pair.first);
-  }
-}
-
-TEST_F(AssistantMediaControllerTest, ShouldSupportNext) {
-  EXPECT_CALL(delegate(), NextTrack);
-  CallFallbackMediaHandler("media.NEXT", "");
-  FlushMojomPipes();
-}
-
-TEST_F(AssistantMediaControllerTest, ShouldSupportPrevious) {
-  EXPECT_CALL(delegate(), PreviousTrack);
-  CallFallbackMediaHandler("media.PREVIOUS", "");
-  FlushMojomPipes();
-}
-
-TEST_F(AssistantMediaControllerTest, ShouldSupportPause) {
-  EXPECT_CALL(delegate(), Pause);
-  CallFallbackMediaHandler("media.PAUSE", "");
-  FlushMojomPipes();
-}
-
-TEST_F(AssistantMediaControllerTest, ShouldSupportResume) {
-  EXPECT_CALL(delegate(), Resume);
-  CallFallbackMediaHandler("media.RESUME", "");
-  FlushMojomPipes();
-}
-
-TEST_F(AssistantMediaControllerTest, ShouldSupportStop) {
-  EXPECT_CALL(delegate(), Stop);
-  CallFallbackMediaHandler("media.STOP", "");
-  FlushMojomPipes();
-}
-
-TEST_F(AssistantMediaControllerTest, ShouldSupportPlayAndroidMedia) {
-  PlayMediaArgs play_media_args;
-  PlayMediaArgs::MediaItem* media_item = play_media_args.add_media_item();
-  ProtoAndroidAppInfo* android_app_info =
-      media_item->mutable_provider()->mutable_android_app_info();
-  android_app_info->set_package_name("package");
-  android_app_info->set_localized_app_name("app name");
-  android_app_info->set_app_version(111);
-  media_item->set_uri("http://the/uri");
-
-  std::optional<AndroidAppInfo> actual;
-  EXPECT_CALL(delegate(), PlayAndroidMedia)
-      .WillOnce([&](const AndroidAppInfo& a) { actual = a; });
-
-  CallFallbackMediaHandler("media.PLAY_MEDIA",
-                           play_media_args.SerializeAsString());
-  FlushMojomPipes();
-
-  ASSERT_TRUE(actual.has_value());
-  EXPECT_EQ(actual.value().package_name, "package");
-  EXPECT_EQ(actual.value().localized_app_name, "app name");
-  EXPECT_EQ(actual.value().version, 111);
-  EXPECT_EQ(actual.value().action, "android.intent.action.VIEW");
-  EXPECT_EQ(actual.value().intent, "http://the/uri");
-}
-
-TEST_F(AssistantMediaControllerTest, ShouldSupportPlayWebMedia) {
-  PlayMediaArgs play_media_args;
-  PlayMediaArgs::MediaItem* media_item = play_media_args.add_media_item();
-  media_item->set_uri("http://the/url");
-
-  std::string actual_url = "<not-called>";
-  EXPECT_CALL(delegate(), PlayWebMedia).WillOnce([&](std::string url) {
-    actual_url = url;
-  });
-
-  CallFallbackMediaHandler("media.PLAY_MEDIA",
-                           play_media_args.SerializeAsString());
-  FlushMojomPipes();
-
-  EXPECT_EQ(actual_url, "http://the/url");
-}
-
-TEST_F(AssistantMediaControllerTest, ShouldIgnoreInvalidUrls) {
-  PlayMediaArgs play_media_args;
-  PlayMediaArgs::MediaItem* media_item = play_media_args.add_media_item();
-  media_item->set_uri("not-a-url");
-
-  EXPECT_NO_CALLS(delegate(), PlayWebMedia);
-
-  CallFallbackMediaHandler("media.PLAY_MEDIA",
-                           play_media_args.SerializeAsString());
-  FlushMojomPipes();
-}
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/network_provider_impl.cc b/chromeos/ash/services/libassistant/network_provider_impl.cc
deleted file mode 100644
index e32dd58..0000000
--- a/chromeos/ash/services/libassistant/network_provider_impl.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/network_provider_impl.h"
-
-#include <vector>
-
-#include "base/containers/contains.h"
-#include "base/functional/bind.h"
-#include "chromeos/ash/services/libassistant/public/mojom/platform_delegate.mojom.h"
-#include "chromeos/services/network_config/public/mojom/constants.mojom.h"
-#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom-forward.h"
-
-using ConnectionStatus = assistant_client::NetworkProvider::ConnectionStatus;
-
-namespace ash::libassistant {
-
-namespace network_config = ::chromeos::network_config;
-
-NetworkProviderImpl::NetworkProviderImpl()
-    : connection_status_(ConnectionStatus::UNKNOWN) {}
-
-void NetworkProviderImpl::Initialize(
-    mojom::PlatformDelegate* platform_delegate) {
-  platform_delegate->BindNetworkConfig(
-      cros_network_config_remote_.BindNewPipeAndPassReceiver());
-  cros_network_config_remote_->AddObserver(
-      receiver_.BindNewPipeAndPassRemote());
-  cros_network_config_remote_->GetNetworkStateList(
-      network_config::mojom::NetworkFilter::New(
-          network_config::mojom::FilterType::kActive,
-          network_config::mojom::NetworkType::kAll,
-          network_config::mojom::kNoLimit),
-      base::BindOnce(&NetworkProviderImpl::OnActiveNetworksChanged,
-                     base::Unretained(this)));
-}
-
-NetworkProviderImpl::~NetworkProviderImpl() = default;
-
-void NetworkProviderImpl::OnActiveNetworksChanged(
-    std::vector<network_config::mojom::NetworkStatePropertiesPtr> networks) {
-  const bool is_any_network_online = base::Contains(
-      networks, network_config::mojom::ConnectionStateType::kOnline,
-      &network_config::mojom::NetworkStateProperties::connection_state);
-
-  if (is_any_network_online)
-    connection_status_ = ConnectionStatus::CONNECTED;
-  else
-    connection_status_ = ConnectionStatus::DISCONNECTED_FROM_INTERNET;
-}
-
-ConnectionStatus NetworkProviderImpl::GetConnectionStatus() {
-  return connection_status_;
-}
-
-// Mdns responder is not supported in ChromeOS.
-assistant_client::MdnsResponder* NetworkProviderImpl::GetMdnsResponder() {
-  return nullptr;
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/network_provider_impl.h b/chromeos/ash/services/libassistant/network_provider_impl.h
deleted file mode 100644
index 193b8a33..0000000
--- a/chromeos/ash/services/libassistant/network_provider_impl.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_NETWORK_PROVIDER_IMPL_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_NETWORK_PROVIDER_IMPL_H_
-
-#include <vector>
-
-#include "chromeos/ash/services/libassistant/public/mojom/platform_delegate.mojom-forward.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/services/network_config/public/cpp/cros_network_config_observer.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
-
-namespace ash::libassistant {
-
-class COMPONENT_EXPORT(ASSISTANT_SERVICE) NetworkProviderImpl
-    : public assistant_client::NetworkProvider,
-      public chromeos::network_config::CrosNetworkConfigObserver {
- public:
-  NetworkProviderImpl();
-
-  NetworkProviderImpl(const NetworkProviderImpl&) = delete;
-  NetworkProviderImpl& operator=(const NetworkProviderImpl&) = delete;
-
-  ~NetworkProviderImpl() override;
-
-  void Initialize(mojom::PlatformDelegate* platform_delegate);
-
-  // assistant_client::NetworkProvider:
-  ConnectionStatus GetConnectionStatus() override;
-  assistant_client::MdnsResponder* GetMdnsResponder() override;
-
-  // chromeos::network_config::CrosNetworkConfigObserver:
-  void OnActiveNetworksChanged(
-      std::vector<chromeos::network_config::mojom::NetworkStatePropertiesPtr>
-          networks) override;
-
- private:
-  ConnectionStatus connection_status_;
-  mojo::Receiver<chromeos::network_config::mojom::CrosNetworkConfigObserver>
-      receiver_{this};
-  mojo::Remote<chromeos::network_config::mojom::CrosNetworkConfig>
-      cros_network_config_remote_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_NETWORK_PROVIDER_IMPL_H_
diff --git a/chromeos/ash/services/libassistant/network_provider_impl_unittest.cc b/chromeos/ash/services/libassistant/network_provider_impl_unittest.cc
deleted file mode 100644
index 3cc74503..0000000
--- a/chromeos/ash/services/libassistant/network_provider_impl_unittest.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/network_provider_impl.h"
-
-#include <utility>
-#include <vector>
-
-#include "base/test/task_environment.h"
-#include "chromeos/ash/services/libassistant/test_support/fake_platform_delegate.h"
-#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom-forward.h"
-#include "chromeos/services/network_config/public/mojom/network_types.mojom-forward.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::libassistant {
-
-using ::chromeos::network_config::mojom::ConnectionStateType;
-using ::chromeos::network_config::mojom::NetworkStatePropertiesPtr;
-using ConnectionStatus = NetworkProviderImpl::ConnectionStatus;
-
-class AssistantNetworkProviderImplTest : public ::testing::Test {
- public:
-  AssistantNetworkProviderImplTest() {
-    network_provider_.Initialize(&platform_delegate_);
-  }
-
-  AssistantNetworkProviderImplTest(const AssistantNetworkProviderImplTest&) =
-      delete;
-  AssistantNetworkProviderImplTest& operator=(
-      const AssistantNetworkProviderImplTest&) = delete;
-
-  ~AssistantNetworkProviderImplTest() override = default;
-
-  void PublishConnectionStateType(ConnectionStateType connection_type) {
-    std::vector<NetworkStatePropertiesPtr> active_networks;
-    active_networks.push_back(CreateNetworkState(connection_type));
-
-    PublishActiveNetworks(std::move(active_networks));
-  }
-
-  NetworkStatePropertiesPtr CreateNetworkState(
-      ConnectionStateType connection_type) const {
-    NetworkStatePropertiesPtr network_state =
-        chromeos::network_config::mojom::NetworkStateProperties::New();
-    network_state->connection_state = connection_type;
-    return network_state;
-  }
-
-  void PublishActiveNetworks(
-      std::vector<NetworkStatePropertiesPtr> active_networks) {
-    network_provider_.OnActiveNetworksChanged(std::move(active_networks));
-  }
-
-  std::vector<std::pair<ConnectionStateType, ConnectionStatus>>
-  GetStatusPairs() {
-    return {
-        {ConnectionStateType::kOnline, ConnectionStatus::CONNECTED},
-        {ConnectionStateType::kConnected,
-         ConnectionStatus::DISCONNECTED_FROM_INTERNET},
-        {ConnectionStateType::kPortal,
-         ConnectionStatus::DISCONNECTED_FROM_INTERNET},
-        {ConnectionStateType::kNotConnected,
-         ConnectionStatus::DISCONNECTED_FROM_INTERNET},
-    };
-  }
-
- protected:
-  base::test::TaskEnvironment task_environment;
-  assistant::FakePlatformDelegate platform_delegate_;
-  NetworkProviderImpl network_provider_;
-};
-
-TEST_F(AssistantNetworkProviderImplTest, StartWithStatusUnknown) {
-  EXPECT_EQ(ConnectionStatus::UNKNOWN, network_provider_.GetConnectionStatus());
-}
-
-TEST_F(AssistantNetworkProviderImplTest,
-       ChangeStateBasedOnConnectionStateType) {
-  for (const auto& test : GetStatusPairs()) {
-    ConnectionStateType input = test.first;
-    ConnectionStatus expected = test.second;
-
-    PublishConnectionStateType(input);
-
-    EXPECT_EQ(expected, network_provider_.GetConnectionStatus())
-        << "Failure with input " << input;
-  }
-}
-
-TEST_F(AssistantNetworkProviderImplTest,
-       IsOnlineIfOneOfTheActiveNetworksIsOnline) {
-  std::vector<NetworkStatePropertiesPtr> active_networks{};
-  active_networks.push_back(
-      CreateNetworkState(ConnectionStateType::kNotConnected));
-  active_networks.push_back(CreateNetworkState(ConnectionStateType::kOnline));
-
-  PublishActiveNetworks(std::move(active_networks));
-
-  EXPECT_EQ(ConnectionStatus::CONNECTED,
-            network_provider_.GetConnectionStatus());
-}
-
-TEST_F(AssistantNetworkProviderImplTest, IsOfflineIfThereAreNoNetworks) {
-  PublishActiveNetworks({});
-
-  EXPECT_EQ(ConnectionStatus::DISCONNECTED_FROM_INTERNET,
-            network_provider_.GetConnectionStatus());
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/notification_delegate_unittest.cc b/chromeos/ash/services/libassistant/notification_delegate_unittest.cc
deleted file mode 100644
index 00f72401..0000000
--- a/chromeos/ash/services/libassistant/notification_delegate_unittest.cc
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/memory/raw_ref.h"
-#include "base/test/task_environment.h"
-#include "chromeos/ash/services/libassistant/public/cpp/assistant_notification.h"
-#include "chromeos/ash/services/libassistant/public/mojom/notification_delegate.mojom-forward.h"
-#include "chromeos/ash/services/libassistant/test_support/libassistant_service_tester.h"
-#include "chromeos/assistant/internal/action/cros_action_module.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_interface.pb.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-class NotificationDelegateMock : public mojom::NotificationDelegate {
- public:
-  NotificationDelegateMock() = default;
-  NotificationDelegateMock(const NotificationDelegateMock&) = delete;
-  NotificationDelegateMock& operator=(const NotificationDelegateMock&) = delete;
-  ~NotificationDelegateMock() override = default;
-
-  // mojom::NotificationDelegate implementation:
-  MOCK_METHOD(void,
-              AddOrUpdateNotification,
-              (assistant::AssistantNotification notification));
-  MOCK_METHOD(void, RemoveAllNotifications, (bool from_server));
-  MOCK_METHOD(void,
-              RemoveNotificationByGroupingKey,
-              (const std::string& grouping_key, bool from_server));
-
-  void Bind(
-      mojo::PendingReceiver<mojom::NotificationDelegate> pending_receiver) {
-    receiver_.Bind(std::move(pending_receiver));
-  }
-
-  void FlushForTesting() { receiver_.FlushForTesting(); }
-
- private:
-  mojo::Receiver<mojom::NotificationDelegate> receiver_{this};
-};
-
-// Helper class to fire interaction response handlers for tests.
-// TODO(meilinw): move it to a separate class since it is used both here and
-// by |ConversationObserverTest|.
-class CrosActionModuleHelper {
- public:
-  explicit CrosActionModuleHelper(
-      chromeos::assistant::action::CrosActionModule* action_module)
-      : action_module_(*action_module) {}
-  CrosActionModuleHelper(const CrosActionModuleHelper&) = delete;
-  CrosActionModuleHelper& operator=(const CrosActionModuleHelper&) = delete;
-  ~CrosActionModuleHelper() = default;
-
-  void ShowNotification(
-      const chromeos::assistant::action::Notification& notification) {
-    for (auto* observer : action_observers())
-      observer->OnShowNotification(notification);
-  }
-
- private:
-  const std::vector<chromeos::assistant::action::AssistantActionObserver*>&
-  action_observers() {
-    return action_module_->GetActionObserversForTesting();
-  }
-
-  const raw_ref<const chromeos::assistant::action::CrosActionModule>
-      action_module_;
-};
-
-}  // namespace
-
-class NotificationDelegateTest : public ::testing::Test {
- public:
-  NotificationDelegateTest() = default;
-  NotificationDelegateTest(const NotificationDelegateTest&) = delete;
-  NotificationDelegateTest& operator=(const NotificationDelegateTest&) = delete;
-  ~NotificationDelegateTest() override = default;
-
-  void SetUp() override {
-    delegate_mock_.Bind(
-        service_tester_.GetNotificationDelegatePendingReceiver());
-    service_tester_.Start();
-    action_module_helper_ = std::make_unique<CrosActionModuleHelper>(
-        static_cast<chromeos::assistant::action::CrosActionModule*>(
-            service_tester_.service()
-                .conversation_controller()
-                .action_module()));
-
-    service_tester_.service()
-        .conversation_controller()
-        .OnAssistantClientRunning(&service_tester_.assistant_client());
-  }
-
-  NotificationDelegateMock& delegate_mock() { return delegate_mock_; }
-
-  CrosActionModuleHelper& action_module_helper() {
-    return *action_module_helper_.get();
-  }
-
-  void OnNotificationRemoved(const std::string& grouping_id) {
-    ::assistant::api::OnDeviceStateEventRequest request;
-    auto* notification_removed =
-        request.mutable_event()->mutable_on_notification_removed();
-    notification_removed->set_grouping_id(grouping_id);
-
-    service_tester_.service().conversation_controller().OnGrpcMessageForTesting(
-        std::move(request));
-  }
-
- private:
-  base::test::SingleThreadTaskEnvironment environment_;
-  ::testing::StrictMock<NotificationDelegateMock> delegate_mock_;
-  LibassistantServiceTester service_tester_;
-  std::unique_ptr<CrosActionModuleHelper> action_module_helper_;
-};
-
-TEST_F(NotificationDelegateTest, ShouldInvokeAddOrUpdateNotification) {
-  chromeos::assistant::action::Notification input_notification{
-      /*title=*/"title",
-      /*text=*/"text",
-      /*action_url=*/"https://action-url/",
-      /*notification_id=*/"notification_id",
-      /*consistency_token=*/"consistency_token",
-      /*opaque_token=*/"opaque_token",
-      /*grouping_key=*/"grouping_key",
-      /*obfuscated_gaia_id=*/"obfuscated_gaia_id",
-      /*expiry_timestamp_ms=*/100,
-  };
-
-  EXPECT_CALL(delegate_mock(), AddOrUpdateNotification)
-      .WillOnce(testing::Invoke(
-          [&](const assistant::AssistantNotification& output_notification) {
-            EXPECT_EQ("title", output_notification.title);
-            EXPECT_EQ("text", output_notification.message);
-            EXPECT_EQ("notification_id", output_notification.server_id);
-            EXPECT_EQ("notification_id", output_notification.client_id);
-            EXPECT_EQ("consistency_token",
-                      output_notification.consistency_token);
-            EXPECT_EQ("opaque_token", output_notification.opaque_token);
-            EXPECT_EQ("grouping_key", output_notification.grouping_key);
-            EXPECT_EQ("obfuscated_gaia_id",
-                      output_notification.obfuscated_gaia_id);
-            EXPECT_EQ(base::Time::FromMillisecondsSinceUnixEpoch(100),
-                      output_notification.expiry_time);
-            EXPECT_EQ(true, output_notification.from_server);
-          }));
-
-  action_module_helper().ShowNotification(input_notification);
-  delegate_mock().FlushForTesting();
-}
-
-TEST_F(NotificationDelegateTest, ShouldInvokeRemoveAllNotifications) {
-  EXPECT_CALL(delegate_mock(), RemoveAllNotifications(/*from_server=*/true));
-
-  // Pass in empty |grouping_key| should trigger all notifications being
-  // removed.
-  OnNotificationRemoved(/*grouping_key=*/"");
-  delegate_mock().FlushForTesting();
-}
-
-TEST_F(NotificationDelegateTest, ShouldInvokeRemoveNotificationByGroupingKey) {
-  const std::string grouping_id = "grouping-id";
-  EXPECT_CALL(delegate_mock(), RemoveNotificationByGroupingKey(
-                                   /*id=*/grouping_id, /*from_server=*/true));
-
-  // Pass in non-empty |grouping_key| will trigger specific group of
-  // notifications being removed.
-  OnNotificationRemoved(grouping_id);
-  delegate_mock().FlushForTesting();
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/platform_api.cc b/chromeos/ash/services/libassistant/platform_api.cc
deleted file mode 100644
index 39291bb..0000000
--- a/chromeos/ash/services/libassistant/platform_api.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/platform_api.h"
-
-#include "base/check.h"
-#include "chromeos/ash/services/assistant/public/cpp/features.h"
-#include "chromeos/ash/services/libassistant/audio/audio_output_provider_impl.h"
-#include "chromeos/ash/services/libassistant/fake_auth_provider.h"
-#include "chromeos/ash/services/libassistant/file_provider_impl.h"
-#include "chromeos/ash/services/libassistant/power_manager_provider_impl.h"
-#include "chromeos/ash/services/libassistant/system_provider_impl.h"
-#include "media/audio/audio_device_description.h"
-
-namespace ash::libassistant {
-
-PlatformApi::PlatformApi()
-    : audio_output_provider_(std::make_unique<AudioOutputProviderImpl>(
-          media::AudioDeviceDescription::kDefaultDeviceId)),
-      fake_auth_provider_(std::make_unique<FakeAuthProvider>()),
-      file_provider_(std::make_unique<FileProviderImpl>()),
-      network_provider_(std::make_unique<NetworkProviderImpl>()) {
-  // Only enable native power features if they are supported by the UI.
-  std::unique_ptr<PowerManagerProviderImpl> provider;
-  if (assistant::features::IsPowerManagerEnabled()) {
-    provider = std::make_unique<PowerManagerProviderImpl>();
-  }
-  system_provider_ = std::make_unique<SystemProviderImpl>(std::move(provider));
-}
-
-PlatformApi::~PlatformApi() = default;
-
-void PlatformApi::Bind(
-    mojo::PendingRemote<mojom::AudioOutputDelegate> audio_output_delegate,
-    mojom::PlatformDelegate* platform_delegate) {
-  audio_output_provider_->Bind(std::move(audio_output_delegate),
-                               platform_delegate);
-  network_provider_->Initialize(platform_delegate);
-  system_provider_->Initialize(platform_delegate);
-}
-
-PlatformApi& PlatformApi::SetAudioInputProvider(
-    assistant_client::AudioInputProvider* provider) {
-  audio_input_provider_ = provider;
-  return *this;
-}
-
-assistant_client::AudioInputProvider& PlatformApi::GetAudioInputProvider() {
-  DCHECK(audio_input_provider_);
-  return *audio_input_provider_;
-}
-
-assistant_client::AudioOutputProvider& PlatformApi::GetAudioOutputProvider() {
-  DCHECK(audio_output_provider_);
-  return *audio_output_provider_;
-}
-
-assistant_client::AuthProvider& PlatformApi::GetAuthProvider() {
-  DCHECK(fake_auth_provider_);
-  return *fake_auth_provider_;
-}
-
-assistant_client::FileProvider& PlatformApi::GetFileProvider() {
-  DCHECK(file_provider_);
-  return *file_provider_;
-}
-
-assistant_client::NetworkProvider& PlatformApi::GetNetworkProvider() {
-  DCHECK(network_provider_);
-  return *network_provider_;
-}
-
-assistant_client::SystemProvider& PlatformApi::GetSystemProvider() {
-  DCHECK(system_provider_);
-  return *system_provider_;
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/platform_api.h b/chromeos/ash/services/libassistant/platform_api.h
deleted file mode 100644
index 951f330e..0000000
--- a/chromeos/ash/services/libassistant/platform_api.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_PLATFORM_API_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_PLATFORM_API_H_
-
-#include <memory>
-
-#include "base/memory/raw_ptr.h"
-#include "chromeos/ash/services/libassistant/network_provider_impl.h"
-#include "chromeos/ash/services/libassistant/public/mojom/audio_output_delegate.mojom.h"
-#include "chromeos/ash/services/libassistant/public/mojom/platform_delegate.mojom.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-
-namespace ash::libassistant {
-
-class AudioOutputProviderImpl;
-class FakeAuthProvider;
-class FileProviderImpl;
-class NetworkProviderImpl;
-class SystemProviderImpl;
-
-// Implementation of the Libassistant PlatformApi.
-// The components that haven't been migrated to this mojom service will still be
-// implemented chromeos/service/assistant/platform (and simply be exposed here).
-class PlatformApi : public assistant_client::PlatformApi {
- public:
-  PlatformApi();
-  PlatformApi(const PlatformApi&) = delete;
-  PlatformApi& operator=(const PlatformApi&) = delete;
-  ~PlatformApi() override;
-
-  void Bind(
-      mojo::PendingRemote<mojom::AudioOutputDelegate> audio_output_delegate,
-      mojom::PlatformDelegate* platform_delegate);
-
-  PlatformApi& SetAudioInputProvider(assistant_client::AudioInputProvider*);
-
-  // assistant_client::PlatformApi:
-  assistant_client::AudioInputProvider& GetAudioInputProvider() override;
-  assistant_client::AudioOutputProvider& GetAudioOutputProvider() override;
-  assistant_client::AuthProvider& GetAuthProvider() override;
-  assistant_client::FileProvider& GetFileProvider() override;
-  assistant_client::NetworkProvider& GetNetworkProvider() override;
-  assistant_client::SystemProvider& GetSystemProvider() override;
-
- private:
-  // This is owned by |AudioInputController|.
-  raw_ptr<assistant_client::AudioInputProvider> audio_input_provider_ = nullptr;
-
-  std::unique_ptr<AudioOutputProviderImpl> audio_output_provider_;
-  std::unique_ptr<FakeAuthProvider> fake_auth_provider_;
-  std::unique_ptr<FileProviderImpl> file_provider_;
-  std::unique_ptr<NetworkProviderImpl> network_provider_;
-  std::unique_ptr<SystemProviderImpl> system_provider_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_PLATFORM_API_H_
diff --git a/chromeos/ash/services/libassistant/power_manager_provider_impl.cc b/chromeos/ash/services/libassistant/power_manager_provider_impl.cc
deleted file mode 100644
index 7919622..0000000
--- a/chromeos/ash/services/libassistant/power_manager_provider_impl.cc
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/power_manager_provider_impl.h"
-
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/threading/platform_thread.h"
-#include "base/time/tick_clock.h"
-#include "base/time/time.h"
-#include "chromeos/ash/services/libassistant/public/mojom/platform_delegate.mojom.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "services/device/public/mojom/wake_lock_provider.mojom.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-// Tag used to identify Assistant timers.
-constexpr char kTag[] = "Assistant";
-
-// Used with wake lock APIs.
-constexpr char kWakeLockReason[] = "Assistant";
-
-// Copied from Chrome's //base/time/time_now_posix.cc.
-// Returns count of |clk_id| in the form of a time delta. Returns an empty time
-// delta if |clk_id| isn't present on the system.
-base::TimeDelta ClockNow(clockid_t clk_id) {
-  struct timespec ts;
-  if (clock_gettime(clk_id, &ts) != 0) {
-    NOTREACHED() << "clock_gettime(" << clk_id << ") failed.";
-  }
-  return base::TimeDelta::FromTimeSpec(ts);
-}
-
-}  // namespace
-
-PowerManagerProviderImpl::PowerManagerProviderImpl()
-    : main_thread_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()),
-      weak_factory_(this) {}
-
-void PowerManagerProviderImpl::Initialize(mojom::PlatformDelegate* delegate) {
-  platform_delegate_ = delegate;
-}
-
-PowerManagerProviderImpl::~PowerManagerProviderImpl() = default;
-
-PowerManagerProviderImpl::AlarmId PowerManagerProviderImpl::AddWakeAlarm(
-    uint64_t relative_time_ms,
-    uint64_t max_delay_ms,
-    assistant_client::Callback0 callback) {
-  const AlarmId id = next_id_++;
-  DVLOG(1) << __func__ << "Add alarm ID " << id << " for "
-           << base::Time::Now() + base::Milliseconds(relative_time_ms);
-
-  main_thread_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          &PowerManagerProviderImpl::AddWakeAlarmOnMainThread,
-          weak_factory_.GetWeakPtr(), id,
-          GetCurrentBootTime() + base::Milliseconds(relative_time_ms),
-          std::move(callback)));
-  return id;
-}
-
-void PowerManagerProviderImpl::ExpireWakeAlarmNow(AlarmId id) {
-  DVLOG(1) << __func__;
-  main_thread_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&PowerManagerProviderImpl::OnTimerFiredOnMainThread,
-                     weak_factory_.GetWeakPtr(), id));
-}
-
-void PowerManagerProviderImpl::AcquireWakeLock() {
-  DVLOG(1) << __func__;
-  main_thread_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&PowerManagerProviderImpl::AcquireWakeLockOnMainThread,
-                     weak_factory_.GetWeakPtr()));
-}
-
-void PowerManagerProviderImpl::ReleaseWakeLock() {
-  DVLOG(1) << __func__;
-  main_thread_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&PowerManagerProviderImpl::ReleaseWakeLockOnMainThread,
-                     weak_factory_.GetWeakPtr()));
-}
-
-base::TimeTicks PowerManagerProviderImpl::GetCurrentBootTime() {
-  if (tick_clock_)
-    return tick_clock_->NowTicks();
-  return base::TimeTicks() + ClockNow(CLOCK_BOOTTIME);
-}
-
-void PowerManagerProviderImpl::AddWakeAlarmOnMainThread(
-    AlarmId id,
-    base::TimeTicks absolute_expiration_time,
-    assistant_client::Callback0 callback) {
-  DVLOG(1) << __func__;
-  DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
-
-  auto timer =
-      std::make_unique<chromeos::NativeTimer>(kTag + base::NumberToString(id));
-  // Once the timer is created successfully, start the timer and store
-  // associated data. The stored |callback| will be called in
-  // |OnTimerFiredOnMainThread|.
-  DVLOG(1) << "Starting timer with ID " << id << " for "
-           << absolute_expiration_time;
-  timer->Start(
-      absolute_expiration_time,
-      base::BindOnce(&PowerManagerProviderImpl::OnTimerFiredOnMainThread,
-                     weak_factory_.GetWeakPtr(), id),
-      base::BindOnce(&PowerManagerProviderImpl::OnStartTimerCallback,
-                     weak_factory_.GetWeakPtr(), id));
-  timers_[id] = std::make_pair(std::move(callback), std::move(timer));
-}
-
-void PowerManagerProviderImpl::AcquireWakeLockOnMainThread() {
-  DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK_GE(wake_lock_count_, 0);
-
-  wake_lock_count_++;
-  if (wake_lock_count_ > 1) {
-    DVLOG(1) << "Wake lock acquire. Count: " << wake_lock_count_;
-    return;
-  }
-
-  // Initialize |wake_lock_| if this is the first time we're using it. Assistant
-  // can acquire a wake lock even when it has nothing to show on the display,
-  // this shouldn't wake the display up. Hence, the wake lock acquired is of
-  // type kPreventAppSuspension.
-  if (!wake_lock_) {
-    mojo::Remote<device::mojom::WakeLockProvider> provider;
-    platform_delegate_->BindWakeLockProvider(
-        provider.BindNewPipeAndPassReceiver());
-    provider->GetWakeLockWithoutContext(
-        device::mojom::WakeLockType::kPreventAppSuspension,
-        device::mojom::WakeLockReason::kOther, kWakeLockReason,
-        wake_lock_.BindNewPipeAndPassReceiver());
-  }
-
-  DVLOG(1) << "Wake lock new acquire";
-  // This would violate |GetWakeLockWithoutContext|'s API contract.
-  DCHECK(wake_lock_);
-  wake_lock_->RequestWakeLock();
-}
-
-void PowerManagerProviderImpl::ReleaseWakeLockOnMainThread() {
-  DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK_GE(wake_lock_count_, 0);
-
-  if (wake_lock_count_ == 0) {
-    LOG(WARNING) << "Release without acquire. Count: " << wake_lock_count_;
-    return;
-  }
-
-  wake_lock_count_--;
-  if (wake_lock_count_ >= 1) {
-    DVLOG(1) << "Wake lock release. Count: " << wake_lock_count_;
-    return;
-  }
-
-  DCHECK(wake_lock_);
-  DVLOG(1) << "Wake lock force release";
-  wake_lock_->CancelWakeLock();
-}
-
-void PowerManagerProviderImpl::OnStartTimerCallback(AlarmId id, bool result) {
-  DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
-
-  if (!result) {
-    // TODO(crbug.com/40608625): Notify Assistant of error so that it can do
-    // something meaningful in the UI.
-    LOG(ERROR) << "Failed to start timer on alarm ID " << id;
-    // Remove any metadata and resources associated with timers mapped to |id|.
-    DCHECK_GT(timers_.erase(id), 0UL);
-  }
-}
-
-void PowerManagerProviderImpl::OnTimerFiredOnMainThread(AlarmId id) {
-  DVLOG(1) << __func__ << " ID " << id;
-  DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
-
-  auto it = timers_.find(id);
-  if (it == timers_.end()) {
-    LOG(ERROR) << "Alarm with id " << id << " not found";
-    return;
-  }
-
-  // Stop tracking the timer once it has fired.
-  CallbackAndTimer& callback_and_timer = it->second;
-  callback_and_timer.first();
-  timers_.erase(id);
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/power_manager_provider_impl.h b/chromeos/ash/services/libassistant/power_manager_provider_impl.h
deleted file mode 100644
index 85f671f..0000000
--- a/chromeos/ash/services/libassistant/power_manager_provider_impl.h
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_POWER_MANAGER_PROVIDER_IMPL_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_POWER_MANAGER_PROVIDER_IMPL_H_
-
-#include <map>
-#include <memory>
-#include <utility>
-
-#include "base/component_export.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/task/sequenced_task_runner.h"
-#include "chromeos/ash/services/libassistant/public/mojom/platform_delegate.mojom-forward.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/dbus/power/native_timer.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "services/device/public/mojom/wake_lock.mojom.h"
-
-namespace ash::libassistant {
-
-// Implementation of power management features for libassistant.
-//
-// This object lives on Assistant service's main thread i.e. on the same
-// sequence as |main_thread_task_runner_|. It is safe to assume that no lifetime
-// issues will occur if all its state is accessed from
-// |main_thread_task_runner_|. Any tasks posted on that will be invalidated if
-// this object dies.
-//
-// However, the public API of this class is called by libassistant and has no
-// guarantees on which thread it's called on. Therefore each method posts a task
-// on |main_thread_task_runner_| to mimic running the API on the same sequence
-// for thread safe access to all class members, as well as using Chrome APIs in
-// a thread safe manner.
-class COMPONENT_EXPORT(ASSISTANT_SERVICE) PowerManagerProviderImpl
-    : public assistant_client::PowerManagerProvider {
- public:
-  PowerManagerProviderImpl();
-
-  PowerManagerProviderImpl(const PowerManagerProviderImpl&) = delete;
-  PowerManagerProviderImpl& operator=(const PowerManagerProviderImpl&) = delete;
-
-  ~PowerManagerProviderImpl() override;
-
-  void Initialize(mojom::PlatformDelegate* delegate);
-
-  // assistant_client::PowerManagerProvider overrides. These are called from
-  // libassistant threads.
-  AlarmId AddWakeAlarm(uint64_t relative_time_ms,
-                       uint64_t max_delay_ms,
-                       assistant_client::Callback0 callback) override;
-  void ExpireWakeAlarmNow(AlarmId alarm_id) override;
-  void AcquireWakeLock() override;
-  void ReleaseWakeLock() override;
-
-  void set_tick_clock_for_testing(const base::TickClock* tick_clock) {
-    DCHECK(tick_clock);
-    tick_clock_ = tick_clock;
-  }
-
- private:
-  using CallbackAndTimer = std::pair<assistant_client::Callback0,
-                                     std::unique_ptr<chromeos::NativeTimer>>;
-
-  // Returns time ticks from boot including time ticks during sleeping.
-  base::TimeTicks GetCurrentBootTime();
-
-  // Creates a native timer by calling |NativeTimer::Create|. Runs on
-  // |main_thread_task_runner_|.
-  void AddWakeAlarmOnMainThread(AlarmId id,
-                                base::TimeTicks absolute_expiration_time,
-                                assistant_client::Callback0 callback);
-
-  // Creates (if not created) and acquires |wake_lock_|.
-  // Runs on |main_thread_task_runner_|.
-  void AcquireWakeLockOnMainThread();
-
-  // Releases |wake_lock_|. Runs on |main_thread_task_runner_|.
-  void ReleaseWakeLockOnMainThread();
-
-  // Callback for a start operation on a |NativeTimer|.
-  void OnStartTimerCallback(AlarmId id, bool result);
-
-  // Callback for timer with id |id| added via |AddWakeAlarm|. It calls the
-  // corresponding client callback associated with the alarm. Removes the entry
-  // for |id| from |timers_|.
-  void OnTimerFiredOnMainThread(AlarmId id);
-
-  // Store of currently active alarm ids returned to clients and the
-  // corresponding pair of timer objects and client callbacks.
-  std::map<AlarmId, CallbackAndTimer> timers_;
-
-  // Monotonically increasing id used as key in |timers_| and assigned to timers
-  // in |AddWakeAlarm|. This is the only member that is accessed from
-  // libassistant threads only and not from |main_thread_task_runner_|.
-  AlarmId next_id_ = 1;
-
-  // Lazily initialized in response to the first call to |AcquireWakeLock|.
-  mojo::Remote<device::mojom::WakeLock> wake_lock_;
-
-  // Current number of clients that requested |wake_lock_|. On zero |wake_lock_|
-  // is released.
-  int wake_lock_count_ = 0;
-
-  // Used to post tasks from a libassistant thread on to the main thread in
-  // order to use Chrome APIs safely.
-  const scoped_refptr<base::SequencedTaskRunner> main_thread_task_runner_;
-
-  // Owned by |PlatformApi|. Used to initialize |wake_lock_|.
-  raw_ptr<mojom::PlatformDelegate> platform_delegate_ = nullptr;
-
-  // Clock to use to calculate time ticks. Set and used only for testing.
-  raw_ptr<const base::TickClock> tick_clock_ = nullptr;
-
-  base::WeakPtrFactory<PowerManagerProviderImpl> weak_factory_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_POWER_MANAGER_PROVIDER_IMPL_H_
diff --git a/chromeos/ash/services/libassistant/power_manager_provider_impl_unittest.cc b/chromeos/ash/services/libassistant/power_manager_provider_impl_unittest.cc
deleted file mode 100644
index f0f35f3..0000000
--- a/chromeos/ash/services/libassistant/power_manager_provider_impl_unittest.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/power_manager_provider_impl.h"
-
-#include "base/memory/raw_ptr.h"
-#include "base/run_loop.h"
-#include "base/test/task_environment.h"
-#include "chromeos/ash/services/libassistant/test_support/fake_platform_delegate.h"
-#include "chromeos/dbus/power/fake_power_manager_client.h"
-#include "services/device/public/cpp/test/test_wake_lock_provider.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-// Constants to be used with the |AddWakeAlarm| API.
-const uint64_t kAlarmRelativeTimeMs = 1000;
-const uint64_t kAlarmMaxDelayMs = 0;
-
-class FakePlatformDelegateImpl : public assistant::FakePlatformDelegate {
- public:
-  explicit FakePlatformDelegateImpl(
-      device::TestWakeLockProvider* wake_lock_provider)
-      : wake_lock_provider_(wake_lock_provider) {}
-
-  // FakePlatformDelegate implementation:
-  void BindWakeLockProvider(
-      mojo::PendingReceiver<::device::mojom::WakeLockProvider> receiver)
-      override {
-    wake_lock_provider_->BindReceiver(std::move(receiver));
-  }
-
- private:
-  const raw_ptr<device::TestWakeLockProvider> wake_lock_provider_;
-};
-
-}  // namespace
-
-class AssistantPowerManagerProviderImplTest : public testing::Test {
- public:
-  AssistantPowerManagerProviderImplTest()
-      : task_environment_(base::test::TaskEnvironment::MainThreadType::IO,
-                          base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
-
-  AssistantPowerManagerProviderImplTest(
-      const AssistantPowerManagerProviderImplTest&) = delete;
-  AssistantPowerManagerProviderImplTest& operator=(
-      const AssistantPowerManagerProviderImplTest&) = delete;
-
-  ~AssistantPowerManagerProviderImplTest() override = default;
-
-  void SetUp() override {
-    chromeos::PowerManagerClient::InitializeFake();
-    chromeos::FakePowerManagerClient::Get()->set_tick_clock(
-        task_environment_.GetMockTickClock());
-    power_manager_provider_impl_ = std::make_unique<PowerManagerProviderImpl>();
-    power_manager_provider_impl_->set_tick_clock_for_testing(
-        task_environment_.GetMockTickClock());
-
-    power_manager_provider_impl_->Initialize(&platform_delegate_);
-  }
-
-  void TearDown() override {
-    power_manager_provider_impl_.reset();
-    chromeos::PowerManagerClient::Shutdown();
-  }
-
- protected:
-  PowerManagerProviderImpl* GetPowerManagerProviderImpl() {
-    return power_manager_provider_impl_.get();
-  }
-
-  // Calls the acquire wake lock API and ensures that the request has reached
-  // the wake lock provider.
-  void AcquireWakeLock() {
-    power_manager_provider_impl_->AcquireWakeLock();
-    base::RunLoop run_loop;
-    run_loop.RunUntilIdle();
-  }
-
-  // Calls the release wake lock API and ensures that the request has reached
-  // the wake lock provider.
-  void ReleaseWakeLock() {
-    power_manager_provider_impl_->ReleaseWakeLock();
-    base::RunLoop run_loop;
-    run_loop.RunUntilIdle();
-  }
-
-  // Returns the number of active wake locks of type |type|.
-  int GetActiveWakeLocks(device::mojom::WakeLockType type) {
-    base::RunLoop run_loop;
-    int result_count = 0;
-    wake_lock_provider_.GetActiveWakeLocksForTests(
-        type,
-        base::BindOnce(
-            [](base::RunLoop* run_loop, int* result_count, int32_t count) {
-              *result_count = count;
-              run_loop->Quit();
-            },
-            &run_loop, &result_count));
-    run_loop.Run();
-    return result_count;
-  }
-
-  // Returns true iff adding a wake alarm via |AddWakeAlarm| returns a > 0
-  // result and the alarm expiration callback fires.
-  bool CheckAddWakeAlarmAndExpiration(uint64_t relative_time_ms,
-                                      uint64_t max_delay_ms) {
-    // Schedule wake alarm and check if valid id is returned and timer callback
-    // is fired.
-    bool result = false;
-    assistant_client::Callback0 wake_alarm_expiration_cb(
-        [&result]() { result = true; });
-    assistant_client::PowerManagerProvider::AlarmId id =
-        power_manager_provider_impl_->AddWakeAlarm(
-            relative_time_ms, max_delay_ms,
-            std::move(wake_alarm_expiration_cb));
-    task_environment_.FastForwardBy(base::Milliseconds(relative_time_ms));
-
-    if (id <= 0UL)
-      return false;
-    return result;
-  }
-
- private:
-  // Needs to be of type |MainThreadType::IO| to use |NativeTimer|.
-  base::test::TaskEnvironment task_environment_;
-
-  device::TestWakeLockProvider wake_lock_provider_;
-  FakePlatformDelegateImpl platform_delegate_{&wake_lock_provider_};
-
-  std::unique_ptr<PowerManagerProviderImpl> power_manager_provider_impl_;
-};
-
-TEST_F(AssistantPowerManagerProviderImplTest, CheckAcquireAndReleaseWakeLock) {
-  // Acquire wake lock and check wake lock count.
-  AcquireWakeLock();
-  EXPECT_EQ(1, GetActiveWakeLocks(
-                   device::mojom::WakeLockType::kPreventAppSuspension));
-  // Acquire another wake lock, this shouldn't change the overall count.
-  AcquireWakeLock();
-  EXPECT_EQ(1, GetActiveWakeLocks(
-                   device::mojom::WakeLockType::kPreventAppSuspension));
-  // Release wake lock, this shouldn't change the overall count.
-  ReleaseWakeLock();
-  EXPECT_EQ(1, GetActiveWakeLocks(
-                   device::mojom::WakeLockType::kPreventAppSuspension));
-  // Release wake lock, this should finally release the wake lock.
-  ReleaseWakeLock();
-  EXPECT_EQ(0, GetActiveWakeLocks(
-                   device::mojom::WakeLockType::kPreventAppSuspension));
-  // An unbalanced release call shouldn't do anything.
-  ReleaseWakeLock();
-  EXPECT_EQ(0, GetActiveWakeLocks(
-                   device::mojom::WakeLockType::kPreventAppSuspension));
-}
-
-TEST_F(AssistantPowerManagerProviderImplTest, CheckWakeAlarms) {
-  // Check consecutive wake alarms addition and expiration.
-  EXPECT_TRUE(
-      CheckAddWakeAlarmAndExpiration(kAlarmRelativeTimeMs, kAlarmMaxDelayMs));
-  EXPECT_TRUE(
-      CheckAddWakeAlarmAndExpiration(kAlarmRelativeTimeMs, kAlarmMaxDelayMs));
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/service_controller.cc b/chromeos/ash/services/libassistant/service_controller.cc
deleted file mode 100644
index 5bb5df62..0000000
--- a/chromeos/ash/services/libassistant/service_controller.cc
+++ /dev/null
@@ -1,329 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/service_controller.h"
-
-#include <memory>
-
-#include "base/check.h"
-#include "base/functional/bind.h"
-#include "chromeos/ash/services/assistant/public/cpp/features.h"
-#include "chromeos/ash/services/libassistant/chromium_api_delegate.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client.h"
-#include "chromeos/ash/services/libassistant/libassistant_factory.h"
-#include "chromeos/ash/services/libassistant/settings_controller.h"
-#include "chromeos/ash/services/libassistant/util.h"
-#include "chromeos/assistant/internal/internal_util.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "services/network/public/cpp/cross_thread_pending_shared_url_loader_factory.h"
-#include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-using mojom::ServiceState;
-
-// A macro which ensures we are running on the mojom thread.
-#define ENSURE_MOJOM_THREAD(method, ...)                                    \
-  if (!mojom_task_runner_->RunsTasksInCurrentSequence()) {                  \
-    mojom_task_runner_->PostTask(                                           \
-        FROM_HERE,                                                          \
-        base::BindOnce(method, weak_factory_.GetWeakPtr(), ##__VA_ARGS__)); \
-    return;                                                                 \
-  }
-
-BASE_FEATURE(kChromeOSAssistantDogfood,
-             "ChromeOSAssistantDogfood",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
-constexpr char kServersideDogfoodExperimentId[] = "20347368";
-constexpr char kServersideOpenAppExperimentId[] = "39651593";
-constexpr char kServersideResponseProcessingV2ExperimentId[] = "1793869";
-
-std::string ToLibassistantConfig(const mojom::BootupConfig& bootup_config) {
-  return CreateLibAssistantConfig(bootup_config.s3_server_uri_override,
-                                  bootup_config.device_id_override);
-}
-
-std::unique_ptr<network::PendingSharedURLLoaderFactory>
-CreatePendingURLLoaderFactory(
-    mojo::PendingRemote<network::mojom::URLLoaderFactory>
-        url_loader_factory_remote) {
-  // First create a wrapped factory that can accept the pending remote.
-  auto pending_url_loader_factory =
-      std::make_unique<network::WrapperPendingSharedURLLoaderFactory>(
-          std::move(url_loader_factory_remote));
-  auto wrapped_factory = network::SharedURLLoaderFactory::Create(
-      std::move(pending_url_loader_factory));
-
-  // Then move it into a cross thread factory, as the url loader factory will be
-  // used from internal Libassistant threads.
-  return std::make_unique<network::CrossThreadPendingSharedURLLoaderFactory>(
-      std::move(wrapped_factory));
-}
-
-void FillServerExperimentIds(std::vector<std::string>* server_experiment_ids) {
-  if (base::FeatureList::IsEnabled(kChromeOSAssistantDogfood)) {
-    server_experiment_ids->emplace_back(kServersideDogfoodExperimentId);
-  }
-
-  if (base::FeatureList::IsEnabled(assistant::features::kAssistantAppSupport))
-    server_experiment_ids->emplace_back(kServersideOpenAppExperimentId);
-
-  server_experiment_ids->emplace_back(
-      kServersideResponseProcessingV2ExperimentId);
-}
-
-void SetServerExperiments(AssistantClient* assistant_client) {
-  std::vector<std::string> server_experiment_ids;
-  FillServerExperimentIds(&server_experiment_ids);
-
-  if (server_experiment_ids.size() > 0) {
-    assistant_client->AddExperimentIds(server_experiment_ids);
-  }
-}
-
-}  // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-//  ServiceController
-////////////////////////////////////////////////////////////////////////////////
-
-ServiceController::ServiceController(LibassistantFactory* factory)
-    : libassistant_factory_(*factory) {
-  DCHECK(factory);
-}
-
-ServiceController::~ServiceController() {
-  // Ensure all our observers know this service is no longer running.
-  // This will be a noop if we're already stopped.
-  Stop();
-}
-
-void ServiceController::Bind(
-    mojo::PendingReceiver<mojom::ServiceController> receiver,
-    mojom::SettingsController* settings_controller) {
-  DCHECK(!receiver_.is_bound());
-  receiver_.Bind(std::move(receiver));
-  settings_controller_ = settings_controller;
-}
-
-void ServiceController::Initialize(
-    mojom::BootupConfigPtr config,
-    mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory) {
-  if (assistant_client_) {
-    LOG(ERROR) << "Initialize() should only be called once.";
-    return;
-  }
-
-  auto assistant_manager = libassistant_factory_->CreateAssistantManager(
-      ToLibassistantConfig(*config));
-  assistant_client_ = AssistantClient::Create(std::move(assistant_manager));
-
-  DCHECK(settings_controller_);
-  settings_controller_->SetAuthenticationTokens(
-      std::move(config->authentication_tokens));
-  settings_controller_->SetLocale(config->locale);
-  settings_controller_->SetHotwordEnabled(config->hotword_enabled);
-  settings_controller_->SetSpokenFeedbackEnabled(
-      config->spoken_feedback_enabled);
-  settings_controller_->SetDarkModeEnabled(config->dark_mode_enabled);
-
-  CreateAndRegisterChromiumApiDelegate(std::move(url_loader_factory));
-  for (auto& observer : assistant_client_observers_) {
-    observer.OnAssistantClientCreated(assistant_client_.get());
-  }
-}
-
-void ServiceController::Start() {
-  if (state_ != ServiceState::kStopped)
-    return;
-
-  DCHECK(IsInitialized()) << "Initialize() must be called before Start()";
-  DVLOG(1) << "Starting Libassistant service";
-
-  // |this| will outlive |assistant_client_|.
-  assistant_client_->StartServices(/*services_status_observer=*/this);
-}
-
-void ServiceController::Stop() {
-  if (state_ == ServiceState::kStopped)
-    return;
-
-  DVLOG(1) << "Stopping Libassistant service";
-
-  for (auto& observer : assistant_client_observers_) {
-    observer.OnDestroyingAssistantClient(assistant_client_.get());
-  }
-
-  assistant_client_ = nullptr;
-  chromium_api_delegate_ = nullptr;
-
-  DVLOG(1) << "Stopped Libassistant service";
-  SetStateAndInformObservers(ServiceState::kStopped);
-
-  for (auto& observer : assistant_client_observers_)
-    observer.OnAssistantClientDestroyed();
-}
-
-void ServiceController::ResetAllDataAndStop() {
-  if (assistant_client_) {
-    DVLOG(1) << "Resetting all Libassistant data";
-    assistant_client_->ResetAllDataAndShutdown();
-  }
-  Stop();
-}
-
-void ServiceController::AddAndFireStateObserver(
-    mojo::PendingRemote<mojom::StateObserver> pending_observer) {
-  mojo::Remote<mojom::StateObserver> observer(std::move(pending_observer));
-
-  observer->OnStateChanged(state_);
-
-  state_observers_.Add(std::move(observer));
-}
-
-void ServiceController::OnServicesStatusChanged(ServicesStatus status) {
-  switch (status) {
-    case ServicesStatus::ONLINE_ALL_SERVICES_AVAILABLE:
-      OnAllServicesReady();
-      break;
-    case ServicesStatus::ONLINE_BOOTING_UP:
-      // Configing internal options or other essential services that are
-      // supported during bootup stage should happen here.
-      OnServicesBootingUp();
-      break;
-    case ServicesStatus::OFFLINE:
-      // No action needed.
-      break;
-  }
-}
-
-void ServiceController::AddAndFireAssistantClientObserver(
-    AssistantClientObserver* observer) {
-  DCHECK(observer);
-
-  assistant_client_observers_.AddObserver(observer);
-
-  if (IsInitialized()) {
-    observer->OnAssistantClientCreated(assistant_client_.get());
-  }
-  // Note we do send the |OnAssistantClientStarted| event even if the service
-  // is currently running, to ensure that an observer that only observes
-  // |OnAssistantClientStarted| will not miss a currently running instance
-  // when it is being added.
-  if (IsStarted()) {
-    observer->OnAssistantClientStarted(assistant_client_.get());
-  }
-  if (IsRunning()) {
-    observer->OnAssistantClientRunning(assistant_client_.get());
-  }
-}
-
-void ServiceController::RemoveAssistantClientObserver(
-    AssistantClientObserver* observer) {
-  assistant_client_observers_.RemoveObserver(observer);
-}
-
-void ServiceController::RemoveAllAssistantClientObservers() {
-  assistant_client_observers_.Clear();
-}
-
-bool ServiceController::IsStarted() const {
-  switch (state_) {
-    case ServiceState::kStopped:
-    case ServiceState::kDisconnected:
-      return false;
-    case ServiceState::kStarted:
-    case ServiceState::kRunning:
-      return true;
-  }
-}
-
-bool ServiceController::IsInitialized() const {
-  return assistant_client_ != nullptr;
-}
-
-bool ServiceController::IsRunning() const {
-  switch (state_) {
-    case ServiceState::kStopped:
-    case ServiceState::kStarted:
-    case ServiceState::kDisconnected:
-      return false;
-    case ServiceState::kRunning:
-      return true;
-  }
-}
-
-AssistantClient* ServiceController::assistant_client() {
-  return assistant_client_.get();
-}
-
-void ServiceController::OnAllServicesReady() {
-  DVLOG(1) << "Libassistant services are ready.";
-
-  SetServerExperiments(assistant_client_.get());
-
-  // Notify observers on Libassistant services ready.
-  SetStateAndInformObservers(mojom::ServiceState::kRunning);
-
-  for (auto& observer : assistant_client_observers_)
-    observer.OnAssistantClientRunning(assistant_client_.get());
-}
-
-void ServiceController::OnServicesBootingUp() {
-  DVLOG(1) << "Started Libassistant service";
-
-  // We set one precondition of BootupState to reach `INITIALIZING_INTERNAL`
-  // is to wait for the gRPC HttpConnection be ready. Only after the BootupState
-  // meets the state, can AssistantManager start.
-  assistant_client_->StartGrpcHttpConnectionClient(
-      chromium_api_delegate_->GetHttpConnectionFactory());
-
-  // The Libassistant BootupState goes to `RUNNING` right after
-  // `SETTING_UP_ESSENTIAL_SERVICES` if AssistantManager::Start() is called
-  // right after the AssistantManager is created. And Libassistant emits signals
-  // of `ESSENTIAL_SERVICES_AVAILABLE` and `ALL_SERVICES_AVAILABLE` almost the
-  // same time. However, unary gRPC does not guarantee order. ChromeOS could
-  // receive these signals out of order.
-  // We call AssistantManager::Start() here, ServicesBootingUp(), which is
-  // triggered by `ESSENTIAL_SERVICES_AVAILABLE`. After the AssistantManager is
-  // started, it will trigger `ALL_SERVICES_AVAILABLE`. Therefore these two
-  // signals are generated in order.
-  assistant_client_->assistant_manager()->Start();
-
-  // Notify observer on Libassistant services started.
-  SetStateAndInformObservers(ServiceState::kStarted);
-
-  for (auto& observer : assistant_client_observers_)
-    observer.OnAssistantClientStarted(assistant_client_.get());
-}
-
-void ServiceController::SetStateAndInformObservers(
-    mojom::ServiceState new_state) {
-  DCHECK_NE(state_, new_state);
-
-  state_ = new_state;
-
-  for (auto& observer : state_observers_)
-    observer->OnStateChanged(state_);
-}
-
-void ServiceController::CreateAndRegisterChromiumApiDelegate(
-    mojo::PendingRemote<network::mojom::URLLoaderFactory>
-        url_loader_factory_remote) {
-  CreateChromiumApiDelegate(std::move(url_loader_factory_remote));
-}
-
-void ServiceController::CreateChromiumApiDelegate(
-    mojo::PendingRemote<network::mojom::URLLoaderFactory>
-        url_loader_factory_remote) {
-  DCHECK(!chromium_api_delegate_);
-
-  chromium_api_delegate_ = std::make_unique<ChromiumApiDelegate>(
-      CreatePendingURLLoaderFactory(std::move(url_loader_factory_remote)));
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/service_controller.h b/chromeos/ash/services/libassistant/service_controller.h
deleted file mode 100644
index 8d93d11..0000000
--- a/chromeos/ash/services/libassistant/service_controller.h
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_SERVICE_CONTROLLER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_SERVICE_CONTROLLER_H_
-
-#include "base/component_export.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/raw_ref.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "base/scoped_observation_traits.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client_observer.h"
-#include "chromeos/ash/services/libassistant/grpc/services_status_observer.h"
-#include "chromeos/ash/services/libassistant/public/mojom/service.mojom.h"
-#include "chromeos/ash/services/libassistant/public/mojom/service_controller.mojom.h"
-#include "chromeos/ash/services/libassistant/public/mojom/settings_controller.mojom-forward.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote_set.h"
-
-namespace ash::libassistant {
-
-class ChromiumApiDelegate;
-class LibassistantFactory;
-
-// Component managing the lifecycle of Libassistant,
-// exposing methods to start/stop and configure Libassistant.
-class COMPONENT_EXPORT(LIBASSISTANT_SERVICE) ServiceController
-    : public mojom::ServiceController,
-      public ServicesStatusObserver {
- public:
-  explicit ServiceController(LibassistantFactory* factory);
-  ServiceController(ServiceController&) = delete;
-  ServiceController& operator=(ServiceController&) = delete;
-  ~ServiceController() override;
-
-  void Bind(mojo::PendingReceiver<mojom::ServiceController> receiver,
-            mojom::SettingsController* settings_controller);
-
-  // mojom::ServiceController implementation:
-  void Initialize(mojom::BootupConfigPtr libassistant_config,
-                  mojo::PendingRemote<network::mojom::URLLoaderFactory>
-                      url_loader_factory) override;
-  void Start() override;
-  void Stop() override;
-  void ResetAllDataAndStop() override;
-  void AddAndFireStateObserver(
-      mojo::PendingRemote<mojom::StateObserver> observer) override;
-
-  // ServicesStatusObserver implementation:
-  void OnServicesStatusChanged(ServicesStatus status) override;
-
-  void AddAndFireAssistantClientObserver(AssistantClientObserver* observer);
-  void RemoveAssistantClientObserver(AssistantClientObserver* observer);
-  void RemoveAllAssistantClientObservers();
-
-  bool IsInitialized() const;
-  // Note this is true even when the service is running (as it is still started
-  // at that point).
-  bool IsStarted() const;
-  bool IsRunning() const;
-
-  // Will return nullptr if the service is stopped.
-  AssistantClient* assistant_client();
-
- private:
-  // Will be invoked when all Libassistant services are ready to query.
-  void OnAllServicesReady();
-  // Will be invoked when Libassistant services are started.
-  void OnServicesBootingUp();
-
-  void SetStateAndInformObservers(mojom::ServiceState new_state);
-
-  void CreateAndRegisterChromiumApiDelegate(
-      mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory);
-  void CreateChromiumApiDelegate(
-      mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory);
-
-  mojom::ServiceState state_ = mojom::ServiceState::kStopped;
-
-  // Called during |Initialize| to apply boot configuration.
-  raw_ptr<mojom::SettingsController> settings_controller_ = nullptr;
-
-  const raw_ref<LibassistantFactory> libassistant_factory_;
-
-  std::unique_ptr<AssistantClient> assistant_client_;
-  std::unique_ptr<ChromiumApiDelegate> chromium_api_delegate_;
-
-  mojo::Receiver<mojom::ServiceController> receiver_{this};
-  mojo::RemoteSet<mojom::StateObserver> state_observers_;
-  base::ObserverList<AssistantClientObserver> assistant_client_observers_;
-
-  base::WeakPtrFactory<ServiceController> weak_factory_{this};
-};
-
-}  // namespace ash::libassistant
-
-namespace base {
-
-template <>
-struct ScopedObservationTraits<ash::libassistant::ServiceController,
-                               ash::libassistant::AssistantClientObserver> {
-  static void AddObserver(
-      ash::libassistant::ServiceController* source,
-      ash::libassistant::AssistantClientObserver* observer) {
-    source->AddAndFireAssistantClientObserver(observer);
-  }
-  static void RemoveObserver(
-      ash::libassistant::ServiceController* source,
-      ash::libassistant::AssistantClientObserver* observer) {
-    source->RemoveAssistantClientObserver(observer);
-  }
-};
-
-}  // namespace base
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_SERVICE_CONTROLLER_H_
diff --git a/chromeos/ash/services/libassistant/service_controller_unittest.cc b/chromeos/ash/services/libassistant/service_controller_unittest.cc
deleted file mode 100644
index 18ba6e9..0000000
--- a/chromeos/ash/services/libassistant/service_controller_unittest.cc
+++ /dev/null
@@ -1,622 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/service_controller.h"
-
-#include <memory>
-
-#include "base/base_paths.h"
-#include "base/json/json_reader.h"
-#include "base/run_loop.h"
-#include "base/test/gtest_util.h"
-#include "base/test/scoped_path_override.h"
-#include "base/test/task_environment.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client_observer.h"
-#include "chromeos/ash/services/libassistant/public/mojom/service_controller.mojom.h"
-#include "chromeos/ash/services/libassistant/public/mojom/settings_controller.mojom.h"
-#include "chromeos/ash/services/libassistant/settings_controller.h"
-#include "chromeos/ash/services/libassistant/test_support/fake_libassistant_factory.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/test_support/fake_assistant_manager.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "services/network/test/test_url_loader_factory.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-using mojom::ServiceState;
-using ::testing::StrictMock;
-
-#define EXPECT_NO_CALLS(args...) EXPECT_CALL(args).Times(0)
-
-// Tests if the JSON string contains the given path with the given value.
-#define EXPECT_HAS_PATH_WITH_VALUE(config_string, path, expected_value)        \
-  ({                                                                           \
-    std::optional<base::Value> config = base::JSONReader::Read(config_string); \
-    ASSERT_TRUE(config.has_value());                                           \
-    ASSERT_TRUE(config->is_dict());                                            \
-    const base::Value* actual = config->GetDict().FindByDottedPath(path);      \
-    base::Value expected = base::Value(expected_value);                        \
-    ASSERT_NE(actual, nullptr)                                                 \
-        << "Path '" << path << "' not found in config: " << config_string;     \
-    EXPECT_EQ(*actual, expected);                                              \
-  })
-
-std::vector<mojom::AuthenticationTokenPtr> ToVector(
-    mojom::AuthenticationTokenPtr token) {
-  std::vector<mojom::AuthenticationTokenPtr> result;
-  result.push_back(std::move(token));
-  return result;
-}
-
-class StateObserverMock : public mojom::StateObserver {
- public:
-  StateObserverMock() : receiver_(this) {}
-
-  MOCK_METHOD(void, OnStateChanged, (ServiceState));
-
-  mojo::PendingRemote<mojom::StateObserver> BindAndPassReceiver() {
-    return receiver_.BindNewPipeAndPassRemote();
-  }
-
- private:
-  mojo::Receiver<mojom::StateObserver> receiver_;
-};
-
-class AssistantClientObserverMock : public AssistantClientObserver {
- public:
-  AssistantClientObserverMock() = default;
-  AssistantClientObserverMock(const AssistantClientObserverMock&) = delete;
-  AssistantClientObserverMock& operator=(const AssistantClientObserverMock&) =
-      delete;
-  ~AssistantClientObserverMock() override = default;
-
-  // AssistantClientObserver implementation:
-  MOCK_METHOD(void,
-              OnAssistantClientCreated,
-              (AssistantClient * assistant_client));
-  MOCK_METHOD(void,
-              OnAssistantClientStarted,
-              (AssistantClient * assistant_client));
-  MOCK_METHOD(void,
-              OnAssistantClientRunning,
-              (AssistantClient * assistant_client));
-  MOCK_METHOD(void,
-              OnDestroyingAssistantClient,
-              (AssistantClient * assistant_client));
-  MOCK_METHOD(void, OnAssistantClientDestroyed, ());
-};
-
-class SettingsControllerMock : public mojom::SettingsController {
- public:
-  SettingsControllerMock() = default;
-  SettingsControllerMock(const SettingsControllerMock&) = delete;
-  SettingsControllerMock& operator=(const SettingsControllerMock&) = delete;
-  ~SettingsControllerMock() override = default;
-
-  // mojom::SettingsController implementation:
-  MOCK_METHOD(void,
-              SetAuthenticationTokens,
-              (std::vector<mojom::AuthenticationTokenPtr> tokens));
-  MOCK_METHOD(void, SetListeningEnabled, (bool value));
-  MOCK_METHOD(void, SetLocale, (const std::string& value));
-  MOCK_METHOD(void, SetSpokenFeedbackEnabled, (bool value));
-  MOCK_METHOD(void, SetDarkModeEnabled, (bool value));
-  MOCK_METHOD(void, SetHotwordEnabled, (bool value));
-  MOCK_METHOD(void,
-              GetSettings,
-              (const std::string& selector,
-               bool include_header,
-               GetSettingsCallback callback));
-  MOCK_METHOD(void,
-              UpdateSettings,
-              (const std::string& settings, UpdateSettingsCallback callback));
-};
-
-class MediaManagerMock : public assistant_client::MediaManager {
- public:
-  MediaManagerMock() = default;
-  MediaManagerMock(const MediaManagerMock&) = delete;
-  MediaManagerMock& operator=(const MediaManagerMock&) = delete;
-  ~MediaManagerMock() override = default;
-
-  // assistant_client::MediaManager:
-  MOCK_METHOD(void, AddListener, (Listener * listener));
-  MOCK_METHOD(void, Next, ());
-  MOCK_METHOD(void, Previous, ());
-  MOCK_METHOD(void, Resume, ());
-  MOCK_METHOD(void, Pause, ());
-  MOCK_METHOD(void, PlayPause, ());
-  MOCK_METHOD(void, StopAndClearPlaylist, ());
-  MOCK_METHOD(void,
-              SetExternalPlaybackState,
-              (const assistant_client::MediaStatus& new_status));
-};
-
-class AssistantServiceControllerTest : public testing::Test {
- public:
-  AssistantServiceControllerTest()
-      : service_controller_(
-            std::make_unique<ServiceController>(&libassistant_factory_)) {
-    service_controller_->Bind(client_.BindNewPipeAndPassReceiver(),
-                              &settings_controller_);
-  }
-
-  mojo::Remote<mojom::ServiceController>& client() { return client_; }
-  ServiceController& service_controller() {
-    DCHECK(service_controller_);
-    return *service_controller_;
-  }
-
-  void RunUntilIdle() { base::RunLoop().RunUntilIdle(); }
-
-  // Add the state observer. Will expect the call that follows immediately after
-  // adding the observer.
-  void AddStateObserver(StateObserverMock* observer) {
-    EXPECT_CALL(*observer, OnStateChanged);
-    service_controller().AddAndFireStateObserver(
-        observer->BindAndPassReceiver());
-    RunUntilIdle();
-  }
-
-  void AddAndFireAssistantClientObserver(AssistantClientObserver* observer) {
-    service_controller().AddAndFireAssistantClientObserver(observer);
-  }
-
-  void RemoveAssistantClientObserver(AssistantClientObserver* observer) {
-    service_controller().RemoveAssistantClientObserver(observer);
-  }
-
-  void AddAndFireStateObserver(StateObserverMock* observer) {
-    service_controller().AddAndFireStateObserver(
-        observer->BindAndPassReceiver());
-    RunUntilIdle();
-  }
-
-  void Initialize(mojom::BootupConfigPtr config = mojom::BootupConfig::New()) {
-    service_controller().Initialize(std::move(config), BindURLLoaderFactory());
-  }
-
-  void Start() {
-    service_controller().Start();
-    libassistant_factory_.assistant_manager().SetMediaManager(&media_manager_);
-
-    // Similuate gRPC heartbeat calls.
-    service_controller().OnServicesStatusChanged(
-        ServicesStatus::ONLINE_BOOTING_UP);
-    RunUntilIdle();
-  }
-
-  void SendOnStartFinished() {
-    // Similuate gRPC heartbeat calls.
-    service_controller().OnServicesStatusChanged(
-        ServicesStatus::ONLINE_ALL_SERVICES_AVAILABLE);
-    RunUntilIdle();
-  }
-
-  void Stop() {
-    service_controller().Stop();
-    RunUntilIdle();
-  }
-
-  void DestroyServiceController() { service_controller_.reset(); }
-
-  std::string libassistant_config() {
-    return libassistant_factory_.libassistant_config();
-  }
-
-  SettingsControllerMock& settings_controller_mock() {
-    return settings_controller_;
-  }
-
- private:
-  mojo::PendingRemote<network::mojom::URLLoaderFactory> BindURLLoaderFactory() {
-    mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_remote;
-    url_loader_factory_.Clone(pending_remote.InitWithNewPipeAndPassReceiver());
-    return pending_remote;
-  }
-
-  base::test::SingleThreadTaskEnvironment environment_;
-  base::ScopedPathOverride home_override{base::DIR_HOME};
-
-  network::TestURLLoaderFactory url_loader_factory_;
-
-  FakeLibassistantFactory libassistant_factory_;
-  testing::NiceMock<SettingsControllerMock> settings_controller_;
-  mojo::Remote<mojom::ServiceController> client_;
-  std::unique_ptr<ServiceController> service_controller_;
-  MediaManagerMock media_manager_;
-};
-
-}  // namespace
-
-namespace mojom {
-
-void PrintTo(const ServiceState state, std::ostream* stream) {
-  switch (state) {
-    case ServiceState::kRunning:
-      *stream << "kRunning";
-      return;
-    case ServiceState::kStarted:
-      *stream << "kStarted";
-      return;
-    case ServiceState::kStopped:
-      *stream << "kStopped";
-      return;
-    case ServiceState::kDisconnected:
-      *stream << "kDisconnected";
-      return;
-  }
-  *stream << "INVALID ServiceState (" << static_cast<int>(state) << ")";
-}
-
-}  // namespace mojom
-
-TEST_F(AssistantServiceControllerTest, StateShouldStartAsStopped) {
-  Initialize();
-  StateObserverMock observer;
-
-  EXPECT_CALL(observer, OnStateChanged(ServiceState::kStopped));
-
-  AddAndFireStateObserver(&observer);
-}
-
-TEST_F(AssistantServiceControllerTest,
-       StateShouldChangeToStartedAfterCallingStart) {
-  Initialize();
-  StateObserverMock observer;
-  AddStateObserver(&observer);
-
-  EXPECT_CALL(observer, OnStateChanged(ServiceState::kStarted));
-
-  Start();
-}
-
-TEST_F(AssistantServiceControllerTest,
-       StateShouldChangeToStoppedAfterCallingStop) {
-  Initialize();
-  Start();
-
-  StateObserverMock observer;
-  AddStateObserver(&observer);
-
-  EXPECT_CALL(observer, OnStateChanged(ServiceState::kStopped));
-
-  Stop();
-}
-
-TEST_F(AssistantServiceControllerTest,
-       StateShouldChangeToRunningAfterLibassistantSignalsItsDone) {
-  Initialize();
-  Start();
-
-  StateObserverMock observer;
-  AddStateObserver(&observer);
-
-  EXPECT_CALL(observer, OnStateChanged(ServiceState::kRunning));
-
-  SendOnStartFinished();
-}
-
-TEST_F(AssistantServiceControllerTest,
-       ShouldSendCurrentStateWhenAddingObserver) {
-  Initialize();
-
-  {
-    StateObserverMock observer;
-
-    EXPECT_CALL(observer, OnStateChanged(ServiceState::kStopped));
-    AddAndFireStateObserver(&observer);
-  }
-
-  Start();
-
-  {
-    StateObserverMock observer;
-
-    EXPECT_CALL(observer, OnStateChanged(ServiceState::kStarted));
-    AddAndFireStateObserver(&observer);
-  }
-
-  Stop();
-
-  {
-    StateObserverMock observer;
-
-    EXPECT_CALL(observer, OnStateChanged(ServiceState::kStopped));
-    AddAndFireStateObserver(&observer);
-  }
-}
-
-TEST_F(AssistantServiceControllerTest,
-       ShouldCreateAssistantManagerWhenCallingInitialize) {
-  EXPECT_EQ(nullptr, service_controller().assistant_client());
-
-  Initialize();
-
-  EXPECT_NE(nullptr,
-            service_controller().assistant_client()->assistant_manager());
-}
-
-TEST_F(AssistantServiceControllerTest, CallingStopTwiceShouldBeANoop) {
-  Initialize();
-  Stop();
-
-  StateObserverMock observer;
-  AddStateObserver(&observer);
-
-  EXPECT_NO_CALLS(observer, OnStateChanged);
-
-  Stop();
-}
-
-TEST_F(AssistantServiceControllerTest, ShouldAllowStartAfterStop) {
-  Initialize();
-  Start();
-  Stop();
-
-  // The second Initialize() call should create the AssistantManager.
-
-  Initialize();
-  EXPECT_NE(nullptr,
-            service_controller().assistant_client()->assistant_manager());
-
-  // The second Start() call should send out a state update.
-
-  StateObserverMock observer;
-  AddStateObserver(&observer);
-
-  EXPECT_CALL(observer, OnStateChanged(ServiceState::kStarted));
-
-  Start();
-
-  EXPECT_NE(nullptr,
-            service_controller().assistant_client()->assistant_manager());
-}
-
-TEST_F(AssistantServiceControllerTest,
-       ShouldDestroyAssistantManagerWhenCallingStop) {
-  Initialize();
-  Start();
-  EXPECT_NE(nullptr,
-            service_controller().assistant_client()->assistant_manager());
-
-  Stop();
-
-  EXPECT_EQ(nullptr, service_controller().assistant_client());
-}
-
-TEST_F(AssistantServiceControllerTest,
-       StateShouldChangeToStoppedWhenBeingDestroyed) {
-  Initialize();
-  Start();
-
-  StateObserverMock observer;
-  AddStateObserver(&observer);
-
-  EXPECT_CALL(observer, OnStateChanged(ServiceState::kStopped));
-
-  DestroyServiceController();
-  RunUntilIdle();
-}
-
-TEST_F(AssistantServiceControllerTest,
-       ShouldPassS3ServerUriOverrideToMojomService) {
-  auto bootup_config = mojom::BootupConfig::New();
-  bootup_config->s3_server_uri_override = "the-s3-server-uri-override";
-  Initialize(std::move(bootup_config));
-
-  EXPECT_HAS_PATH_WITH_VALUE(libassistant_config(),
-                             "testing.s3_grpc_server_uri",
-                             "the-s3-server-uri-override");
-}
-
-TEST_F(AssistantServiceControllerTest,
-       ShouldCallOnAssistantClientCreatedWhenCallingInitialize) {
-  StrictMock<AssistantClientObserverMock> observer;
-  AddAndFireAssistantClientObserver(&observer);
-
-  EXPECT_CALL(observer, OnAssistantClientCreated)
-      .WillOnce([&controller =
-                     service_controller()](AssistantClient* assistant_client) {
-        EXPECT_EQ(assistant_client, controller.assistant_client());
-      });
-
-  Initialize();
-
-  RemoveAssistantClientObserver(&observer);
-}
-
-TEST_F(AssistantServiceControllerTest,
-       ShouldCallOnAssistantClientCreatedWhenAddingObserver) {
-  Initialize();
-
-  StrictMock<AssistantClientObserverMock> observer;
-
-  EXPECT_CALL(observer, OnAssistantClientCreated)
-      .WillOnce([&controller =
-                     service_controller()](AssistantClient* assistant_client) {
-        EXPECT_EQ(assistant_client, controller.assistant_client());
-      });
-
-  AddAndFireAssistantClientObserver(&observer);
-
-  RemoveAssistantClientObserver(&observer);
-}
-
-TEST_F(AssistantServiceControllerTest,
-       ShouldCallOnAssistantClientStartedWhenCallingStart) {
-  StrictMock<AssistantClientObserverMock> observer;
-  AddAndFireAssistantClientObserver(&observer);
-
-  EXPECT_CALL(observer, OnAssistantClientCreated);
-  Initialize();
-
-  EXPECT_CALL(observer, OnAssistantClientStarted)
-      .WillOnce([&controller =
-                     service_controller()](AssistantClient* assistant_client) {
-        EXPECT_EQ(assistant_client, controller.assistant_client());
-      });
-
-  Start();
-
-  RemoveAssistantClientObserver(&observer);
-}
-
-TEST_F(AssistantServiceControllerTest,
-       ShouldCallOnAssistantManagerInitializedAndCreatedWhenAddingObserver) {
-  Initialize();
-  Start();
-
-  StrictMock<AssistantClientObserverMock> observer;
-
-  EXPECT_CALL(observer, OnAssistantClientCreated)
-      .WillOnce([&controller =
-                     service_controller()](AssistantClient* assistant_client) {
-        EXPECT_EQ(assistant_client, controller.assistant_client());
-      });
-
-  EXPECT_CALL(observer, OnAssistantClientStarted)
-      .WillOnce([&controller =
-                     service_controller()](AssistantClient* assistant_client) {
-        EXPECT_EQ(assistant_client, controller.assistant_client());
-      });
-
-  AddAndFireAssistantClientObserver(&observer);
-
-  RemoveAssistantClientObserver(&observer);
-}
-
-TEST_F(AssistantServiceControllerTest,
-       ShouldCallOnAssistantClientRunningWhenCallingOnStartFinished) {
-  StrictMock<AssistantClientObserverMock> observer;
-  AddAndFireAssistantClientObserver(&observer);
-
-  EXPECT_CALL(observer, OnAssistantClientCreated);
-  Initialize();
-  EXPECT_CALL(observer, OnAssistantClientStarted);
-  Start();
-
-  EXPECT_CALL(observer, OnAssistantClientRunning)
-      .WillOnce([&controller =
-                     service_controller()](AssistantClient* assistant_client) {
-        EXPECT_EQ(assistant_client, controller.assistant_client());
-      });
-
-  SendOnStartFinished();
-
-  RemoveAssistantClientObserver(&observer);
-}
-
-TEST_F(AssistantServiceControllerTest,
-       ShouldCallOnAssistantClientRunningWhenAddingObserver) {
-  Initialize();
-  Start();
-  SendOnStartFinished();
-
-  StrictMock<AssistantClientObserverMock> observer;
-
-  EXPECT_CALL(observer, OnAssistantClientCreated)
-      .WillOnce([&controller =
-                     service_controller()](AssistantClient* assistant_client) {
-        EXPECT_EQ(assistant_client, controller.assistant_client());
-      });
-
-  EXPECT_CALL(observer, OnAssistantClientStarted)
-      .WillOnce([&controller =
-                     service_controller()](AssistantClient* assistant_client) {
-        EXPECT_EQ(assistant_client, controller.assistant_client());
-      });
-
-  EXPECT_CALL(observer, OnAssistantClientRunning)
-      .WillOnce([&controller =
-                     service_controller()](AssistantClient* assistant_client) {
-        EXPECT_EQ(assistant_client, controller.assistant_client());
-      });
-
-  AddAndFireAssistantClientObserver(&observer);
-
-  RemoveAssistantClientObserver(&observer);
-}
-TEST_F(AssistantServiceControllerTest,
-       ShouldCallOnDestroyingAssistantClientWhenCallingStop) {
-  StrictMock<AssistantClientObserverMock> observer;
-  AddAndFireAssistantClientObserver(&observer);
-
-  EXPECT_CALL(observer, OnAssistantClientCreated);
-  EXPECT_CALL(observer, OnAssistantClientStarted);
-  Initialize();
-  Start();
-
-  EXPECT_CALL(observer, OnDestroyingAssistantClient)
-      .WillOnce([&controller =
-                     service_controller()](AssistantClient* assistant_client) {
-        EXPECT_EQ(assistant_client, controller.assistant_client());
-      });
-  EXPECT_CALL(observer, OnAssistantClientDestroyed);
-
-  Stop();
-
-  RemoveAssistantClientObserver(&observer);
-}
-
-TEST_F(AssistantServiceControllerTest,
-       ShouldNotCallAssistantClientObserverWhenItHasBeenRemoved) {
-  StrictMock<AssistantClientObserverMock> observer;
-  AddAndFireAssistantClientObserver(&observer);
-  RemoveAssistantClientObserver(&observer);
-
-  EXPECT_NO_CALLS(observer, OnAssistantClientCreated);
-  EXPECT_NO_CALLS(observer, OnAssistantClientStarted);
-  EXPECT_NO_CALLS(observer, OnDestroyingAssistantClient);
-  EXPECT_NO_CALLS(observer, OnAssistantClientDestroyed);
-
-  Initialize();
-  Start();
-  Stop();
-
-  RemoveAssistantClientObserver(&observer);
-}
-
-TEST_F(AssistantServiceControllerTest,
-       ShouldCallOnDestroyingAssistantClientWhenBeingDestroyed) {
-  Initialize();
-  Start();
-
-  StrictMock<AssistantClientObserverMock> observer;
-  EXPECT_CALL(observer, OnAssistantClientCreated);
-  EXPECT_CALL(observer, OnAssistantClientStarted);
-  AddAndFireAssistantClientObserver(&observer);
-
-  EXPECT_CALL(observer, OnDestroyingAssistantClient);
-  EXPECT_CALL(observer, OnAssistantClientDestroyed);
-  DestroyServiceController();
-}
-
-TEST_F(AssistantServiceControllerTest,
-       ShouldPassBootupConfigToSettingsController) {
-  const bool hotword_enabled = true;
-  const bool spoken_feedback_enabled = false;
-
-  EXPECT_CALL(settings_controller_mock(), SetLocale("locale"));
-  EXPECT_CALL(settings_controller_mock(), SetHotwordEnabled(hotword_enabled));
-  EXPECT_CALL(settings_controller_mock(),
-              SetSpokenFeedbackEnabled(spoken_feedback_enabled));
-  EXPECT_CALL(settings_controller_mock(), SetAuthenticationTokens);
-
-  auto bootup_config = mojom::BootupConfig::New();
-  bootup_config->locale = "locale";
-  bootup_config->hotword_enabled = hotword_enabled;
-  bootup_config->spoken_feedback_enabled = spoken_feedback_enabled;
-  bootup_config->authentication_tokens =
-      ToVector(mojom::AuthenticationToken::New("user", "token"));
-
-  Initialize(std::move(bootup_config));
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/settings_controller.cc b/chromeos/ash/services/libassistant/settings_controller.cc
deleted file mode 100644
index 5fd6be8..0000000
--- a/chromeos/ash/services/libassistant/settings_controller.cc
+++ /dev/null
@@ -1,385 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/settings_controller.h"
-
-#include <algorithm>
-#include <memory>
-
-#include "base/functional/callback_helpers.h"
-#include "base/memory/raw_ref.h"
-#include "base/sequence_checker.h"
-#include "chromeos/ash/services/assistant/public/proto/assistant_device_settings_ui.pb.h"
-#include "chromeos/ash/services/assistant/public/proto/settings_ui.pb.h"
-#include "chromeos/ash/services/libassistant/callback_utils.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client.h"
-#include "chromeos/ash/services/libassistant/grpc/utils/settings_utils.h"
-#include "chromeos/assistant/internal/internal_util.h"
-#include "chromeos/assistant/internal/proto/assistant/display_connection.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/settings_ui.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/config_settings_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/display_interface.pb.h"
-#include "third_party/icu/source/common/unicode/locid.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-// Each authentication token exists of a [gaia_id, access_token] tuple.
-using AuthTokens = std::vector<std::pair<std::string, std::string>>;
-
-AuthTokens ToAuthTokens(
-    const std::vector<mojom::AuthenticationTokenPtr>& mojo_tokens) {
-  AuthTokens result;
-
-  for (const auto& token : mojo_tokens)
-    result.emplace_back(token->gaia_id, token->access_token);
-
-  return result;
-}
-
-const char* LocaleOrDefault(const std::string& locale) {
-  if (locale.empty()) {
-    // When |locale| is not provided we fall back to approximate locale.
-    return icu::Locale::getDefault().getName();
-  } else {
-    return locale.c_str();
-  }
-}
-
-}  // namespace
-
-// Will be created as Libassistant is started, and will update the device
-// settings when |UpdateSettings| is called.
-// The device settings can not be updated earlier, as they require the
-// device-id that is only assigned by Libassistant when it starts.
-class SettingsController::DeviceSettingsUpdater
-    : public AssistantClientObserver {
- public:
-  DeviceSettingsUpdater(SettingsController* parent,
-                        AssistantClient* assistant_client)
-      : parent_(*parent), assistant_client_(*assistant_client) {}
-  DeviceSettingsUpdater(const DeviceSettingsUpdater&) = delete;
-  DeviceSettingsUpdater& operator=(const DeviceSettingsUpdater&) = delete;
-  ~DeviceSettingsUpdater() override = default;
-
-  void UpdateSettings(const std::string& locale, bool hotword_enabled) {
-    const std::string device_id = assistant_client_->GetDeviceId();
-    if (device_id.empty())
-      return;
-
-    // Update device id and device type.
-    assistant::SettingsUiUpdate update;
-    assistant::AssistantDeviceSettingsUpdate* device_settings_update =
-        update.mutable_assistant_device_settings_update()
-            ->add_assistant_device_settings_update();
-    device_settings_update->set_device_id(device_id);
-    device_settings_update->set_assistant_device_type(
-        assistant::AssistantDevice::CROS);
-
-    if (hotword_enabled) {
-      device_settings_update->mutable_device_settings()->set_speaker_id_enabled(
-          true);
-    }
-
-    VLOG(1) << "Assistant: Update device locale: " << locale;
-    device_settings_update->mutable_device_settings()->set_locale(locale);
-
-    // Enable personal readout to grant permission for personal features.
-    device_settings_update->mutable_device_settings()->set_personal_readout(
-        assistant::AssistantDeviceSettings::PERSONAL_READOUT_ENABLED);
-
-    // Device settings update result is not handled because it is not included
-    // in the SettingsUiUpdateResult.
-    parent_->UpdateSettings(update.SerializeAsString(), base::DoNothing());
-  }
-
-  const raw_ref<SettingsController> parent_;
-  const raw_ref<AssistantClient> assistant_client_;
-};
-
-// Sends a 'get settings' requests to Libassistant,
-// waits for the response and forwards it to the callback.
-// Will ensure the callback is always called, even when Libassistant is not
-// running or stopped.
-class GetSettingsResponseWaiter : public AbortableTask {
- public:
-  GetSettingsResponseWaiter(SettingsController::GetSettingsCallback callback,
-                            bool include_header)
-      : callback_(std::move(callback)), include_header_(include_header) {}
-
-  GetSettingsResponseWaiter(const GetSettingsResponseWaiter&) = delete;
-  GetSettingsResponseWaiter& operator=(const GetSettingsResponseWaiter&) =
-      delete;
-  ~GetSettingsResponseWaiter() override { DCHECK(!callback_); }
-
-  void SendRequest(AssistantClient* assistant_client,
-                   const std::string& selector) {
-    if (!assistant_client) {
-      VLOG(1) << "Assistant: 'get settings' request while Libassistant is not "
-                 "running.";
-      Abort();
-      return;
-    }
-
-    ::assistant::ui::SettingsUiSelector selector_proto;
-    selector_proto.ParseFromString(selector);
-    assistant_client->GetAssistantSettings(
-        selector_proto, /*user_id=*/std::string(),
-        base::BindOnce(&GetSettingsResponseWaiter::OnResponse,
-                       weak_factory_.GetWeakPtr()));
-  }
-
-  // AbortableTask implementation:
-  bool IsFinished() override { return callback_.is_null(); }
-  void Abort() override {
-    VLOG(1) << "Assistant: Aborting 'get settings' request";
-    std::move(callback_).Run(std::string());
-  }
-
- private:
-  void OnResponse(
-      const ::assistant::api::GetAssistantSettingsResponse& response) {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-    // |settings_ui| is either a serialized proto message of |SettingsUi|
-    // or |GetSettingsUiResponse| upon success, or an empty string otherwise.
-    std::string settings_ui =
-        UnwrapGetAssistantSettingsResponse(response, include_header_);
-    std::move(callback_).Run(settings_ui);
-  }
-
-  // Ensures all callbacks are called on the current sequence.
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  SettingsController::GetSettingsCallback callback_;
-  // Whether to include header in response. If this is true, a serialized proto
-  // of GetSettingsUiResponse is passed to the callback; otherwise, a serialized
-  // proto of SettingsUi is passed to the callback.
-  bool include_header_;
-  base::WeakPtrFactory<GetSettingsResponseWaiter> weak_factory_{this};
-};
-
-// Sends a 'update settings' requests to Libassistant,
-// waits for the response and forwards it to the callback.
-// Will ensure the callback is always called, even when Libassistant is not
-// running or stopped.
-class UpdateSettingsResponseWaiter : public AbortableTask {
- public:
-  explicit UpdateSettingsResponseWaiter(
-      SettingsController::UpdateSettingsCallback callback)
-      : callback_(std::move(callback)) {}
-
-  UpdateSettingsResponseWaiter(const UpdateSettingsResponseWaiter&) = delete;
-  UpdateSettingsResponseWaiter& operator=(const UpdateSettingsResponseWaiter&) =
-      delete;
-  ~UpdateSettingsResponseWaiter() override = default;
-
-  void SendRequest(AssistantClient* assistant_client,
-                   const std::string& settings) {
-    if (!assistant_client) {
-      VLOG(1) << "Assistant: 'update settings' request while Libassistant is "
-                 "not running.";
-      Abort();
-      return;
-    }
-
-    ::assistant::ui::SettingsUiUpdate update;
-    update.ParseFromString(settings);
-    assistant_client->UpdateAssistantSettings(
-        update, /*user_id=*/std::string(),
-        base::BindOnce(&UpdateSettingsResponseWaiter::OnResponse,
-                       weak_factory_.GetWeakPtr()));
-  }
-
-  // AbortableTask implementation:
-  bool IsFinished() override { return callback_.is_null(); }
-  void Abort() override { std::move(callback_).Run(std::string()); }
-
- private:
-  void OnResponse(
-      const ::assistant::api::UpdateAssistantSettingsResponse& response) {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-    // |update_result| is either a serialized proto message of
-    // |SettingsUiUpdateResult| or an empty string.
-    std::string update_result = UnwrapUpdateAssistantSettingsResponse(response);
-    std::move(callback_).Run(update_result);
-  }
-
-  // Ensures all callbacks are called on the current sequence.
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  SettingsController::UpdateSettingsCallback callback_;
-  base::WeakPtrFactory<UpdateSettingsResponseWaiter> weak_factory_{this};
-};
-
-SettingsController::SettingsController() = default;
-SettingsController::~SettingsController() = default;
-
-void SettingsController::Bind(
-    mojo::PendingReceiver<mojom::SettingsController> receiver) {
-  receiver_.Bind(std::move(receiver));
-}
-
-void SettingsController::SetAuthenticationTokens(
-    std::vector<mojom::AuthenticationTokenPtr> tokens) {
-  authentication_tokens_ = std::move(tokens);
-
-  UpdateAuthenticationTokens(authentication_tokens_);
-}
-
-void SettingsController::SetLocale(const std::string& value) {
-  locale_ = LocaleOrDefault(value);
-  UpdateLocaleOverride(locale_);
-  UpdateInternalOptions(locale_, spoken_feedback_enabled_, dark_mode_enabled_);
-  UpdateDeviceSettings(locale_, hotword_enabled_);
-}
-
-void SettingsController::SetListeningEnabled(bool value) {
-  listening_enabled_ = value;
-  UpdateListeningEnabled(listening_enabled_);
-}
-
-void SettingsController::SetSpokenFeedbackEnabled(bool value) {
-  spoken_feedback_enabled_ = value;
-  UpdateInternalOptions(locale_, spoken_feedback_enabled_, dark_mode_enabled_);
-}
-
-void SettingsController::SetDarkModeEnabled(bool value) {
-  dark_mode_enabled_ = value;
-  UpdateDarkModeEnabledV2(dark_mode_enabled_);
-}
-
-void SettingsController::SetHotwordEnabled(bool value) {
-  hotword_enabled_ = value;
-  UpdateDeviceSettings(locale_, hotword_enabled_);
-}
-
-void SettingsController::GetSettings(const std::string& selector,
-                                     bool include_header,
-                                     GetSettingsCallback callback) {
-  auto* waiter =
-      pending_response_waiters_.Add(std::make_unique<GetSettingsResponseWaiter>(
-          std::move(callback), include_header));
-  waiter->SendRequest(assistant_client_, selector);
-}
-
-void SettingsController::UpdateSettings(const std::string& settings,
-                                        UpdateSettingsCallback callback) {
-  auto* waiter = pending_response_waiters_.Add(
-      std::make_unique<UpdateSettingsResponseWaiter>(std::move(callback)));
-  waiter->SendRequest(assistant_client_, settings);
-}
-
-void SettingsController::UpdateListeningEnabled(
-    std::optional<bool> listening_enabled) {
-  if (!assistant_client_)
-    return;
-  if (!listening_enabled.has_value())
-    return;
-
-  assistant_client_->EnableListening(listening_enabled.value());
-}
-
-void SettingsController::UpdateAuthenticationTokens(
-    const std::optional<std::vector<mojom::AuthenticationTokenPtr>>& tokens) {
-  if (!assistant_client_)
-    return;
-  if (!tokens.has_value())
-    return;
-
-  assistant_client_->SetAuthenticationInfo(ToAuthTokens(tokens.value()));
-}
-
-void SettingsController::UpdateInternalOptions(
-    const std::optional<std::string>& locale,
-    std::optional<bool> spoken_feedback_enabled,
-    std::optional<bool> dark_mode_enabled) {
-  if (!assistant_client_)
-    return;
-
-  if (locale.has_value() && spoken_feedback_enabled.has_value()) {
-    assistant_client_->SetInternalOptions(locale.value(),
-                                          spoken_feedback_enabled.value());
-  }
-}
-
-void SettingsController::UpdateLocaleOverride(
-    const std::optional<std::string>& locale) {
-  if (!assistant_client_)
-    return;
-
-  if (!locale.has_value())
-    return;
-
-  assistant_client_->SetLocaleOverride(locale.value());
-}
-
-void SettingsController::UpdateDeviceSettings(
-    const std::optional<std::string>& locale,
-    std::optional<bool> hotword_enabled) {
-  if (!device_settings_updater_)
-    return;
-
-  if (locale.has_value() && hotword_enabled.has_value()) {
-    device_settings_updater_->UpdateSettings(locale.value(),
-                                             hotword_enabled.value());
-  }
-}
-
-void SettingsController::UpdateDarkModeEnabledV2(
-    std::optional<bool> dark_mode_enabled) {
-  if (!assistant_client_)
-    return;
-
-  if (!dark_mode_enabled.has_value())
-    return;
-
-  ::assistant::display::DisplayRequest display_request;
-  display_request.mutable_set_device_properties_request()
-      ->mutable_theme_properties_to_merge()
-      ->set_mode(dark_mode_enabled.value()
-                     ? ::assistant::api::params::ThemeProperties::DARK_THEME
-                     : ::assistant::api::params::ThemeProperties::LIGHT_THEME);
-
-  ::assistant::api::OnDisplayRequestRequest request;
-  request.set_display_request_bytes(display_request.SerializeAsString());
-  assistant_client_->SendDisplayRequest(request);
-}
-
-void SettingsController::OnAssistantClientCreated(
-    AssistantClient* assistant_client) {
-  assistant_client_ = assistant_client;
-
-  // Note we do not enable the device settings updater here, as it requires
-  // Libassistant to be fully ready.
-  UpdateAuthenticationTokens(authentication_tokens_);
-  UpdateInternalOptions(locale_, spoken_feedback_enabled_, dark_mode_enabled_);
-}
-
-void SettingsController::OnAssistantClientRunning(
-    AssistantClient* assistant_client) {
-  device_settings_updater_ =
-      std::make_unique<DeviceSettingsUpdater>(this, assistant_client);
-
-  UpdateDeviceSettings(locale_, hotword_enabled_);
-  UpdateLocaleOverride(locale_);
-  UpdateListeningEnabled(listening_enabled_);
-  UpdateDarkModeEnabledV2(dark_mode_enabled_);
-}
-
-void SettingsController::OnDestroyingAssistantClient(
-    AssistantClient* assistant_client) {
-  assistant_client_ = nullptr;
-  device_settings_updater_ = nullptr;
-  pending_response_waiters_.AbortAll();
-
-  authentication_tokens_.reset();
-  hotword_enabled_.reset();
-  locale_.reset();
-  spoken_feedback_enabled_.reset();
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/settings_controller.h b/chromeos/ash/services/libassistant/settings_controller.h
deleted file mode 100644
index e0970d9..0000000
--- a/chromeos/ash/services/libassistant/settings_controller.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_SETTINGS_CONTROLLER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_SETTINGS_CONTROLLER_H_
-
-#include <optional>
-#include <string>
-
-#include "base/memory/raw_ptr.h"
-#include "chromeos/ash/services/libassistant/abortable_task_list.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client_observer.h"
-#include "chromeos/ash/services/libassistant/public/mojom/settings_controller.mojom.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-
-namespace ash::libassistant {
-
-class SettingsController : public AssistantClientObserver,
-                           public mojom::SettingsController {
- public:
-  SettingsController();
-  SettingsController(const SettingsController&) = delete;
-  SettingsController& operator=(const SettingsController&) = delete;
-  ~SettingsController() override;
-
-  void Bind(mojo::PendingReceiver<mojom::SettingsController> receiver);
-
-  // mojom::SettingsController implementation:
-  void SetAuthenticationTokens(
-      std::vector<mojom::AuthenticationTokenPtr> tokens) override;
-  void SetListeningEnabled(bool value) override;
-  void SetLocale(const std::string& value) override;
-  void SetSpokenFeedbackEnabled(bool value) override;
-  void SetDarkModeEnabled(bool value) override;
-  void SetHotwordEnabled(bool value) override;
-  void GetSettings(const std::string& selector,
-                   bool include_header,
-                   GetSettingsCallback callback) override;
-  void UpdateSettings(const std::string& settings,
-                      UpdateSettingsCallback callback) override;
-
-  // AssistantClientObserver:
-  void OnAssistantClientCreated(AssistantClient* assistant_client) override;
-  void OnAssistantClientRunning(AssistantClient* assistant_client) override;
-  void OnDestroyingAssistantClient(AssistantClient* assistant_client) override;
-
- private:
-  class DeviceSettingsUpdater;
-
-  // The settings are being passed in to clearly document when Libassistant
-  // must be updated.
-  void UpdateListeningEnabled(std::optional<bool> listening_enabled);
-  void UpdateAuthenticationTokens(
-      const std::optional<std::vector<mojom::AuthenticationTokenPtr>>& tokens);
-  void UpdateInternalOptions(const std::optional<std::string>& locale,
-                             std::optional<bool> spoken_feedback_enabled,
-                             std::optional<bool> dark_mode_enabled);
-  void UpdateLocaleOverride(const std::optional<std::string>& locale);
-  void UpdateDeviceSettings(const std::optional<std::string>& locale,
-                            std::optional<bool> hotword_enabled);
-  void UpdateDarkModeEnabledV2(std::optional<bool> dark_mode_enabled);
-
-  // Instantiated when Libassistant is started and destroyed when Libassistant
-  // is stopped.
-  // Used to update the device settings.
-  std::unique_ptr<DeviceSettingsUpdater> device_settings_updater_;
-  // Contains all pending callbacks for get/update setting requests.
-  AbortableTaskList pending_response_waiters_;
-
-  // Set in |OnAssistantClientCreated| and unset in
-  // |OnDestroyingAssistantClient|.
-  raw_ptr<AssistantClient> assistant_client_ = nullptr;
-
-  std::optional<bool> hotword_enabled_;
-  std::optional<bool> spoken_feedback_enabled_;
-  std::optional<bool> dark_mode_enabled_;
-  std::optional<bool> listening_enabled_;
-  std::optional<std::string> locale_;
-  std::optional<std::vector<mojom::AuthenticationTokenPtr>>
-      authentication_tokens_;
-
-  mojo::Receiver<mojom::SettingsController> receiver_{this};
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_SETTINGS_CONTROLLER_H_
diff --git a/chromeos/ash/services/libassistant/settings_controller_unittest.cc b/chromeos/ash/services/libassistant/settings_controller_unittest.cc
deleted file mode 100644
index 1a49311..0000000
--- a/chromeos/ash/services/libassistant/settings_controller_unittest.cc
+++ /dev/null
@@ -1,430 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/settings_controller.h"
-
-#include "base/test/mock_callback.h"
-#include "base/test/task_environment.h"
-#include "chromeos/ash/services/libassistant/test_support/fake_assistant_client.h"
-#include "chromeos/assistant/internal/test_support/fake_assistant_manager.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/icu/source/common/unicode/locid.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-#define EXPECT_NO_CALLS(args...) EXPECT_CALL(args).Times(0);
-#define IGNORE_CALLS(args...) EXPECT_CALL(args).Times(testing::AnyNumber());
-// The auth tokens are pairs of <user, token>
-using AuthTokens = std::vector<std::pair<std::string, std::string>>;
-
-std::vector<mojom::AuthenticationTokenPtr> ToVector(
-    mojom::AuthenticationTokenPtr token) {
-  std::vector<mojom::AuthenticationTokenPtr> result;
-  result.push_back(std::move(token));
-  return result;
-}
-
-class AssistantClientMock : public FakeAssistantClient {
- public:
-  AssistantClientMock(std::unique_ptr<chromeos::assistant::FakeAssistantManager>
-                          assistant_manager)
-      : FakeAssistantClient(std::move(assistant_manager)) {}
-  ~AssistantClientMock() override = default;
-
-  // FakeAssistantClient:
-  MOCK_METHOD(
-      void,
-      UpdateAssistantSettings,
-      (const ::assistant::ui::SettingsUiUpdate& settings,
-       const std::string& user_id,
-       base::OnceCallback<void(
-           const ::assistant::api::UpdateAssistantSettingsResponse&)> on_done));
-  MOCK_METHOD(
-      void,
-      GetAssistantSettings,
-      (const ::assistant::ui::SettingsUiSelector& selector,
-       const std::string& user_id,
-       base::OnceCallback<void(
-           const ::assistant::api::GetAssistantSettingsResponse&)> on_done));
-  MOCK_METHOD(void, SetLocaleOverride, (const std::string& locale));
-  MOCK_METHOD(void,
-              SetInternalOptions,
-              (const std::string& locale, bool spoken_feedback_enabled));
-  MOCK_METHOD(void, SetDeviceAttributes, (bool dark_mode_enabled));
-  MOCK_METHOD(void, EnableListening, (bool listening_enabled));
-  MOCK_METHOD(void, SetAuthenticationInfo, (const AuthTokens& tokens));
-  MOCK_METHOD(void,
-              SendDisplayRequest,
-              (const OnDisplayRequestRequest& request));
-};
-
-}  // namespace
-
-class AssistantSettingsControllerTest : public testing::Test {
- public:
-  AssistantSettingsControllerTest() { Init(); }
-
-  AssistantSettingsControllerTest(const AssistantSettingsControllerTest&) =
-      delete;
-  AssistantSettingsControllerTest& operator=(
-      const AssistantSettingsControllerTest&) = delete;
-  ~AssistantSettingsControllerTest() override = default;
-
-  SettingsController& controller() { return controller_; }
-
-  void CreateLibassistant() {
-    controller().OnAssistantClientCreated(assistant_client_.get());
-  }
-
-  void RunningLibassistant() {
-    controller().OnAssistantClientRunning(assistant_client_.get());
-  }
-
-  void DestroyLibassistant() {
-    controller().OnDestroyingAssistantClient(assistant_client_.get());
-
-    Init();
-  }
-
-  void CreateAndRunningLibassistant() {
-    CreateLibassistant();
-    RunningLibassistant();
-  }
-
-  void Init() {
-    assistant_client_ = nullptr;
-
-    auto assistant_manager =
-        std::make_unique<chromeos::assistant::FakeAssistantManager>();
-    assistant_client_ =
-        std::make_unique<AssistantClientMock>(std::move(assistant_manager));
-  }
-
-  AssistantClientMock& assistant_client_mock() { return *assistant_client_; }
-
- private:
-  base::test::SingleThreadTaskEnvironment environment_;
-
-  SettingsController controller_;
-  std::unique_ptr<AssistantClientMock> assistant_client_;
-};
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldNotCrashIfLibassistantIsNotCreated) {
-  controller().SetAuthenticationTokens({});
-  controller().SetHotwordEnabled(true);
-  controller().SetListeningEnabled(true);
-  controller().SetLocale("locale");
-  controller().SetSpokenFeedbackEnabled(true);
-  controller().SetDarkModeEnabled(false);
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldNotCrashAfterDestroyingLibassistant) {
-  CreateLibassistant();
-  DestroyLibassistant();
-
-  controller().SetAuthenticationTokens({});
-  controller().SetHotwordEnabled(true);
-  controller().SetListeningEnabled(true);
-  controller().SetLocale("locale");
-  controller().SetSpokenFeedbackEnabled(true);
-  controller().SetDarkModeEnabled(false);
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldResetAllValuesWhenLibassistantIsDestroyed) {
-  controller().SetAuthenticationTokens({});
-  controller().SetHotwordEnabled(true);
-  controller().SetLocale("locale");
-  controller().SetSpokenFeedbackEnabled(true);
-  controller().SetDarkModeEnabled(true);
-
-  DestroyLibassistant();
-
-  // After destroying Libassistant, the settings should be cleared.
-  // We test this by ensuring they are not applied when Libassistant starts.
-  EXPECT_NO_CALLS(assistant_client_mock(), SetLocaleOverride);
-  EXPECT_NO_CALLS(assistant_client_mock(), SetInternalOptions);
-  EXPECT_NO_CALLS(assistant_client_mock(), UpdateAssistantSettings);
-  EXPECT_NO_CALLS(assistant_client_mock(), SetAuthenticationInfo);
-  CreateLibassistant();
-}
-
-TEST_F(AssistantSettingsControllerTest, ShouldSetLocale) {
-  CreateLibassistant();
-
-  EXPECT_CALL(assistant_client_mock(), SetLocaleOverride("locale"));
-
-  controller().SetLocale("locale");
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldUseDefaultLocaleIfSettingToEmptyString) {
-  const std::string default_locale = icu::Locale::getDefault().getName();
-  CreateLibassistant();
-
-  EXPECT_CALL(assistant_client_mock(), SetLocaleOverride(default_locale));
-
-  controller().SetLocale("");
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldNotSetInternalOptionsWhenLocaleIsNotSet) {
-  CreateLibassistant();
-
-  EXPECT_NO_CALLS(assistant_client_mock(), SetInternalOptions);
-  EXPECT_NO_CALLS(assistant_client_mock(), SetDeviceAttributes);
-
-  controller().SetSpokenFeedbackEnabled(true);
-  controller().SetDarkModeEnabled(false);
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldNotSetInternalOptionsWhenSpokenFeedbackEnabledIsNotSet) {
-  IGNORE_CALLS(assistant_client_mock(), SetLocaleOverride);
-  CreateLibassistant();
-
-  EXPECT_NO_CALLS(assistant_client_mock(), SetInternalOptions);
-  EXPECT_NO_CALLS(assistant_client_mock(), SetDeviceAttributes);
-
-  controller().SetLocale("locale");
-  controller().SetDarkModeEnabled(false);
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldNotSetInternalOptionsWhenDarkModeEnabledIsNotSet) {
-  IGNORE_CALLS(assistant_client_mock(), SetLocaleOverride);
-  CreateLibassistant();
-
-  EXPECT_NO_CALLS(assistant_client_mock(), SetDeviceAttributes);
-
-  controller().SetLocale("locale");
-  controller().SetSpokenFeedbackEnabled(true);
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldSetInternalOptionsWhenLocaleIsUpdated) {
-  IGNORE_CALLS(assistant_client_mock(), SetLocaleOverride);
-  controller().SetSpokenFeedbackEnabled(true);
-  controller().SetDarkModeEnabled(false);
-  CreateLibassistant();
-
-  EXPECT_CALL(assistant_client_mock(), SetInternalOptions);
-
-  controller().SetLocale("locale");
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldSetInternalOptionsWhenSpokenFeedbackEnabledIsUpdated) {
-  IGNORE_CALLS(assistant_client_mock(), SetLocaleOverride);
-  controller().SetLocale("locale");
-  controller().SetDarkModeEnabled(false);
-  CreateLibassistant();
-
-  EXPECT_CALL(assistant_client_mock(), SetInternalOptions);
-
-  controller().SetSpokenFeedbackEnabled(true);
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldSetInternalOptionsWhenDarkModeEnabledIsUpdated_V2) {
-  IGNORE_CALLS(assistant_client_mock(), SetLocaleOverride);
-  controller().SetLocale("locale");
-  controller().SetSpokenFeedbackEnabled(true);
-  CreateLibassistant();
-
-  EXPECT_CALL(assistant_client_mock(), SendDisplayRequest);
-  EXPECT_NO_CALLS(assistant_client_mock(), SetInternalOptions);
-  EXPECT_NO_CALLS(assistant_client_mock(), SetDeviceAttributes);
-
-  controller().SetDarkModeEnabled(false);
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldSetInternalOptionsAndLocaleWhenLibassistantIsRunning_V2) {
-  CreateLibassistant();
-  controller().SetLocale("locale");
-  controller().SetSpokenFeedbackEnabled(true);
-  controller().SetDarkModeEnabled(false);
-
-  EXPECT_CALL(assistant_client_mock(), SetLocaleOverride);
-  EXPECT_CALL(assistant_client_mock(), SetInternalOptions);
-
-  CreateAndRunningLibassistant();
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldNotSetDeviceOptionsWhenLocaleIsNotSet) {
-  IGNORE_CALLS(assistant_client_mock(), SetLocaleOverride);
-  CreateLibassistant();
-
-  EXPECT_NO_CALLS(assistant_client_mock(), UpdateAssistantSettings);
-
-  controller().SetHotwordEnabled(true);
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldNotSetDeviceOptionsWhenHotwordEnabledIsNotSet) {
-  IGNORE_CALLS(assistant_client_mock(), SetLocaleOverride);
-  CreateLibassistant();
-
-  EXPECT_NO_CALLS(assistant_client_mock(), UpdateAssistantSettings);
-
-  controller().SetLocale("locale");
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldSetDeviceOptionsWhenLocaleIsUpdated) {
-  IGNORE_CALLS(assistant_client_mock(), SetLocaleOverride);
-  CreateAndRunningLibassistant();
-  controller().SetHotwordEnabled(true);
-
-  EXPECT_CALL(assistant_client_mock(), UpdateAssistantSettings);
-
-  controller().SetLocale("locale");
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldSetDeviceOptionsWhenHotwordEnabledIsUpdated) {
-  IGNORE_CALLS(assistant_client_mock(), SetLocaleOverride);
-  CreateAndRunningLibassistant();
-  controller().SetLocale("locale");
-
-  EXPECT_CALL(assistant_client_mock(), UpdateAssistantSettings);
-
-  controller().SetHotwordEnabled(true);
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldSetDeviceOptionsWhenLibassistantIsRunning) {
-  IGNORE_CALLS(assistant_client_mock(), SetLocaleOverride);
-  CreateLibassistant();
-  controller().SetLocale("locale");
-  controller().SetHotwordEnabled(true);
-
-  EXPECT_CALL(assistant_client_mock(), UpdateAssistantSettings);
-
-  RunningLibassistant();
-}
-
-TEST_F(AssistantSettingsControllerTest, ShouldSetAuthenticationTokens) {
-  const AuthTokens expected = {{"user", "token"}};
-
-  CreateLibassistant();
-
-  EXPECT_CALL(assistant_client_mock(), SetAuthenticationInfo(expected));
-
-  controller().SetAuthenticationTokens(
-      ToVector(mojom::AuthenticationToken::New("user", "token")));
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldSetAuthenticationTokensWhenLibassistantIsStarted) {
-  const AuthTokens expected = {{"user", "token"}};
-
-  controller().SetAuthenticationTokens(
-      ToVector(mojom::AuthenticationToken::New("user", "token")));
-
-  EXPECT_CALL(assistant_client_mock(), SetAuthenticationInfo(expected));
-
-  CreateLibassistant();
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldSupportEmptyAuthenticationTokenList) {
-  CreateLibassistant();
-
-  const AuthTokens expected = {};
-  EXPECT_CALL(assistant_client_mock(), SetAuthenticationInfo(expected));
-
-  controller().SetAuthenticationTokens({});
-}
-
-TEST_F(AssistantSettingsControllerTest, ShouldSetListeningEnabled) {
-  CreateLibassistant();
-
-  EXPECT_CALL(assistant_client_mock(), EnableListening(true));
-
-  controller().SetListeningEnabled(true);
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldSetListeningEnabledWhenLibassistantIsRunning_V2) {
-  CreateLibassistant();
-  controller().SetListeningEnabled(false);
-
-  EXPECT_CALL(assistant_client_mock(), EnableListening(false));
-
-  RunningLibassistant();
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       GetSettingsShouldCallCallbackEvenIfLibassistantIsNotStarted) {
-  base::MockCallback<SettingsController::GetSettingsCallback> callback;
-
-  EXPECT_CALL(callback, Run(std::string{}));
-
-  controller().GetSettings("selector", /*include_header=*/false, callback.Get());
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       GetSettingsShouldCallCallbackIfLibassistantIsStopped) {
-  CreateLibassistant();
-
-  base::MockCallback<SettingsController::GetSettingsCallback> callback;
-  controller().GetSettings("selector", /*include_header=*/false, callback.Get());
-
-  EXPECT_CALL(callback, Run(std::string{}));
-  DestroyLibassistant();
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       UpdateSettingsShouldCallCallbackEvenIfLibassistantIsNotStarted) {
-  base::MockCallback<SettingsController::UpdateSettingsCallback> callback;
-
-  EXPECT_CALL(callback, Run(std::string{}));
-
-  controller().UpdateSettings("selector", callback.Get());
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       UpdateSettingsShouldCallCallbackIfLibassistantIsStopped) {
-  IGNORE_CALLS(assistant_client_mock(), UpdateAssistantSettings);
-  CreateLibassistant();
-
-  base::MockCallback<SettingsController::UpdateSettingsCallback> callback;
-  controller().UpdateSettings("selector", callback.Get());
-
-  EXPECT_CALL(callback, Run(std::string{}));
-  DestroyLibassistant();
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldInvokeGetAssistantSettingsWhenGetSettingsCalled) {
-  CreateLibassistant();
-
-  EXPECT_CALL(assistant_client_mock(), GetAssistantSettings);
-
-  controller().GetSettings("selector", /*include_header=*/false,
-                           base::DoNothing());
-
-  DestroyLibassistant();
-}
-
-TEST_F(AssistantSettingsControllerTest,
-       ShouldInvokeUpdateAssistantSettingsWhenUpdateSettingsCalled) {
-  CreateLibassistant();
-
-  EXPECT_CALL(assistant_client_mock(), UpdateAssistantSettings);
-
-  controller().UpdateSettings("selector", base::DoNothing());
-
-  DestroyLibassistant();
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/speaker_id_enrollment_controller.cc b/chromeos/ash/services/libassistant/speaker_id_enrollment_controller.cc
deleted file mode 100644
index 5ffbb68..0000000
--- a/chromeos/ash/services/libassistant/speaker_id_enrollment_controller.cc
+++ /dev/null
@@ -1,246 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/speaker_id_enrollment_controller.h"
-
-#include "base/memory/raw_ptr.h"
-#include "base/scoped_observation.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/grpc_services_observer.h"
-#include "chromeos/ash/services/libassistant/public/mojom/audio_input_controller.mojom.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_interface.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/speaker_id_enrollment_event.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/speaker_id_enrollment_interface.pb.h"
-#include "mojo/public/cpp/bindings/remote.h"
-
-namespace ash::libassistant {
-
-using ::assistant::api::OnSpeakerIdEnrollmentEventRequest;
-
-////////////////////////////////////////////////////////////////////////////////
-// GetStatusWaiter
-////////////////////////////////////////////////////////////////////////////////
-
-// Helper class that will wait for the result of the
-// |GetSpeakerIdEnrollmentStatus| call, and send it to the callback.
-class SpeakerIdEnrollmentController::GetStatusWaiter : public AbortableTask {
- public:
-  using Callback =
-      SpeakerIdEnrollmentController::GetSpeakerIdEnrollmentStatusCallback;
-
-  GetStatusWaiter() = default;
-  ~GetStatusWaiter() override { DCHECK(!callback_); }
-  GetStatusWaiter(const GetStatusWaiter&) = delete;
-  GetStatusWaiter& operator=(const GetStatusWaiter&) = delete;
-
-  void Start(AssistantClient* assistant_client,
-             const std::string& user_gaia_id,
-             Callback callback) {
-    callback_ = std::move(callback);
-
-    VLOG(1) << "Assistant: Retrieving speaker enrollment status";
-
-    if (!assistant_client) {
-      SendErrorResponse();
-      return;
-    }
-
-    ::assistant::api::GetSpeakerIdEnrollmentInfoRequest request;
-    auto* user_model_request = request.mutable_user_model_status_request();
-    user_model_request->set_user_id(user_gaia_id);
-    assistant_client->GetSpeakerIdEnrollmentInfo(
-        request, base::BindOnce(&GetStatusWaiter::SendResponse,
-                                weak_ptr_factory_.GetWeakPtr()));
-  }
-
-  // AbortableTask implementation:
-  bool IsFinished() override { return callback_.is_null(); }
-  void Abort() override { SendErrorResponse(); }
-
-  void SendResponseForTesting(bool user_model_exists) {
-    SendResponse(user_model_exists);
-  }
-
- private:
-  void SendErrorResponse() { SendResponse(false); }
-
-  void SendResponse(bool user_model_exists) {
-    VLOG(1) << "Assistant: Is user already enrolled? " << user_model_exists;
-
-    std::move(callback_).Run(
-        mojom::SpeakerIdEnrollmentStatus::New(user_model_exists));
-  }
-
-  Callback callback_;
-  base::WeakPtrFactory<GetStatusWaiter> weak_ptr_factory_{this};
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// EnrollmentSession
-////////////////////////////////////////////////////////////////////////////////
-
-// A single enrollment session, created when speaker id enrollment is started,
-// and destroyed when it is done or cancelled.
-class SpeakerIdEnrollmentController::EnrollmentSession
-    : public GrpcServicesObserver<OnSpeakerIdEnrollmentEventRequest> {
- public:
-  using SpeakerIdEnrollmentEvent =
-      ::assistant::api::events::SpeakerIdEnrollmentEvent;
-
-  EnrollmentSession(
-      ::mojo::PendingRemote<mojom::SpeakerIdEnrollmentClient> client,
-      AssistantClient* assistant_client)
-      : client_(std::move(client)), assistant_client_(assistant_client) {
-    DCHECK(assistant_client_);
-    scoped_assistant_client_observation_.Observe(assistant_client_.get());
-  }
-  EnrollmentSession(const EnrollmentSession&) = delete;
-  EnrollmentSession& operator=(const EnrollmentSession&) = delete;
-  ~EnrollmentSession() override { Stop(); }
-
-  // GrpcServicesObserver:
-  // Invoked when a Speaker Id Enrollment event has been received.
-  void OnGrpcMessage(const ::assistant::api::OnSpeakerIdEnrollmentEventRequest&
-                         request) override {
-    switch (request.event().type_case()) {
-      case SpeakerIdEnrollmentEvent::kListenState:
-        VLOG(1) << "Assistant: Speaker id enrollment is listening";
-        client_->OnListeningHotword();
-        break;
-      case SpeakerIdEnrollmentEvent::kProcessState:
-        VLOG(1) << "Assistant: Speaker id enrollment is processing";
-        client_->OnProcessingHotword();
-        break;
-      case SpeakerIdEnrollmentEvent::kDoneState:
-        VLOG(1) << "Assistant: Speaker id enrollment is done";
-        client_->OnSpeakerIdEnrollmentDone();
-        done_ = true;
-        break;
-      case SpeakerIdEnrollmentEvent::kFailureState:
-        VLOG(1) << "Assistant: Speaker id enrollment is done (with failure)";
-        client_->OnSpeakerIdEnrollmentFailure();
-        done_ = true;
-        break;
-      case SpeakerIdEnrollmentEvent::kInitState:
-      case SpeakerIdEnrollmentEvent::kCheckState:
-      case SpeakerIdEnrollmentEvent::kRecognizeState:
-      case SpeakerIdEnrollmentEvent::kUploadState:
-      case SpeakerIdEnrollmentEvent::kFetchState:
-      case SpeakerIdEnrollmentEvent::TYPE_NOT_SET:
-        break;
-    }
-  }
-
-  void Start(const std::string& user_gaia_id, bool skip_cloud_enrollment) {
-    VLOG(1) << "Assistant: Starting speaker id enrollment";
-
-    ::assistant::api::StartSpeakerIdEnrollmentRequest request;
-    request.set_user_id(user_gaia_id);
-    request.set_skip_cloud_enrollment(skip_cloud_enrollment);
-    assistant_client_->StartSpeakerIdEnrollment(request);
-  }
-
-  void Stop() {
-    if (done_)
-      return;
-
-    VLOG(1) << "Assistant: Stopping speaker id enrollment";
-    ::assistant::api::CancelSpeakerIdEnrollmentRequest request;
-    assistant_client_->CancelSpeakerIdEnrollment(request);
-  }
-
- private:
-  ::mojo::Remote<mojom::SpeakerIdEnrollmentClient> client_;
-  const raw_ptr<AssistantClient> assistant_client_;
-  bool done_ = false;
-  base::ScopedObservation<
-      AssistantClient,
-      GrpcServicesObserver<OnSpeakerIdEnrollmentEventRequest>>
-      scoped_assistant_client_observation_{this};
-  base::WeakPtrFactory<EnrollmentSession> weak_factory_{this};
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// SpeakerIdEnrollmentController
-////////////////////////////////////////////////////////////////////////////////
-
-SpeakerIdEnrollmentController::SpeakerIdEnrollmentController(
-    mojom::AudioInputController* audio_input)
-    : audio_input_(audio_input) {}
-SpeakerIdEnrollmentController::~SpeakerIdEnrollmentController() = default;
-
-void SpeakerIdEnrollmentController::Bind(
-    mojo::PendingReceiver<mojom::SpeakerIdEnrollmentController>
-        pending_receiver) {
-  receiver_.Bind(std::move(pending_receiver));
-}
-
-void SpeakerIdEnrollmentController::StartSpeakerIdEnrollment(
-    const std::string& user_gaia_id,
-    bool skip_cloud_enrollment,
-    ::mojo::PendingRemote<mojom::SpeakerIdEnrollmentClient> client) {
-  if (!assistant_client_)
-    return;
-
-  // Force mic state to open, otherwise the training might not open the
-  // microphone. See b/139329513.
-  audio_input_->SetMicOpen(true);
-
-  // If there is an ongoing enrollment session, abort it first.
-  if (active_enrollment_session_)
-    active_enrollment_session_->Stop();
-
-  active_enrollment_session_ =
-      std::make_unique<EnrollmentSession>(std::move(client), assistant_client_);
-  active_enrollment_session_->Start(user_gaia_id, skip_cloud_enrollment);
-}
-
-void SpeakerIdEnrollmentController::StopSpeakerIdEnrollment() {
-  if (!assistant_client_)
-    return;
-
-  if (!active_enrollment_session_)
-    return;
-
-  audio_input_->SetMicOpen(false);
-
-  active_enrollment_session_->Stop();
-  active_enrollment_session_ = nullptr;
-}
-
-void SpeakerIdEnrollmentController::GetSpeakerIdEnrollmentStatus(
-    const std::string& user_gaia_id,
-    GetSpeakerIdEnrollmentStatusCallback callback) {
-  auto* waiter =
-      pending_response_waiters_.Add(std::make_unique<GetStatusWaiter>());
-  waiter->Start(assistant_client_, user_gaia_id, std::move(callback));
-}
-
-void SpeakerIdEnrollmentController::OnAssistantClientStarted(
-    AssistantClient* assistant_client) {
-  assistant_client_ = assistant_client;
-}
-
-void SpeakerIdEnrollmentController::OnDestroyingAssistantClient(
-    AssistantClient* assistant_client) {
-  active_enrollment_session_ = nullptr;
-  assistant_client_ = nullptr;
-  pending_response_waiters_.AbortAll();
-}
-
-void SpeakerIdEnrollmentController::OnGrpcMessageForTesting(
-    const ::assistant::api::OnSpeakerIdEnrollmentEventRequest& request) {
-  active_enrollment_session_->OnGrpcMessage(std::move(request));
-}
-
-void SpeakerIdEnrollmentController::SendGetStatusResponseForTesting(
-    bool user_model_exists) {
-  auto* waiter =
-      reinterpret_cast<SpeakerIdEnrollmentController::GetStatusWaiter*>(
-          pending_response_waiters_.GetFirstTaskForTesting());
-  waiter->SendResponseForTesting(user_model_exists);
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/speaker_id_enrollment_controller.h b/chromeos/ash/services/libassistant/speaker_id_enrollment_controller.h
deleted file mode 100644
index 4a9bc9e..0000000
--- a/chromeos/ash/services/libassistant/speaker_id_enrollment_controller.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_SPEAKER_ID_ENROLLMENT_CONTROLLER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_SPEAKER_ID_ENROLLMENT_CONTROLLER_H_
-
-#include "base/memory/raw_ptr.h"
-#include "chromeos/ash/services/libassistant/abortable_task_list.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client_observer.h"
-#include "chromeos/ash/services/libassistant/public/mojom/audio_input_controller.mojom-forward.h"
-#include "chromeos/ash/services/libassistant/public/mojom/speaker_id_enrollment_controller.mojom.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_interface.pb.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-
-namespace ash::libassistant {
-
-class AssistantClient;
-
-class SpeakerIdEnrollmentController
-    : public mojom::SpeakerIdEnrollmentController,
-      public AssistantClientObserver {
- public:
-  explicit SpeakerIdEnrollmentController(
-      mojom::AudioInputController* audio_input);
-  SpeakerIdEnrollmentController(const SpeakerIdEnrollmentController&) = delete;
-  SpeakerIdEnrollmentController& operator=(
-      const SpeakerIdEnrollmentController&) = delete;
-  ~SpeakerIdEnrollmentController() override;
-
-  void Bind(mojo::PendingReceiver<mojom::SpeakerIdEnrollmentController>
-                pending_receiver);
-
-  // mojom::SpeakerIdEnrollmentController implementation:
-  void StartSpeakerIdEnrollment(
-      const std::string& user_gaia_id,
-      bool skip_cloud_enrollment,
-      ::mojo::PendingRemote<mojom::SpeakerIdEnrollmentClient> client) override;
-  void StopSpeakerIdEnrollment() override;
-  void GetSpeakerIdEnrollmentStatus(
-      const std::string& user_gaia_id,
-      GetSpeakerIdEnrollmentStatusCallback callback) override;
-
-  // AssistantClientObserver implementation:
-  void OnAssistantClientStarted(AssistantClient* assistant_client) override;
-  void OnDestroyingAssistantClient(AssistantClient* assistant_client) override;
-
-  bool IsSpeakerIdEnrollmentInProgressForTesting() const {
-    return !!active_enrollment_session_;
-  }
-
-  void OnGrpcMessageForTesting(
-      const ::assistant::api::OnSpeakerIdEnrollmentEventRequest& request);
-
-  void SendGetStatusResponseForTesting(bool user_model_exists);
-
- private:
-  class EnrollmentSession;
-  class GetStatusWaiter;
-
-  mojo::Receiver<mojom::SpeakerIdEnrollmentController> receiver_{this};
-  const raw_ptr<mojom::AudioInputController> audio_input_;
-
-  std::unique_ptr<EnrollmentSession> active_enrollment_session_;
-  // Contains all pending callbacks for GetSpeakerIdEnrollmentStatus requests.
-  AbortableTaskList pending_response_waiters_;
-
-  raw_ptr<AssistantClient> assistant_client_ = nullptr;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_SPEAKER_ID_ENROLLMENT_CONTROLLER_H_
diff --git a/chromeos/ash/services/libassistant/speaker_id_enrollment_controller_unittest.cc b/chromeos/ash/services/libassistant/speaker_id_enrollment_controller_unittest.cc
deleted file mode 100644
index 9e53ed8a..0000000
--- a/chromeos/ash/services/libassistant/speaker_id_enrollment_controller_unittest.cc
+++ /dev/null
@@ -1,276 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/speaker_id_enrollment_controller.h"
-
-#include "base/test/mock_callback.h"
-#include "base/test/task_environment.h"
-#include "chromeos/ash/services/libassistant/test_support/libassistant_service_tester.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_interface.pb.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::libassistant {
-
-namespace {
-using assistant_client::SpeakerIdEnrollmentStatus;
-using SpeakerIdEnrollmentState =
-    ::assistant_client::SpeakerIdEnrollmentUpdate::State;
-using GetSpeakerIdEnrollmentStatusCallback =
-    SpeakerIdEnrollmentController::GetSpeakerIdEnrollmentStatusCallback;
-using ::testing::NiceMock;
-using ::testing::StrictMock;
-
-class SpeakerIdEnrollmentClientMock : public mojom::SpeakerIdEnrollmentClient {
- public:
-  SpeakerIdEnrollmentClientMock() = default;
-  SpeakerIdEnrollmentClientMock(const SpeakerIdEnrollmentClientMock&) = delete;
-  SpeakerIdEnrollmentClientMock& operator=(
-      const SpeakerIdEnrollmentClientMock&) = delete;
-  ~SpeakerIdEnrollmentClientMock() override = default;
-
-  ::mojo::PendingRemote<SpeakerIdEnrollmentClient> BindNewPipeAndPassRemote() {
-    return receiver_.BindNewPipeAndPassRemote();
-  }
-
-  // mojom::SpeakerIdEnrollmentClient implementation:
-  MOCK_METHOD(void, OnListeningHotword, ());
-  MOCK_METHOD(void, OnProcessingHotword, ());
-  MOCK_METHOD(void, OnSpeakerIdEnrollmentDone, ());
-  MOCK_METHOD(void, OnSpeakerIdEnrollmentFailure, ());
-
-  void FlushForTesting() { receiver_.FlushForTesting(); }
-
- private:
-  ::mojo::Receiver<mojom::SpeakerIdEnrollmentClient> receiver_{this};
-};
-}  // namespace
-
-class AssistantSpeakerIdEnrollmentControllerTest : public ::testing::Test {
- public:
-  AssistantSpeakerIdEnrollmentControllerTest() = default;
-  AssistantSpeakerIdEnrollmentControllerTest(
-      const AssistantSpeakerIdEnrollmentControllerTest&) = delete;
-  AssistantSpeakerIdEnrollmentControllerTest& operator=(
-      const AssistantSpeakerIdEnrollmentControllerTest&) = delete;
-  ~AssistantSpeakerIdEnrollmentControllerTest() override = default;
-
-  mojom::SpeakerIdEnrollmentController& controller() {
-    return service_tester_.speaker_id_enrollment_controller();
-  }
-
-  void FlushForTesting() { service_tester_.FlushForTesting(); }
-
-  LibassistantServiceTester& service_tester() { return service_tester_; }
-
-  assistant_client::SpeakerIdEnrollmentUpdate CreateUpdate(
-      SpeakerIdEnrollmentState state) {
-    assistant_client::SpeakerIdEnrollmentUpdate result;
-    result.state = state;
-    return result;
-  }
-
-  bool IsSpeakerIdEnrollmentInProgress() {
-    return service_tester_.service()
-        .speaker_id_enrollment_controller_for_testing()
-        .IsSpeakerIdEnrollmentInProgressForTesting();
-  }
-
-  void CallUpdateCallback(
-      const ::assistant_client::SpeakerIdEnrollmentUpdate& update) {
-    ::assistant::api::OnSpeakerIdEnrollmentEventRequest request;
-    ::assistant::api::events::SpeakerIdEnrollmentEvent* event =
-        request.mutable_event();
-    switch (update.state) {
-      case ::assistant_client::SpeakerIdEnrollmentUpdate::State::INIT: {
-        event->mutable_init_state();
-        break;
-      }
-      case ::assistant_client::SpeakerIdEnrollmentUpdate::State::CHECK: {
-        event->mutable_check_state();
-        break;
-      }
-      case ::assistant_client::SpeakerIdEnrollmentUpdate::State::LISTEN: {
-        event->mutable_listen_state();
-        break;
-      }
-      case ::assistant_client::SpeakerIdEnrollmentUpdate::State::PROCESS: {
-        event->mutable_process_state();
-        break;
-      }
-      case ::assistant_client::SpeakerIdEnrollmentUpdate::State::UPLOAD: {
-        event->mutable_upload_state();
-        break;
-      }
-      case ::assistant_client::SpeakerIdEnrollmentUpdate::State::FETCH: {
-        event->mutable_fetch_state();
-        break;
-      }
-      case ::assistant_client::SpeakerIdEnrollmentUpdate::State::DONE: {
-        event->mutable_done_state();
-        break;
-      }
-      case ::assistant_client::SpeakerIdEnrollmentUpdate::State::FAILURE: {
-        event->mutable_failure_state();
-        break;
-      }
-    }
-
-    service_tester_.service()
-        .speaker_id_enrollment_controller_for_testing()
-        .OnGrpcMessageForTesting(std::move(request));
-  }
-
-  void CallGetStatusCallback(bool user_model_exists) {
-    service_tester_.service()
-        .speaker_id_enrollment_controller_for_testing()
-        .SendGetStatusResponseForTesting(user_model_exists);
-  }
-
- private:
-  base::test::SingleThreadTaskEnvironment environment_;
-  LibassistantServiceTester service_tester_;
-};
-
-TEST_F(AssistantSpeakerIdEnrollmentControllerTest,
-       StartShouldBeANoopIfLibassistantIsNotStarted) {
-  StrictMock<SpeakerIdEnrollmentClientMock> client;
-
-  controller().StartSpeakerIdEnrollment("user-id",
-                                        /*skip_cloud_enrollment=*/false,
-                                        client.BindNewPipeAndPassRemote());
-
-  FlushForTesting();
-
-  EXPECT_FALSE(IsSpeakerIdEnrollmentInProgress());
-}
-
-TEST_F(AssistantSpeakerIdEnrollmentControllerTest,
-       StopShouldBeANoopIfLibassistantIsNotStarted) {
-  controller().StopSpeakerIdEnrollment();
-
-  FlushForTesting();
-}
-
-TEST_F(AssistantSpeakerIdEnrollmentControllerTest,
-       ShouldBeAbleToStartEnrollment) {
-  service_tester().Start();
-  StrictMock<SpeakerIdEnrollmentClientMock> client;
-
-  controller().StartSpeakerIdEnrollment("user-id",
-                                        /*skip_cloud_enrollment=*/false,
-                                        client.BindNewPipeAndPassRemote());
-
-  FlushForTesting();
-
-  EXPECT_TRUE(IsSpeakerIdEnrollmentInProgress());
-}
-
-TEST_F(AssistantSpeakerIdEnrollmentControllerTest,
-       ShouldBeAbleToStopEnrollment) {
-  service_tester().Start();
-  StrictMock<SpeakerIdEnrollmentClientMock> client;
-
-  controller().StartSpeakerIdEnrollment("user-id",
-                                        /*skip_cloud_enrollment=*/false,
-                                        client.BindNewPipeAndPassRemote());
-  controller().StopSpeakerIdEnrollment();
-
-  FlushForTesting();
-
-  EXPECT_FALSE(IsSpeakerIdEnrollmentInProgress());
-}
-
-TEST_F(AssistantSpeakerIdEnrollmentControllerTest,
-       ShouldPassEnrollmentUpdatesToClient) {
-  service_tester().Start();
-  StrictMock<SpeakerIdEnrollmentClientMock> client;
-
-  controller().StartSpeakerIdEnrollment("user-id",
-                                        /*skip_cloud_enrollment=*/false,
-                                        client.BindNewPipeAndPassRemote());
-  FlushForTesting();
-  EXPECT_TRUE(IsSpeakerIdEnrollmentInProgress());
-
-  // These are ignored
-  CallUpdateCallback(CreateUpdate(SpeakerIdEnrollmentState::INIT));
-  CallUpdateCallback(CreateUpdate(SpeakerIdEnrollmentState::CHECK));
-  CallUpdateCallback(CreateUpdate(SpeakerIdEnrollmentState::UPLOAD));
-  CallUpdateCallback(CreateUpdate(SpeakerIdEnrollmentState::FETCH));
-  client.FlushForTesting();
-
-  EXPECT_CALL(client, OnListeningHotword);
-  CallUpdateCallback(CreateUpdate(SpeakerIdEnrollmentState::LISTEN));
-  client.FlushForTesting();
-
-  EXPECT_CALL(client, OnProcessingHotword);
-  CallUpdateCallback(CreateUpdate(SpeakerIdEnrollmentState::PROCESS));
-  client.FlushForTesting();
-
-  EXPECT_CALL(client, OnSpeakerIdEnrollmentDone);
-  CallUpdateCallback(CreateUpdate(SpeakerIdEnrollmentState::DONE));
-  client.FlushForTesting();
-
-  EXPECT_CALL(client, OnSpeakerIdEnrollmentFailure);
-  CallUpdateCallback(CreateUpdate(SpeakerIdEnrollmentState::FAILURE));
-  client.FlushForTesting();
-}
-
-TEST_F(AssistantSpeakerIdEnrollmentControllerTest,
-       ShouldStartSecondEnrollmentEvenIfFirstIsOngoing) {
-  service_tester().Start();
-
-  StrictMock<SpeakerIdEnrollmentClientMock> first_client;
-  StrictMock<SpeakerIdEnrollmentClientMock> second_client;
-
-  controller().StartSpeakerIdEnrollment(
-      "first user",
-      /*skip_cloud_enrollment=*/false, first_client.BindNewPipeAndPassRemote());
-
-  controller().StartSpeakerIdEnrollment(
-      "second user",
-      /*skip_cloud_enrollment=*/false,
-      second_client.BindNewPipeAndPassRemote());
-
-  FlushForTesting();
-
-  EXPECT_CALL(second_client, OnProcessingHotword);
-  CallUpdateCallback(CreateUpdate(SpeakerIdEnrollmentState::PROCESS));
-
-  first_client.FlushForTesting();
-  second_client.FlushForTesting();
-}
-
-TEST_F(
-    AssistantSpeakerIdEnrollmentControllerTest,
-    GetSpeakerIdEnrollmentStatusShouldReturnFalseIfLibassistantIsNotStarted) {
-  base::MockCallback<GetSpeakerIdEnrollmentStatusCallback> callback;
-
-  EXPECT_CALL(callback, Run).WillOnce([](auto response) {
-    EXPECT_FALSE(response->user_model_exists);
-  });
-
-  controller().GetSpeakerIdEnrollmentStatus("user-id", callback.Get());
-
-  FlushForTesting();
-}
-
-TEST_F(AssistantSpeakerIdEnrollmentControllerTest,
-       ShouldReturnSpeakerIdEnrollmentStatus) {
-  service_tester().Start();
-
-  base::MockCallback<GetSpeakerIdEnrollmentStatusCallback> callback;
-  EXPECT_CALL(callback, Run).WillOnce([](auto response) {
-    EXPECT_TRUE(response->user_model_exists);
-  });
-
-  controller().GetSpeakerIdEnrollmentStatus("user-id", callback.Get());
-  FlushForTesting();
-
-  CallGetStatusCallback(/*user_model_exists=*/true);
-  FlushForTesting();
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/speech_recognition_observer_unittest.cc b/chromeos/ash/services/libassistant/speech_recognition_observer_unittest.cc
deleted file mode 100644
index ede2899..0000000
--- a/chromeos/ash/services/libassistant/speech_recognition_observer_unittest.cc
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/test/task_environment.h"
-#include "chromeos/ash/services/libassistant/display_connection.h"
-#include "chromeos/ash/services/libassistant/libassistant_service.h"
-#include "chromeos/ash/services/libassistant/public/mojom/speech_recognition_observer.mojom.h"
-#include "chromeos/ash/services/libassistant/test_support/libassistant_service_tester.h"
-#include "chromeos/assistant/internal/internal_util.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/proto/assistant/display_connection.pb.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/display_interface.pb.h"
-#include "chromeos/assistant/internal/test_support/fake_assistant_manager.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-using RecognitionState =
-    assistant_client::ConversationStateListener::RecognitionState;
-using RecognitionResult =
-    assistant_client::ConversationStateListener::RecognitionResult;
-
-std::string CreateDisplayAssistantEvent(float speech_level) {
-  ::assistant::display::AssistantEvent result;
-  result.mutable_speech_level_event()->set_speech_level(speech_level);
-  return result.SerializeAsString();
-}
-
-class SpeechRecognitionObserverMock : public mojom::SpeechRecognitionObserver {
- public:
-  SpeechRecognitionObserverMock() = default;
-  SpeechRecognitionObserverMock(const SpeechRecognitionObserverMock&) = delete;
-  SpeechRecognitionObserverMock& operator=(
-      const SpeechRecognitionObserverMock&) = delete;
-  ~SpeechRecognitionObserverMock() override = default;
-
-  // mojom::SpeechRecognitionObserver implementation:
-  MOCK_METHOD(void, OnSpeechLevelUpdated, (float speech_level_in_decibels));
-  MOCK_METHOD(void, OnSpeechRecognitionStart, ());
-  MOCK_METHOD(void,
-              OnIntermediateResult,
-              (const std::string& high_confidence_text,
-               const std::string& low_confidence_text));
-  MOCK_METHOD(void, OnSpeechRecognitionEnd, ());
-  MOCK_METHOD(void, OnFinalResult, (const std::string& recognized_text));
-
-  mojo::PendingRemote<mojom::SpeechRecognitionObserver>
-  BindNewPipeAndPassRemote() {
-    return receiver_.BindNewPipeAndPassRemote();
-  }
-
-  void FlushForTesting() { receiver_.FlushForTesting(); }
-
- private:
-  mojo::Receiver<mojom::SpeechRecognitionObserver> receiver_{this};
-};
-
-}  // namespace
-
-class AssistantSpeechRecognitionObserverTest : public ::testing::Test {
- public:
-  AssistantSpeechRecognitionObserverTest() = default;
-  AssistantSpeechRecognitionObserverTest(
-      const AssistantSpeechRecognitionObserverTest&) = delete;
-  AssistantSpeechRecognitionObserverTest& operator=(
-      const AssistantSpeechRecognitionObserverTest&) = delete;
-  ~AssistantSpeechRecognitionObserverTest() override = default;
-
-  void SetUp() override {
-    service_tester_.service().AddSpeechRecognitionObserver(
-        observer_mock_.BindNewPipeAndPassRemote());
-
-    service_tester_.Start();
-  }
-
-  SpeechRecognitionObserverMock& observer_mock() { return observer_mock_; }
-
-  assistant_client::ConversationStateListener& conversation_state_listener() {
-    return *service_tester_.assistant_manager().conversation_state_listener();
-  }
-
-  void SendDisplayConnectionEvent(const std::string& event) {
-    ::assistant::api::OnAssistantDisplayEventRequest request;
-    auto* assistant_display_event = request.mutable_event();
-    auto* on_assistant_event =
-        assistant_display_event->mutable_on_assistant_event();
-    on_assistant_event->set_assistant_event_bytes(event);
-    service_tester_.GetDisplayConnection().OnGrpcMessage(request);
-  }
-
- private:
-  base::test::SingleThreadTaskEnvironment environment_;
-  ::testing::StrictMock<SpeechRecognitionObserverMock> observer_mock_;
-  LibassistantServiceTester service_tester_;
-};
-
-TEST_F(AssistantSpeechRecognitionObserverTest,
-       ShouldReceiveSpeechLevelUpdates) {
-  EXPECT_CALL(observer_mock(), OnSpeechLevelUpdated(0.5));
-  SendDisplayConnectionEvent(CreateDisplayAssistantEvent(/*speech_level=*/0.5));
-  observer_mock().FlushForTesting();
-}
-
-TEST_F(AssistantSpeechRecognitionObserverTest,
-       ShouldReceiveOnSpeechRecognitionStartEvent) {
-  EXPECT_CALL(observer_mock(), OnSpeechRecognitionStart());
-
-  conversation_state_listener().OnRecognitionStateChanged(
-      RecognitionState::STARTED, RecognitionResult());
-  observer_mock().FlushForTesting();
-}
-
-TEST_F(AssistantSpeechRecognitionObserverTest,
-       ShouldReceiveOnSpeechRecognitionEndEvent) {
-  EXPECT_CALL(observer_mock(), OnSpeechRecognitionEnd());
-
-  conversation_state_listener().OnRecognitionStateChanged(
-      RecognitionState::END_OF_UTTERANCE, RecognitionResult());
-  observer_mock().FlushForTesting();
-}
-
-TEST_F(AssistantSpeechRecognitionObserverTest,
-       ShouldReceiveOnIntermediateResultEvent) {
-  EXPECT_CALL(observer_mock(), OnIntermediateResult("high-confidence-text",
-                                                    "low-confidence-text"));
-
-  RecognitionResult recognition_result;
-  recognition_result.high_confidence_text = "high-confidence-text";
-  recognition_result.low_confidence_text = "low-confidence-text";
-  conversation_state_listener().OnRecognitionStateChanged(
-      RecognitionState::INTERMEDIATE_RESULT, recognition_result);
-  observer_mock().FlushForTesting();
-}
-
-TEST_F(AssistantSpeechRecognitionObserverTest,
-       ShouldReceiveOnFinalResultEvent) {
-  EXPECT_CALL(observer_mock(), OnFinalResult("recognized-speech"));
-
-  RecognitionResult recognition_result;
-  recognition_result.recognized_speech = "recognized-speech";
-  conversation_state_listener().OnRecognitionStateChanged(
-      RecognitionState::FINAL_RESULT, recognition_result);
-  observer_mock().FlushForTesting();
-}
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/system_provider_impl.cc b/chromeos/ash/services/libassistant/system_provider_impl.cc
deleted file mode 100644
index 07f8d392..0000000
--- a/chromeos/ash/services/libassistant/system_provider_impl.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/system_provider_impl.h"
-
-#include <utility>
-
-#include "base/functional/bind.h"
-#include "base/strings/string_util.h"
-#include "base/system/sys_info.h"
-#include "chromeos/ash/services/libassistant/power_manager_provider_impl.h"
-
-namespace ash::libassistant {
-
-SystemProviderImpl::SystemProviderImpl(
-    std::unique_ptr<PowerManagerProviderImpl> power_manager_provider)
-    : power_manager_provider_(std::move(power_manager_provider)) {}
-
-SystemProviderImpl::~SystemProviderImpl() = default;
-
-void SystemProviderImpl::Initialize(
-    mojom::PlatformDelegate* platform_delegate) {
-  if (power_manager_provider_)
-    power_manager_provider_->Initialize(platform_delegate);
-
-  platform_delegate->BindBatteryMonitor(
-      battery_monitor_.BindNewPipeAndPassReceiver());
-  battery_monitor_->QueryNextStatus(base::BindOnce(
-      &SystemProviderImpl::OnBatteryStatus, base::Unretained(this)));
-}
-
-assistant_client::MicMuteState SystemProviderImpl::GetMicMuteState() {
-  // CRAS input is never muted.
-  return assistant_client::MicMuteState::MICROPHONE_ENABLED;
-}
-
-void SystemProviderImpl::RegisterMicMuteChangeCallback(
-    ConfigChangeCallback callback) {
-  // No need to register since it will never change.
-}
-
-assistant_client::PowerManagerProvider*
-SystemProviderImpl::GetPowerManagerProvider() {
-  return power_manager_provider_.get();
-}
-
-bool SystemProviderImpl::GetBatteryState(BatteryState* state) {
-  if (!current_battery_status_)
-    return false;
-
-  state->is_charging = current_battery_status_->charging;
-  state->charge_percentage =
-      static_cast<int>(current_battery_status_->level * 100);
-  return true;
-}
-
-void SystemProviderImpl::UpdateTimezoneAndLocale(const std::string& timezone,
-                                                 const std::string& locale) {}
-
-void SystemProviderImpl::OnBatteryStatus(
-    device::mojom::BatteryStatusPtr battery_status) {
-  current_battery_status_ = std::move(battery_status);
-
-  // Battery monitor is one shot, send another query to get battery status
-  // updates. This query will only return when a status changes.
-  battery_monitor_->QueryNextStatus(base::BindOnce(
-      &SystemProviderImpl::OnBatteryStatus, base::Unretained(this)));
-}
-
-void SystemProviderImpl::FlushForTesting() {
-  battery_monitor_.FlushForTesting();  // IN-TEST
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/system_provider_impl.h b/chromeos/ash/services/libassistant/system_provider_impl.h
deleted file mode 100644
index cfaeeec..0000000
--- a/chromeos/ash/services/libassistant/system_provider_impl.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_SYSTEM_PROVIDER_IMPL_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_SYSTEM_PROVIDER_IMPL_H_
-
-#include <memory>
-#include <string>
-
-#include "base/component_export.h"
-#include "chromeos/ash/services/libassistant/public/mojom/platform_delegate.mojom.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "services/device/public/mojom/battery_monitor.mojom.h"
-#include "services/device/public/mojom/battery_status.mojom.h"
-
-namespace ash::libassistant {
-
-class PowerManagerProviderImpl;
-
-class SystemProviderImpl : public assistant_client::SystemProvider {
- public:
-  // Acceptable to pass in |nullptr| for |power_manager_provider| when no
-  // platform power manager provider is available.
-  explicit SystemProviderImpl(
-      std::unique_ptr<PowerManagerProviderImpl> power_manager_provider);
-
-  SystemProviderImpl(const SystemProviderImpl&) = delete;
-  SystemProviderImpl& operator=(const SystemProviderImpl&) = delete;
-
-  ~SystemProviderImpl() override;
-
-  void Initialize(mojom::PlatformDelegate* platform_delegate);
-
-  // assistant_client::SystemProvider implementation:
-  assistant_client::MicMuteState GetMicMuteState() override;
-  void RegisterMicMuteChangeCallback(ConfigChangeCallback callback) override;
-  assistant_client::PowerManagerProvider* GetPowerManagerProvider() override;
-  bool GetBatteryState(BatteryState* state) override;
-  void UpdateTimezoneAndLocale(const std::string& timezone,
-                               const std::string& locale) override;
-
- private:
-  friend class AssistantSystemProviderImplTest;
-  void OnBatteryStatus(device::mojom::BatteryStatusPtr battery_status);
-
-  void FlushForTesting();
-
-  std::unique_ptr<PowerManagerProviderImpl> power_manager_provider_;
-
-  mojo::Remote<device::mojom::BatteryMonitor> battery_monitor_;
-  device::mojom::BatteryStatusPtr current_battery_status_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_SYSTEM_PROVIDER_IMPL_H_
diff --git a/chromeos/ash/services/libassistant/system_provider_impl_unittest.cc b/chromeos/ash/services/libassistant/system_provider_impl_unittest.cc
deleted file mode 100644
index c9f0a10..0000000
--- a/chromeos/ash/services/libassistant/system_provider_impl_unittest.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/system_provider_impl.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/test/task_environment.h"
-#include "chromeos/ash/services/libassistant/power_manager_provider_impl.h"
-#include "chromeos/ash/services/libassistant/test_support/fake_platform_delegate.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "services/device/public/mojom/battery_monitor.mojom.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::libassistant {
-
-class FakeBatteryMonitor : device::mojom::BatteryMonitor {
- public:
-  FakeBatteryMonitor() = default;
-
-  FakeBatteryMonitor(const FakeBatteryMonitor&) = delete;
-  FakeBatteryMonitor& operator=(const FakeBatteryMonitor&) = delete;
-
-  void Bind(
-      mojo::PendingReceiver<::device::mojom::BatteryMonitor> pending_receiver) {
-    receiver_.Bind(std::move(pending_receiver));
-  }
-
-  void QueryNextStatus(QueryNextStatusCallback callback) override {
-    if (has_status) {
-      std::move(callback).Run(std::move(battery_status_));
-      has_status = false;
-    } else {
-      callback_ = std::move(callback);
-    }
-  }
-
-  void SetStatus(device::mojom::BatteryStatusPtr battery_status) {
-    battery_status_ = std::move(battery_status);
-    has_status = true;
-
-    if (callback_) {
-      std::move(callback_).Run(std::move(battery_status_));
-      has_status = false;
-    }
-  }
-
- private:
-  bool has_status = false;
-
-  device::mojom::BatteryStatusPtr battery_status_;
-  QueryNextStatusCallback callback_;
-
-  mojo::Receiver<device::mojom::BatteryMonitor> receiver_{this};
-};
-
-class AssistantSystemProviderImplTest : public testing::Test {
- public:
-  AssistantSystemProviderImplTest()
-      : task_environment_(base::test::TaskEnvironment::MainThreadType::UI) {
-    battery_monitor_.SetStatus(device::mojom::BatteryStatus::New(
-        false /* charging */, 0 /* charging_time */, 0 /* discharging_time */,
-        0 /* level */));
-
-    system_provider_impl_ = std::make_unique<SystemProviderImpl>(
-        std::make_unique<PowerManagerProviderImpl>());
-    system_provider_impl_->Initialize(&platform_delegate_);
-    battery_monitor_.Bind(platform_delegate_.battery_monitor_receiver());
-    FlushForTesting();
-  }
-  AssistantSystemProviderImplTest(const AssistantSystemProviderImplTest&) =
-      delete;
-  AssistantSystemProviderImplTest& operator=(
-      const AssistantSystemProviderImplTest&) = delete;
-
-  SystemProviderImpl* system_provider() { return system_provider_impl_.get(); }
-
-  FakeBatteryMonitor* battery_monitor() { return &battery_monitor_; }
-
-  void FlushForTesting() { system_provider_impl_->FlushForTesting(); }
-
- private:
-  base::test::TaskEnvironment task_environment_;
-  FakeBatteryMonitor battery_monitor_;
-  assistant::FakePlatformDelegate platform_delegate_;
-  std::unique_ptr<SystemProviderImpl> system_provider_impl_;
-};
-
-TEST_F(AssistantSystemProviderImplTest, GetBatteryStateReturnsLastState) {
-  SystemProviderImpl::BatteryState state;
-  // Initial level is 0
-  system_provider()->GetBatteryState(&state);
-  FlushForTesting();
-
-  EXPECT_EQ(state.charge_percentage, 0);
-  battery_monitor()->SetStatus(device::mojom::BatteryStatus::New(
-      false /* charging */, 0 /* charging_time */, 0 /* discharging_time */,
-      1 /* level */));
-
-  FlushForTesting();
-  // New level after status change
-  system_provider()->GetBatteryState(&state);
-  EXPECT_EQ(state.charge_percentage, 100);
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/test_support/fake_assistant_client.cc b/chromeos/ash/services/libassistant/test_support/fake_assistant_client.cc
deleted file mode 100644
index 7f87332..0000000
--- a/chromeos/ash/services/libassistant/test_support/fake_assistant_client.cc
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/test_support/fake_assistant_client.h"
-
-#include "base/functional/callback.h"
-#include "base/test/bind.h"
-#include "chromeos/ash/services/libassistant/grpc/utils/timer_utils.h"
-#include "chromeos/ash/services/libassistant/public/cpp/assistant_timer.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_interface.pb.h"
-
-namespace ash::libassistant {
-
-FakeAssistantClient::FakeAssistantClient(
-    std::unique_ptr<chromeos::assistant::FakeAssistantManager>
-        assistant_manager)
-    : AssistantClient(std::move(assistant_manager)) {}
-
-FakeAssistantClient::~FakeAssistantClient() = default;
-
-void FakeAssistantClient::StartServices(
-    ServicesStatusObserver* services_status_observer) {}
-
-bool FakeAssistantClient::StartGrpcServices() {
-  return true;
-}
-
-void FakeAssistantClient::StartGrpcHttpConnectionClient(
-    assistant_client::HttpConnectionFactory*) {}
-
-void FakeAssistantClient::AddExperimentIds(
-    const std::vector<std::string>& exp_ids) {}
-
-void FakeAssistantClient::AddSpeakerIdEnrollmentEventObserver(
-    GrpcServicesObserver<OnSpeakerIdEnrollmentEventRequest>* observer) {}
-
-void FakeAssistantClient::RemoveSpeakerIdEnrollmentEventObserver(
-    GrpcServicesObserver<OnSpeakerIdEnrollmentEventRequest>* observer) {}
-
-void FakeAssistantClient::StartSpeakerIdEnrollment(
-    const StartSpeakerIdEnrollmentRequest& request) {}
-
-void FakeAssistantClient::CancelSpeakerIdEnrollment(
-    const CancelSpeakerIdEnrollmentRequest& request) {}
-
-void FakeAssistantClient::GetSpeakerIdEnrollmentInfo(
-    const GetSpeakerIdEnrollmentInfoRequest& request,
-    base::OnceCallback<void(bool user_model_exists)> on_done) {
-  std::move(on_done).Run(false);
-}
-
-void FakeAssistantClient::ResetAllDataAndShutdown() {}
-
-void FakeAssistantClient::SendDisplayRequest(
-    const OnDisplayRequestRequest& request) {}
-
-void FakeAssistantClient::AddDisplayEventObserver(
-    GrpcServicesObserver<OnAssistantDisplayEventRequest>* observer) {}
-
-void FakeAssistantClient::ResumeCurrentStream() {}
-
-void FakeAssistantClient::PauseCurrentStream() {}
-
-void FakeAssistantClient::SetExternalPlaybackState(
-    const MediaStatus& status_proto) {}
-
-void FakeAssistantClient::AddDeviceStateEventObserver(
-    GrpcServicesObserver<OnDeviceStateEventRequest>* observer) {}
-
-void FakeAssistantClient::SendVoicelessInteraction(
-    const ::assistant::api::Interaction& interaction,
-    const std::string& description,
-    const ::assistant::api::VoicelessOptions& options,
-    base::OnceCallback<void(bool)> on_done) {}
-
-void FakeAssistantClient::RegisterActionModule(
-    assistant_client::ActionModule* action_module) {}
-
-void FakeAssistantClient::StartVoiceInteraction() {}
-
-void FakeAssistantClient::StopAssistantInteraction(bool cancel_conversation) {}
-
-void FakeAssistantClient::AddConversationStateEventObserver(
-    GrpcServicesObserver<OnConversationStateEventRequest>* observer) {}
-
-void FakeAssistantClient::AddMediaActionFallbackEventObserver(
-    GrpcServicesObserver<OnMediaActionFallbackEventRequest>* observer) {}
-
-void FakeAssistantClient::SetInternalOptions(const std::string& locale,
-                                             bool spoken_feedback_enabled) {}
-
-void FakeAssistantClient::SetAuthenticationInfo(const AuthTokens& tokens) {}
-
-void FakeAssistantClient::UpdateAssistantSettings(
-    const ::assistant::ui::SettingsUiUpdate& settings,
-    const std::string& user_id,
-    base::OnceCallback<void(
-        const ::assistant::api::UpdateAssistantSettingsResponse&)> on_done) {}
-
-void FakeAssistantClient::GetAssistantSettings(
-    const ::assistant::ui::SettingsUiSelector& selector,
-    const std::string& user_id,
-    base::OnceCallback<
-        void(const ::assistant::api::GetAssistantSettingsResponse&)> on_done) {}
-
-void FakeAssistantClient::SetLocaleOverride(const std::string& locale) {}
-
-std::string FakeAssistantClient::GetDeviceId() {
-  return assistant_manager()->GetDeviceId();
-}
-
-void FakeAssistantClient::EnableListening(bool listening_enabled) {}
-
-void FakeAssistantClient::AddTimeToTimer(const std::string& id,
-                                         const base::TimeDelta& duration) {
-}
-
-void FakeAssistantClient::PauseTimer(const std::string& timer_id) {
-}
-
-void FakeAssistantClient::RemoveTimer(const std::string& timer_id) {
-}
-
-void FakeAssistantClient::ResumeTimer(const std::string& timer_id) {
-}
-
-void FakeAssistantClient::GetTimers(
-    base::OnceCallback<void(const std::vector<assistant::AssistantTimer>&)>
-        on_done) {
-}
-
-void FakeAssistantClient::AddAlarmTimerEventObserver(
-    GrpcServicesObserver<::assistant::api::OnAlarmTimerEventRequest>*
-        observer) {
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/test_support/fake_assistant_client.h b/chromeos/ash/services/libassistant/test_support/fake_assistant_client.h
deleted file mode 100644
index aeed826..0000000
--- a/chromeos/ash/services/libassistant/test_support/fake_assistant_client.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_TEST_SUPPORT_FAKE_ASSISTANT_CLIENT_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_TEST_SUPPORT_FAKE_ASSISTANT_CLIENT_H_
-
-#include "base/memory/raw_ptr.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client.h"
-#include "chromeos/assistant/internal/test_support/fake_assistant_manager.h"
-
-namespace ash::libassistant {
-
-class FakeAssistantClient : public AssistantClient {
- public:
-  FakeAssistantClient(std::unique_ptr<chromeos::assistant::FakeAssistantManager>
-                          assistant_manager);
-  ~FakeAssistantClient() override;
-
-  // AssistantClient:
-  chromeos::assistant::FakeAssistantManager* assistant_manager() {
-    return reinterpret_cast<chromeos::assistant::FakeAssistantManager*>(
-        AssistantClient::assistant_manager());
-  }
-
-  void StartServices(ServicesStatusObserver* services_status_observer) override;
-  bool StartGrpcServices() override;
-  void StartGrpcHttpConnectionClient(
-      assistant_client::HttpConnectionFactory*) override;
-  void AddExperimentIds(const std::vector<std::string>& exp_ids) override;
-  void AddSpeakerIdEnrollmentEventObserver(
-      GrpcServicesObserver<OnSpeakerIdEnrollmentEventRequest>* observer)
-      override;
-  void RemoveSpeakerIdEnrollmentEventObserver(
-      GrpcServicesObserver<OnSpeakerIdEnrollmentEventRequest>* observer)
-      override;
-  void StartSpeakerIdEnrollment(
-      const StartSpeakerIdEnrollmentRequest& request) override;
-  void CancelSpeakerIdEnrollment(
-      const CancelSpeakerIdEnrollmentRequest& request) override;
-  void GetSpeakerIdEnrollmentInfo(
-      const GetSpeakerIdEnrollmentInfoRequest& request,
-      base::OnceCallback<void(bool user_model_exists)> on_done) override;
-  void ResetAllDataAndShutdown() override;
-  void SendDisplayRequest(const OnDisplayRequestRequest& request) override;
-  void AddDisplayEventObserver(
-      GrpcServicesObserver<OnAssistantDisplayEventRequest>* observer) override;
-  void ResumeCurrentStream() override;
-  void PauseCurrentStream() override;
-  void SetExternalPlaybackState(const MediaStatus& status_proto) override;
-  void AddDeviceStateEventObserver(
-      GrpcServicesObserver<OnDeviceStateEventRequest>* observer) override;
-  void AddMediaActionFallbackEventObserver(
-      GrpcServicesObserver<OnMediaActionFallbackEventRequest>* observer)
-      override;
-  void SendVoicelessInteraction(
-      const ::assistant::api::Interaction& interaction,
-      const std::string& description,
-      const ::assistant::api::VoicelessOptions& options,
-      base::OnceCallback<void(bool)> on_done) override;
-  void RegisterActionModule(
-      assistant_client::ActionModule* action_module) override;
-  void StartVoiceInteraction() override;
-  void StopAssistantInteraction(bool cancel_conversation) override;
-  void AddConversationStateEventObserver(
-      GrpcServicesObserver<OnConversationStateEventRequest>* observer) override;
-  void SetInternalOptions(const std::string& locale,
-                          bool spoken_feedback_enabled) override;
-  void SetAuthenticationInfo(const AuthTokens& tokens) override;
-  void UpdateAssistantSettings(
-      const ::assistant::ui::SettingsUiUpdate& settings,
-      const std::string& user_id,
-      base::OnceCallback<void(
-          const ::assistant::api::UpdateAssistantSettingsResponse&)> on_done)
-      override;
-  void GetAssistantSettings(
-      const ::assistant::ui::SettingsUiSelector& selector,
-      const std::string& user_id,
-      base::OnceCallback<
-          void(const ::assistant::api::GetAssistantSettingsResponse&)> on_done)
-      override;
-  void SetLocaleOverride(const std::string& locale) override;
-  std::string GetDeviceId() override;
-  void EnableListening(bool listening_enabled) override;
-  void AddTimeToTimer(const std::string& id,
-                      const base::TimeDelta& duration) override;
-  void PauseTimer(const std::string& timer_id) override;
-  void RemoveTimer(const std::string& timer_id) override;
-  void ResumeTimer(const std::string& timer_id) override;
-  void GetTimers(
-      base::OnceCallback<void(const std::vector<assistant::AssistantTimer>&)>
-          on_done) override;
-  void AddAlarmTimerEventObserver(
-      GrpcServicesObserver<::assistant::api::OnAlarmTimerEventRequest>*
-          observer) override;
-
- private:
-  void GetAndNotifyTimerStatus();
-
-  raw_ptr<GrpcServicesObserver<::assistant::api::OnAlarmTimerEventRequest>>
-      timer_observer_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_TEST_SUPPORT_FAKE_ASSISTANT_CLIENT_H_
diff --git a/chromeos/ash/services/libassistant/test_support/fake_libassistant_factory.cc b/chromeos/ash/services/libassistant/test_support/fake_libassistant_factory.cc
deleted file mode 100644
index 10f259a9..0000000
--- a/chromeos/ash/services/libassistant/test_support/fake_libassistant_factory.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/test_support/fake_libassistant_factory.h"
-
-#include "chromeos/assistant/internal/test_support/fake_assistant_manager.h"
-
-namespace ash::libassistant {
-
-FakeLibassistantFactory::FakeLibassistantFactory() {
-  // We start by creating a pending assistant manager, as our unittests
-  // might need to access the assistant manager before it is created through
-  // CreateAssistantManager() (for example to set expectations).
-  pending_assistant_manager_ =
-      std::make_unique<chromeos::assistant::FakeAssistantManager>();
-}
-
-FakeLibassistantFactory::~FakeLibassistantFactory() = default;
-
-std::unique_ptr<assistant_client::AssistantManager>
-FakeLibassistantFactory::CreateAssistantManager(
-    const std::string& libassistant_config) {
-  auto result = std::move(pending_assistant_manager_);
-  if (!result) {
-    // We come here if this is not the first call to CreateAssistantManager().
-    result = std::make_unique<chromeos::assistant::FakeAssistantManager>();
-  }
-
-  // Keep a pointer around so our unittests can still retrieve it.
-  current_assistant_manager_ = result.get();
-  libassistant_config_ = libassistant_config;
-
-  return result;
-}
-
-chromeos::assistant::FakeAssistantManager&
-FakeLibassistantFactory::assistant_manager() {
-  if (current_assistant_manager_)
-    return *current_assistant_manager_;
-
-  // We should only come here if CreateAssistantManager() has not been called
-  // yet. In that case we return a pointer to the pending assistant manager
-  // instead.
-  DCHECK(pending_assistant_manager_);
-  return *pending_assistant_manager_;
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/test_support/fake_libassistant_factory.h b/chromeos/ash/services/libassistant/test_support/fake_libassistant_factory.h
deleted file mode 100644
index 4630d0b..0000000
--- a/chromeos/ash/services/libassistant/test_support/fake_libassistant_factory.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_TEST_SUPPORT_FAKE_LIBASSISTANT_FACTORY_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_TEST_SUPPORT_FAKE_LIBASSISTANT_FACTORY_H_
-
-#include "base/memory/raw_ptr.h"
-#include "chromeos/ash/services/libassistant/libassistant_factory.h"
-
-#include "base/component_export.h"
-
-namespace chromeos {
-namespace assistant {
-class FakeAssistantManager;
-}  // namespace assistant
-}  // namespace chromeos
-
-namespace ash::libassistant {
-
-// Implementation of |LibassistantFactory| that returns fake
-// instances for all of the member methods. Used during unittests.
-class FakeLibassistantFactory : public LibassistantFactory {
- public:
-  FakeLibassistantFactory();
-  ~FakeLibassistantFactory() override;
-
-  chromeos::assistant::FakeAssistantManager& assistant_manager();
-
-  // LibassistantFactory implementation:
-  std::unique_ptr<assistant_client::AssistantManager> CreateAssistantManager(
-      const std::string& libassistant_config) override;
-
-  std::string libassistant_config() const { return libassistant_config_; }
-
- private:
-  std::unique_ptr<chromeos::assistant::FakeAssistantManager>
-      pending_assistant_manager_;
-  raw_ptr<chromeos::assistant::FakeAssistantManager>
-      current_assistant_manager_ = nullptr;
-
-  // Config passed to LibAssistant when it was started.
-  std::string libassistant_config_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_TEST_SUPPORT_FAKE_LIBASSISTANT_FACTORY_H_
diff --git a/chromeos/ash/services/libassistant/test_support/fake_platform_delegate.cc b/chromeos/ash/services/libassistant/test_support/fake_platform_delegate.cc
deleted file mode 100644
index 590267c..0000000
--- a/chromeos/ash/services/libassistant/test_support/fake_platform_delegate.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/test_support/fake_platform_delegate.h"
-
-namespace ash::assistant {
-
-FakePlatformDelegate::FakePlatformDelegate() = default;
-FakePlatformDelegate::~FakePlatformDelegate() = default;
-
-void FakePlatformDelegate::BindAudioStreamFactory(
-    mojo::PendingReceiver<::media::mojom::AudioStreamFactory> receiver) {
-  stream_factory_receiver_ = std::move(receiver);
-}
-
-void FakePlatformDelegate::BindAudioDecoderFactory(
-    mojo::PendingReceiver<mojom::AssistantAudioDecoderFactory> receiver) {
-  audio_decoder_factory_receiver_ = std::move(receiver);
-}
-
-void FakePlatformDelegate::BindBatteryMonitor(
-    mojo::PendingReceiver<::device::mojom::BatteryMonitor> receiver) {
-  battery_monitor_receiver_ = std::move(receiver);
-}
-
-}  // namespace ash::assistant
diff --git a/chromeos/ash/services/libassistant/test_support/fake_platform_delegate.h b/chromeos/ash/services/libassistant/test_support/fake_platform_delegate.h
deleted file mode 100644
index b9d68f5a..0000000
--- a/chromeos/ash/services/libassistant/test_support/fake_platform_delegate.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_TEST_SUPPORT_FAKE_PLATFORM_DELEGATE_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_TEST_SUPPORT_FAKE_PLATFORM_DELEGATE_H_
-
-#include "chromeos/ash/services/libassistant/public/mojom/platform_delegate.mojom.h"
-
-namespace ash::assistant {
-
-class FakePlatformDelegate : public libassistant::mojom::PlatformDelegate {
- public:
-  FakePlatformDelegate();
-  FakePlatformDelegate(FakePlatformDelegate&) = delete;
-  FakePlatformDelegate& operator=(FakePlatformDelegate&) = delete;
-  ~FakePlatformDelegate() override;
-
-  // mojom::PlatformDelegate implementation:
-  void BindAudioStreamFactory(
-      mojo::PendingReceiver<::media::mojom::AudioStreamFactory> receiver)
-      override;
-  void BindAudioDecoderFactory(
-      mojo::PendingReceiver<mojom::AssistantAudioDecoderFactory> receiver)
-      override;
-  void BindBatteryMonitor(
-      mojo::PendingReceiver<::device::mojom::BatteryMonitor> receiver) override;
-  void BindNetworkConfig(
-      mojo::PendingReceiver<chromeos::network_config::mojom::CrosNetworkConfig>
-          receiver) override {}
-  void BindAssistantVolumeControl(
-      mojo::PendingReceiver<::ash::mojom::AssistantVolumeControl> receiver)
-      override {}
-  void BindWakeLockProvider(
-      mojo::PendingReceiver<::device::mojom::WakeLockProvider> receiver)
-      override {}
-
-  // Return the pending receiver passed to the last BindAudioStreamFactory call.
-  mojo::PendingReceiver<::media::mojom::AudioStreamFactory>
-  stream_factory_receiver() {
-    return std::move(stream_factory_receiver_);
-  }
-
-  mojo::PendingReceiver<mojom::AssistantAudioDecoderFactory>
-  audio_decoder_factory_receiver() {
-    return std::move(audio_decoder_factory_receiver_);
-  }
-
-  // Return the pending receiver passed to the last BindBatteryMonitor call.
-  mojo::PendingReceiver<::device::mojom::BatteryMonitor>
-  battery_monitor_receiver() {
-    return std::move(battery_monitor_receiver_);
-  }
-
- private:
-  mojo::PendingReceiver<::media::mojom::AudioStreamFactory>
-      stream_factory_receiver_;
-  mojo::PendingReceiver<mojom::AssistantAudioDecoderFactory>
-      audio_decoder_factory_receiver_;
-  mojo::PendingReceiver<::device::mojom::BatteryMonitor>
-      battery_monitor_receiver_;
-};
-
-}  // namespace ash::assistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_TEST_SUPPORT_FAKE_PLATFORM_DELEGATE_H_
diff --git a/chromeos/ash/services/libassistant/test_support/libassistant_service_tester.cc b/chromeos/ash/services/libassistant/test_support/libassistant_service_tester.cc
deleted file mode 100644
index da8d853..0000000
--- a/chromeos/ash/services/libassistant/test_support/libassistant_service_tester.cc
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/test_support/libassistant_service_tester.h"
-
-#include "base/base_paths.h"
-#include "chromeos/ash/services/libassistant/display_connection.h"
-#include "chromeos/ash/services/libassistant/display_controller.h"
-#include "chromeos/ash/services/libassistant/grpc/services_status_observer.h"
-#include "chromeos/ash/services/libassistant/public/mojom/notification_delegate.mojom-forward.h"
-#include "chromeos/ash/services/libassistant/service_controller.h"
-#include "chromeos/ash/services/libassistant/test_support/fake_libassistant_factory.h"
-#include "services/network/test/test_url_loader_factory.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-mojo::PendingRemote<network::mojom::URLLoaderFactory> BindURLLoaderFactory() {
-  mojo::PendingRemote<network::mojom::URLLoaderFactory> result;
-  network::TestURLLoaderFactory().Clone(
-      result.InitWithNewPipeAndPassReceiver());
-  return result;
-}
-
-}  // namespace
-
-LibassistantServiceTester::LibassistantServiceTester()
-    : home_dir_override_(base::DIR_HOME) {
-  auto factory = std::make_unique<FakeLibassistantFactory>();
-  // Keep a pointer around.
-  libassistant_factory_ = factory.get();
-
-  service_ = std::make_unique<LibassistantService>(
-      service_remote_.BindNewPipeAndPassReceiver(), std::move(factory));
-
-  BindControllers();
-}
-
-LibassistantServiceTester::~LibassistantServiceTester() = default;
-
-AssistantClient& LibassistantServiceTester::assistant_client() {
-  return *(service_->service_controller().assistant_client());
-}
-
-chromeos::assistant::FakeAssistantManager&
-LibassistantServiceTester::assistant_manager() {
-  return libassistant_factory_->assistant_manager();
-}
-
-void LibassistantServiceTester::Start() {
-  service_controller_->Initialize(mojom::BootupConfig::New(),
-                                  BindURLLoaderFactory());
-  service_controller_->Start();
-  service_controller_.FlushForTesting();
-  // Simulate gRPC heartbeat of the booting up signal.
-  service_->service_controller().OnServicesStatusChanged(
-      ServicesStatus::ONLINE_BOOTING_UP);
-}
-
-void LibassistantServiceTester::BindControllers() {
-  mojo::PendingRemote<mojom::AudioOutputDelegate>
-      pending_audio_output_delegate_remote;
-  mojo::PendingRemote<mojom::DeviceSettingsDelegate>
-      pending_device_settings_delegate_remote;
-  mojo::PendingRemote<mojom::MediaDelegate> pending_media_delegate_remote;
-  mojo::PendingRemote<mojom::NotificationDelegate>
-      pending_notification_delegate_remote;
-  mojo::PendingRemote<mojom::PlatformDelegate> pending_platform_delegate_remote;
-  mojo::PendingRemote<mojom::TimerDelegate> pending_timer_delegate_remote;
-
-  pending_audio_output_delegate_ =
-      pending_audio_output_delegate_remote.InitWithNewPipeAndPassReceiver();
-  pending_device_settings_delegate_ =
-      pending_device_settings_delegate_remote.InitWithNewPipeAndPassReceiver();
-  pending_media_delegate_ =
-      pending_media_delegate_remote.InitWithNewPipeAndPassReceiver();
-  pending_notification_delegate_ =
-      pending_notification_delegate_remote.InitWithNewPipeAndPassReceiver();
-  pending_platform_delegate_ =
-      pending_platform_delegate_remote.InitWithNewPipeAndPassReceiver();
-  pending_timer_delegate_ =
-      pending_timer_delegate_remote.InitWithNewPipeAndPassReceiver();
-
-  service_->Bind(audio_input_controller_.BindNewPipeAndPassReceiver(),
-                 conversation_controller_.BindNewPipeAndPassReceiver(),
-                 display_controller_.BindNewPipeAndPassReceiver(),
-                 media_controller_.BindNewPipeAndPassReceiver(),
-                 service_controller_.BindNewPipeAndPassReceiver(),
-                 settings_controller_.BindNewPipeAndPassReceiver(),
-                 speaker_id_enrollment_controller_.BindNewPipeAndPassReceiver(),
-                 timer_controller_.BindNewPipeAndPassReceiver(),
-                 std::move(pending_audio_output_delegate_remote),
-                 std::move(pending_device_settings_delegate_remote),
-                 std::move(pending_media_delegate_remote),
-                 std::move(pending_notification_delegate_remote),
-                 std::move(pending_platform_delegate_remote),
-                 std::move(pending_timer_delegate_remote));
-}
-
-mojo::PendingReceiver<mojom::NotificationDelegate>
-LibassistantServiceTester::GetNotificationDelegatePendingReceiver() {
-  DCHECK(pending_notification_delegate_.is_valid());
-  return std::move(pending_notification_delegate_);
-}
-
-DisplayConnection& LibassistantServiceTester::GetDisplayConnection() {
-  return service_->GetDisplayControllerForTesting()
-      .GetDisplayConnectionForTesting();
-}
-
-void LibassistantServiceTester::FlushForTesting() {
-  audio_input_controller_.FlushForTesting();
-  conversation_controller_.FlushForTesting();
-  display_controller_.FlushForTesting();
-  media_controller_.FlushForTesting();
-  service_controller_.FlushForTesting();
-  speaker_id_enrollment_controller_.FlushForTesting();
-  service_remote_.FlushForTesting();
-  timer_controller_.FlushForTesting();
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/test_support/libassistant_service_tester.h b/chromeos/ash/services/libassistant/test_support/libassistant_service_tester.h
deleted file mode 100644
index 2d96c6d..0000000
--- a/chromeos/ash/services/libassistant/test_support/libassistant_service_tester.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_TEST_SUPPORT_LIBASSISTANT_SERVICE_TESTER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_TEST_SUPPORT_LIBASSISTANT_SERVICE_TESTER_H_
-
-#include "base/memory/raw_ptr.h"
-#include "base/test/scoped_path_override.h"
-#include "chromeos/ash/services/libassistant/libassistant_service.h"
-#include "chromeos/ash/services/libassistant/public/mojom/audio_input_controller.mojom.h"
-#include "chromeos/ash/services/libassistant/public/mojom/audio_output_delegate.mojom-forward.h"
-#include "chromeos/ash/services/libassistant/public/mojom/conversation_controller.mojom.h"
-#include "chromeos/ash/services/libassistant/public/mojom/device_settings_delegate.mojom-forward.h"
-#include "chromeos/ash/services/libassistant/public/mojom/display_controller.mojom.h"
-#include "chromeos/ash/services/libassistant/public/mojom/notification_delegate.mojom-forward.h"
-#include "chromeos/ash/services/libassistant/public/mojom/service.mojom.h"
-#include "chromeos/ash/services/libassistant/public/mojom/service_controller.mojom.h"
-#include "chromeos/ash/services/libassistant/public/mojom/speaker_id_enrollment_controller.mojom-forward.h"
-#include "chromeos/assistant/internal/test_support/fake_assistant_manager.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
-
-namespace ash::libassistant {
-
-class AssistantClient;
-class DisplayConnection;
-class FakeLibassistantFactory;
-
-// Helper class that makes it easier to test |LibassistantService|.
-class LibassistantServiceTester {
- public:
-  LibassistantServiceTester();
-  LibassistantServiceTester(const LibassistantServiceTester&) = delete;
-  LibassistantServiceTester& operator=(const LibassistantServiceTester&) =
-      delete;
-  ~LibassistantServiceTester();
-
-  // Initialize and start Libassistant.
-  void Start();
-
-  LibassistantService& service() { return *service_; }
-
-  AssistantClient& assistant_client();
-  chromeos::assistant::FakeAssistantManager& assistant_manager();
-
-  mojom::AudioInputController& audio_input_controller() {
-    return *audio_input_controller_.get();
-  }
-  mojom::ConversationController& conversation_controller() {
-    return *conversation_controller_.get();
-  }
-  mojom::DisplayController& display_controller() {
-    return *display_controller_.get();
-  }
-  mojom::ServiceController& service_controller() {
-    return *service_controller_.get();
-  }
-  mojom::SpeakerIdEnrollmentController& speaker_id_enrollment_controller() {
-    return *speaker_id_enrollment_controller_.get();
-  }
-
-  mojo::PendingReceiver<mojom::NotificationDelegate>
-  GetNotificationDelegatePendingReceiver();
-
-  DisplayConnection& GetDisplayConnection();
-
-  void FlushForTesting();
-
- private:
-  void BindControllers();
-
-  mojo::Remote<mojom::AudioInputController> audio_input_controller_;
-  mojo::Remote<mojom::ConversationController> conversation_controller_;
-  mojo::Remote<mojom::DisplayController> display_controller_;
-  mojo::Remote<mojom::MediaController> media_controller_;
-  mojo::Remote<mojom::ServiceController> service_controller_;
-  mojo::Remote<mojom::SettingsController> settings_controller_;
-  mojo::Remote<mojom::SpeakerIdEnrollmentController>
-      speaker_id_enrollment_controller_;
-  mojo::Remote<mojom::TimerController> timer_controller_;
-  mojo::PendingReceiver<mojom::AudioOutputDelegate>
-      pending_audio_output_delegate_;
-  mojo::PendingReceiver<mojom::DeviceSettingsDelegate>
-      pending_device_settings_delegate_;
-  mojo::PendingReceiver<mojom::MediaDelegate> pending_media_delegate_;
-  mojo::PendingReceiver<mojom::NotificationDelegate>
-      pending_notification_delegate_;
-  mojo::PendingReceiver<mojom::PlatformDelegate> pending_platform_delegate_;
-  mojo::PendingReceiver<mojom::TimerDelegate> pending_timer_delegate_;
-
-  mojo::Remote<mojom::LibassistantService> service_remote_;
-  // Our file provider requires the home dir to be overridden.
-  base::ScopedPathOverride home_dir_override_;
-  raw_ptr<FakeLibassistantFactory> libassistant_factory_ = nullptr;
-  std::unique_ptr<LibassistantService> service_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_TEST_SUPPORT_LIBASSISTANT_SERVICE_TESTER_H_
diff --git a/chromeos/ash/services/libassistant/timer_controller.cc b/chromeos/ash/services/libassistant/timer_controller.cc
deleted file mode 100644
index 32bae5aa..0000000
--- a/chromeos/ash/services/libassistant/timer_controller.cc
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/timer_controller.h"
-
-#include "base/memory/raw_ref.h"
-#include "base/thread_annotations.h"
-#include "build/buildflag.h"
-#include "chromeos/ash/services/assistant/public/cpp/features.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client.h"
-#include "chromeos/ash/services/libassistant/grpc/external_services/grpc_services_observer.h"
-#include "chromeos/ash/services/libassistant/grpc/utils/timer_utils.h"
-#include "chromeos/ash/services/libassistant/public/cpp/assistant_timer.h"
-#include "chromeos/assistant/internal/proto/shared/proto/v2/delegate/event_handler_interface.pb.h"
-
-namespace ash::libassistant {
-
-////////////////////////////////////////////////////////////////////////////////
-// TimerListener
-////////////////////////////////////////////////////////////////////////////////
-
-// Helper that listens to Libassistant timer events, and forwards this
-// information to controller::OnTimerStateChanged().
-class TimerController::TimerListener
-    : public GrpcServicesObserver<::assistant::api::OnAlarmTimerEventRequest> {
- public:
-  TimerListener(AssistantClient* assistant_client,
-                mojom::TimerDelegate* delegate)
-      : assistant_client_(*assistant_client), delegate_(*delegate) {}
-  TimerListener(const TimerListener&) = delete;
-  TimerListener& operator=(const TimerListener&) = delete;
-  ~TimerListener() override = default;
-
-  void Start() {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-    // Register as an observer of |AlarmTimerEvent| to get notified on
-    // alarm/timer status change, i.e. when timers are scheduled, updated,
-    // and/or removed. Status change will be reflected on UI correspondingly.
-    assistant_client_->AddAlarmTimerEventObserver(this);
-
-    // Force sync the initial timer state.
-    assistant_client_->GetTimers(base::BindOnce(
-        &TimerListener::NotifyTimerStatusChanged, weak_factory_.GetWeakPtr()));
-  }
-
-  void Stop() {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-    // Notify our timer delegate to clear its cache to remain in sync with
-    // LibAssistant.
-    NotifyTimerStatusChanged(/*timers=*/{});
-  }
-
- private:
-  // GrpcServicesObserver:
-  // Invoked when an alarm/timer event has been received.
-  // TODO(meilinw): Besides the list of all current timers, the V2 proto also
-  // returns information associated with the timer which the status has changed.
-  // Investigate on if we could use that field.
-  void OnGrpcMessage(
-      const ::assistant::api::OnAlarmTimerEventRequest& request) override {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-    // Only handle timer event in this timer listener.
-    auto& alarm_timer_event = request.event();
-    if (alarm_timer_event.has_on_timer_state_changed()) {
-      NotifyTimerStatusChanged(ConstructAssistantTimersFromProto(
-          alarm_timer_event.on_timer_state_changed().timer_params()));
-    }
-  }
-
-  // Notify our timer delegate on any timer status change. |timers| contains
-  // all the current timers.
-  void NotifyTimerStatusChanged(
-      const std::vector<assistant::AssistantTimer>& timers) {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-    delegate_->OnTimerStateChanged(timers);
-  }
-
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  const raw_ref<AssistantClient> assistant_client_ GUARDED_BY_CONTEXT(
-      sequence_checker_);
-  const raw_ref<mojom::TimerDelegate> delegate_ GUARDED_BY_CONTEXT(
-      sequence_checker_);
-
-  base::WeakPtrFactory<TimerListener> weak_factory_{this};
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// TimerController
-////////////////////////////////////////////////////////////////////////////////
-
-TimerController::TimerController() = default;
-TimerController::~TimerController() = default;
-
-void TimerController::Bind(
-    mojo::PendingReceiver<mojom::TimerController> receiver,
-    mojo::PendingRemote<mojom::TimerDelegate> delegate) {
-  receiver_.Bind(std::move(receiver));
-  delegate_.Bind(std::move(delegate));
-}
-
-void TimerController::AddTimeToTimer(const std::string& id,
-                                     ::base::TimeDelta duration) {
-  if (assistant_client_)
-    assistant_client_->AddTimeToTimer(id, duration);
-}
-
-void TimerController::PauseTimer(const std::string& id) {
-  if (assistant_client_)
-    assistant_client_->PauseTimer(id);
-}
-
-void TimerController::RemoveTimer(const std::string& id) {
-  if (assistant_client_)
-    assistant_client_->RemoveTimer(id);
-}
-
-void TimerController::ResumeTimer(const std::string& id) {
-  if (assistant_client_)
-    assistant_client_->ResumeTimer(id);
-}
-
-void TimerController::OnAssistantClientRunning(
-    AssistantClient* assistant_client) {
-  assistant_client_ = assistant_client;
-  timer_listener_ =
-      std::make_unique<TimerListener>(assistant_client, delegate_.get());
-  timer_listener_->Start();
-}
-
-void TimerController::OnDestroyingAssistantClient(
-    AssistantClient* assistant_client) {
-  assistant_client_ = nullptr;
-
-  if (timer_listener_) {
-    timer_listener_->Stop();
-    timer_listener_.reset();
-  }
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/timer_controller.h b/chromeos/ash/services/libassistant/timer_controller.h
deleted file mode 100644
index 473111b7..0000000
--- a/chromeos/ash/services/libassistant/timer_controller.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_TIMER_CONTROLLER_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_TIMER_CONTROLLER_H_
-
-#include <string>
-
-#include "base/memory/raw_ptr.h"
-#include "base/time/time.h"
-#include "chromeos/ash/services/libassistant/grpc/assistant_client_observer.h"
-#include "chromeos/ash/services/libassistant/public/mojom/timer_controller.mojom.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
-
-namespace ash::libassistant {
-
-class TimerController : public mojom::TimerController,
-                        public AssistantClientObserver {
- public:
-  TimerController();
-  TimerController(const TimerController&) = delete;
-  TimerController& operator=(const TimerController&) = delete;
-  ~TimerController() override;
-
-  void Bind(mojo::PendingReceiver<mojom::TimerController> receiver,
-            mojo::PendingRemote<mojom::TimerDelegate> delegate);
-
-  // mojom::TimerController implementation:
-  void AddTimeToTimer(const std::string& id,
-                      ::base::TimeDelta duration) override;
-  void PauseTimer(const std::string& id) override;
-  void RemoveTimer(const std::string& id) override;
-  void ResumeTimer(const std::string& id) override;
-
-  // AssistantClientObserver implementation:
-  void OnAssistantClientRunning(AssistantClient* assistant_client) override;
-  void OnDestroyingAssistantClient(AssistantClient* assistant_client) override;
-
- private:
-  class TimerListener;
-
-  // Created when Libassistant is running, and destroyed when it stops.
-  std::unique_ptr<TimerListener> timer_listener_;
-
-  // Owned by |ServiceController|, set in OnAssistantClientRunning() and reset
-  // in OnDestroyingAssistantClient().
-  raw_ptr<AssistantClient> assistant_client_ = nullptr;
-
-  mojo::Receiver<mojom::TimerController> receiver_{this};
-  mojo::Remote<mojom::TimerDelegate> delegate_;
-};
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_TIMER_CONTROLLER_H_
diff --git a/chromeos/ash/services/libassistant/timer_controller_unittest.cc b/chromeos/ash/services/libassistant/timer_controller_unittest.cc
deleted file mode 100644
index 7b879ce..0000000
--- a/chromeos/ash/services/libassistant/timer_controller_unittest.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/timer_controller.h"
-
-#include "base/test/scoped_feature_list.h"
-#include "base/test/task_environment.h"
-#include "chromeos/ash/services/assistant/public/cpp/features.h"
-#include "chromeos/ash/services/libassistant/public/mojom/timer_controller.mojom-forward.h"
-#include "chromeos/ash/services/libassistant/test_support/fake_assistant_client.h"
-#include "chromeos/assistant/internal/libassistant/shared_headers.h"
-#include "chromeos/assistant/internal/test_support/fake_assistant_manager.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash::libassistant {
-
-namespace {
-
-class TimerDelegateMock : public mojom::TimerDelegate {
- public:
-  TimerDelegateMock() = default;
-  TimerDelegateMock(const TimerDelegateMock&) = delete;
-  TimerDelegateMock& operator=(const TimerDelegateMock&) = delete;
-  ~TimerDelegateMock() override = default;
-
-  // mojom::TimerDelegate implementation:
-  MOCK_METHOD(void,
-              OnTimerStateChanged,
-              (const std::vector<assistant::AssistantTimer>& timers));
-
-  mojo::PendingRemote<mojom::TimerDelegate> BindNewPipeAndPassRemote() {
-    return receiver_.BindNewPipeAndPassRemote();
-  }
-
-  void FlushForTesting() { receiver_.FlushForTesting(); }
-
- private:
-  mojo::Receiver<mojom::TimerDelegate> receiver_{this};
-};
-
-}  // namespace
-
-class AssistantTimerControllerTest : public ::testing::Test {
- public:
-  AssistantTimerControllerTest() = default;
-  AssistantTimerControllerTest(const AssistantTimerControllerTest&) = delete;
-  AssistantTimerControllerTest& operator=(const AssistantTimerControllerTest&) =
-      delete;
-  ~AssistantTimerControllerTest() override = default;
-
-  void SetUp() override {
-    controller_.Bind(client_.BindNewPipeAndPassReceiver(),
-                     delegate_.BindNewPipeAndPassRemote());
-    Init();
-  }
-
-  void Init() {
-    auto assistant_manager =
-        std::make_unique<chromeos::assistant::FakeAssistantManager>();
-    assistant_client_ =
-        std::make_unique<FakeAssistantClient>(std::move(assistant_manager));
-  }
-
-  void StartLibassistant() {
-    if (!assistant_client_) {
-      Init();
-    }
-    controller_.OnAssistantClientRunning(assistant_client_.get());
-  }
-
-  void StopLibassistant() {
-    controller_.OnDestroyingAssistantClient(assistant_client_.get());
-
-    // Delete the assistant manager so we crash on use-after-free.
-    assistant_client_.reset();
-  }
-
-  TimerController& controller() { return controller_; }
-
- private:
-  base::test::SingleThreadTaskEnvironment environment_;
-  std::unique_ptr<FakeAssistantClient> assistant_client_;
-  mojo::Remote<mojom::TimerController> client_;
-  testing::StrictMock<TimerDelegateMock> delegate_;
-  TimerController controller_;
-};
-
-TEST_F(AssistantTimerControllerTest, ShouldNotCrashIfLibassistantIsNotStarted) {
-  controller().AddTimeToTimer("timer-id", /*duration=*/base::TimeDelta());
-  controller().PauseTimer("timer-id");
-  controller().RemoveTimer("timer-id");
-  controller().ResumeTimer("timer-id");
-}
-
-TEST_F(AssistantTimerControllerTest, ShouldNotCrashAfterStoppingLibassistant) {
-  StartLibassistant();
-  StopLibassistant();
-
-  controller().AddTimeToTimer("timer-id", /*duration=*/base::TimeDelta());
-  controller().PauseTimer("timer-id");
-  controller().RemoveTimer("timer-id");
-  controller().ResumeTimer("timer-id");
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/util.cc b/chromeos/ash/services/libassistant/util.cc
deleted file mode 100644
index 2c358f7..0000000
--- a/chromeos/ash/services/libassistant/util.cc
+++ /dev/null
@@ -1,419 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ash/services/libassistant/util.h"
-
-#include "base/command_line.h"
-#include "base/files/file_util.h"
-#include "base/json/json_writer.h"
-#include "base/path_service.h"
-#include "base/strings/stringprintf.h"
-#include "base/system/sys_info.h"
-#include "base/values.h"
-#include "build/util/chromium_git_revision.h"
-#include "chromeos/ash/services/assistant/public/cpp/features.h"
-#include "chromeos/ash/services/assistant/public/cpp/switches.h"
-#include "chromeos/ash/services/libassistant/constants.h"
-#include "chromeos/ash/services/libassistant/grpc/grpc_util.h"
-#include "chromeos/ash/services/libassistant/public/cpp/android_app_info.h"
-#include "chromeos/assistant/internal/internal_constants.h"
-#include "chromeos/assistant/internal/internal_util.h"
-#include "chromeos/assistant/internal/util_headers.h"
-#include "chromeos/version/version_loader.h"
-
-using ::assistant::api::Interaction;
-using chromeos::assistant::shared::ClientInteraction;
-using chromeos::assistant::shared::ClientOpResult;
-using chromeos::assistant::shared::GetDeviceSettingsResult;
-using chromeos::assistant::shared::Protobuf;
-using chromeos::assistant::shared::ProviderVerificationResult;
-using chromeos::assistant::shared::ResponseCode;
-using chromeos::assistant::shared::SettingInfo;
-using chromeos::assistant::shared::VerifyProviderClientOpResult;
-
-namespace ash::libassistant {
-
-namespace {
-
-using AppStatus = assistant::AppStatus;
-
-void CreateUserAgent(std::string* user_agent) {
-  DCHECK(user_agent->empty());
-  base::StringAppendF(user_agent,
-                      "Mozilla/5.0 (X11; CrOS %s %s; %s) "
-                      "AppleWebKit/537.36 (KHTML, like Gecko)",
-                      base::SysInfo::OperatingSystemArchitecture().c_str(),
-                      base::SysInfo::OperatingSystemVersion().c_str(),
-                      base::SysInfo::GetLsbReleaseBoard().c_str());
-
-  std::string arc_version = chromeos::version_loader::GetArcVersion();
-  if (!arc_version.empty())
-    base::StringAppendF(user_agent, " ARC/%s", arc_version.c_str());
-}
-
-ProviderVerificationResult::VerificationStatus GetProviderVerificationStatus(
-    AppStatus status) {
-  switch (status) {
-    case AppStatus::kUnknown:
-      return ProviderVerificationResult::UNKNOWN;
-    case AppStatus::kAvailable:
-      return ProviderVerificationResult::AVAILABLE;
-    case AppStatus::kUnavailable:
-      return ProviderVerificationResult::UNAVAILABLE;
-    case AppStatus::kVersionMismatch:
-      return ProviderVerificationResult::VERSION_MISMATCH;
-    case AppStatus::kDisabled:
-      return ProviderVerificationResult::DISABLED;
-  }
-}
-
-SettingInfo ToSettingInfo(bool is_supported) {
-  SettingInfo result;
-  result.set_available(is_supported);
-  result.set_setting_status(is_supported
-                                ? SettingInfo::AVAILABLE_AND_MODIFY_SUPPORTED
-                                : SettingInfo::UNAVAILABLE);
-  return result;
-}
-
-// Helper class used for constructing V1 interaction proto messages.
-class V1InteractionBuilder {
- public:
-  V1InteractionBuilder() = default;
-  V1InteractionBuilder(V1InteractionBuilder&) = delete;
-  V1InteractionBuilder& operator=(V1InteractionBuilder&) = delete;
-  ~V1InteractionBuilder() = default;
-
-  V1InteractionBuilder& SetInResponseTo(int interaction_id) {
-    interaction_.set_in_response_to(interaction_id);
-    return *this;
-  }
-
-  V1InteractionBuilder& AddResult(
-      const std::string& key,
-      const google::protobuf::MessageLite& result_proto) {
-    auto* result = client_op_result()->mutable_results()->add_result();
-    result->set_key(key);
-    result->mutable_value()->set_protobuf_type(result_proto.GetTypeName());
-    result->mutable_value()->set_protobuf_data(
-        result_proto.SerializeAsString());
-    return *this;
-  }
-
-  V1InteractionBuilder& SetStatusCode(ResponseCode::Status status_code) {
-    ResponseCode* response_code = client_op_result()->mutable_response_code();
-    response_code->set_status_code(status_code);
-    return *this;
-  }
-
-  // Set the status code to |OK| (if true) or |NOT_FOUND| (if false).
-  V1InteractionBuilder& SetStatusCodeFromEntityFound(bool found) {
-    SetStatusCode(found ? ResponseCode::OK : ResponseCode::NOT_FOUND);
-    return *this;
-  }
-
-  V1InteractionBuilder& SetClientInputName(const std::string& name) {
-    auto* client_input = client_interaction()->mutable_client_input();
-    client_input->set_client_input_name(name);
-    return *this;
-  }
-
-  V1InteractionBuilder& AddClientInputParams(
-      const std::string& key,
-      const google::protobuf::MessageLite& params_proto) {
-    auto* client_input = client_interaction()->mutable_client_input();
-    Protobuf& value = (*client_input->mutable_params())[key];
-    value.set_protobuf_type(params_proto.GetTypeName());
-    value.set_protobuf_data(params_proto.SerializeAsString());
-    return *this;
-  }
-
-  std::string SerializeAsString() { return interaction_.SerializeAsString(); }
-
-  Interaction Proto() { return interaction_; }
-
- private:
-  ClientInteraction* client_interaction() {
-    return interaction_.mutable_from_client();
-  }
-
-  ClientOpResult* client_op_result() {
-    return client_interaction()->mutable_client_op_result();
-  }
-
-  Interaction interaction_;
-};
-
-bool ShouldPutLogsInHomeDirectory() {
-  const bool redirect_logging =
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          assistant::switches::kRedirectLibassistantLogging);
-  return !redirect_logging;
-}
-
-bool ShouldLogToFile() {
-  const bool disable_logfile =
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          assistant::switches::kDisableLibAssistantLogfile);
-  return !disable_logfile;
-}
-
-}  // namespace
-
-base::FilePath GetBaseAssistantDir() {
-  return base::FilePath(FILE_PATH_LITERAL(kAssistantBaseDirPath));
-}
-
-std::string CreateLibAssistantConfig(
-    std::optional<std::string> s3_server_uri_override,
-    std::optional<std::string> device_id_override) {
-  using Value = base::Value;
-
-  Value::Dict config;
-
-  std::optional<std::string> version = chromeos::version_loader::GetVersion(
-      chromeos::version_loader::VERSION_FULL);
-  config.Set("device",
-             Value::Dict()
-                 .Set("board_name", base::SysInfo::GetLsbReleaseBoard())
-                 .Set("board_revision", "1")
-                 .Set("embedder_build_info", version.value_or("0.0.0.0"))
-                 .Set("model_id", chromeos::assistant::kModelId)
-                 .Set("model_revision", 1));
-
-  // Enables Libassistant gRPC server for V2.
-  const bool is_chromeos_device = base::SysInfo::IsRunningOnChromeOS();
-  const std::string server_addresses =
-      GetLibassistantServiceAddress(is_chromeos_device) + "," +
-      GetHttpConnectionServiceAddress(is_chromeos_device);
-
-  config.Set("libas_server", Value::Dict()
-                                 .Set("libas_server_address", server_addresses)
-                                 .Set("enable_display_service", true)
-                                 .Set("enable_http_connection_service", true));
-
-  config.Set("discovery", Value::Dict().Set("enable_mdns", false));
-
-  std::string user_agent;
-  CreateUserAgent(&user_agent);
-
-  auto internal =
-      Value::Dict()
-          .Set("surface_type", "OPA_CROS")
-          .Set("user_agent", user_agent)
-
-          // Prevent LibAssistant from automatically playing ready
-          // message TTS during the startup sequence when the
-          // version of LibAssistant has been upgraded.
-          .Set("override_ready_message", true)
-
-          // Set DeviceProperties.visibility to Visibility::PRIVATE.
-          // See //libassistant/shared/proto/device_properties.proto.
-          .Set("visibility", "PRIVATE")
-
-          // Enable logging.
-          .Set("enable_logging", true)
-
-          // This only enables logging to local disk combined with the flag
-          // above. When user choose to file a Feedback report, user can examine
-          // the log and choose to upload the log with the report or not.
-          .Set("logging_opt_in", true)
-
-          // Allows libassistant to automatically toggle signed-out mode
-          // depending on whether it has auth_tokens.
-          .Set("enable_signed_out_mode", true);
-
-  if (ShouldLogToFile()) {
-    std::string log_dir("/var/log/chrome/");
-    if (ShouldPutLogsInHomeDirectory()) {
-      base::FilePath log_path =
-          GetBaseAssistantDir().Append(FILE_PATH_LITERAL("log"));
-
-      // The directory will be created by LibassistantPreSandboxHook if sandbox
-      // is enabled.
-      if (!assistant::features::IsLibAssistantSandboxEnabled())
-        CHECK(base::CreateDirectory(log_path));
-
-      log_dir = log_path.value();
-    }
-
-    auto logging = Value::Dict()
-                       .Set("directory", log_dir)
-                       // Maximum disk space consumed by all log files. There
-                       // are 5 rotating log files on disk.
-                       .Set("max_size_kb", 3 * 1024)
-                       // Empty "output_type" disables logging to stderr.
-                       .Set("output_type", Value::List());
-    config.Set("logging", std::move(logging));
-  } else {
-    // Print logs to console if running in desktop or test mode.
-    internal.Set("disable_log_files", true);
-  }
-
-  config.Set("internal", std::move(internal));
-
-  config.Set(
-      "audio_input",
-      Value::Dict()
-          // Skip sending speaker ID selection to disable user verification.
-          .Set("should_send_speaker_id_selection_info", false)
-          .Set("sources",
-               Value::List().Append(
-                   Value::Dict()
-                       .Set("enable_eraser",
-                            assistant::features::IsAudioEraserEnabled())
-                       .Set("enable_eraser_toggling",
-                            assistant::features::IsAudioEraserEnabled()))));
-
-  if (assistant::features::IsLibAssistantBetaBackendEnabled()) {
-    config.SetByDottedPath("internal.backend_type", "BETA_DOGFOOD");
-  }
-
-  // Use http unless we're using the fake s3 server, which requires grpc.
-  if (s3_server_uri_override) {
-    config.SetByDottedPath("internal.transport_type", "GRPC");
-  } else {
-    config.SetByDottedPath("internal.transport_type", "HTTP");
-  }
-
-  if (device_id_override) {
-    config.SetByDottedPath("internal.cast_device_id",
-                           device_id_override.value());
-  }
-
-  config.SetByDottedPath("internal.enable_on_device_assistant_tts_as_text",
-                         true);
-
-  // Finally add in the server uri override.
-  if (s3_server_uri_override) {
-    config.SetByDottedPath("testing.s3_grpc_server_uri",
-                           s3_server_uri_override.value());
-  }
-
-  std::string json;
-  base::JSONWriter::Write(config, &json);
-  return json;
-}
-
-Interaction CreateVerifyProviderResponseInteraction(
-    const int interaction_id,
-    const std::vector<assistant::AndroidAppInfo>& apps_info) {
-  // Construct verify provider result proto.
-  VerifyProviderClientOpResult result_proto;
-  bool any_provider_available = false;
-  for (const auto& android_app_info : apps_info) {
-    auto* provider_status = result_proto.add_provider_status();
-    provider_status->set_status(
-        GetProviderVerificationStatus(android_app_info.status));
-    auto* app_info =
-        provider_status->mutable_provider_info()->mutable_android_app_info();
-    app_info->set_package_name(android_app_info.package_name);
-    app_info->set_app_version(android_app_info.version);
-    app_info->set_localized_app_name(android_app_info.localized_app_name);
-    app_info->set_android_intent(android_app_info.intent);
-
-    if (android_app_info.status == AppStatus::kAvailable)
-      any_provider_available = true;
-  }
-
-  // Construct response interaction.
-  return V1InteractionBuilder()
-      .SetInResponseTo(interaction_id)
-      .SetStatusCodeFromEntityFound(any_provider_available)
-      .AddResult(chromeos::assistant::kResultKeyVerifyProvider, result_proto)
-      .Proto();
-}
-
-Interaction CreateGetDeviceSettingInteraction(
-    int interaction_id,
-    const std::vector<chromeos::assistant::DeviceSetting>& device_settings) {
-  GetDeviceSettingsResult result_proto;
-  for (const auto& setting : device_settings) {
-    (*result_proto.mutable_settings_info())[setting.setting_id] =
-        ToSettingInfo(setting.is_supported);
-  }
-
-  // Construct response interaction.
-  return V1InteractionBuilder()
-      .SetInResponseTo(interaction_id)
-      .SetStatusCode(ResponseCode::OK)
-      .AddResult(/*key=*/chromeos::assistant::kResultKeyGetDeviceSettings,
-                 result_proto)
-      .Proto();
-}
-
-Interaction CreateNotificationRequestInteraction(
-    const std::string& notification_id,
-    const std::string& consistent_token,
-    const std::string& opaque_token,
-    const int action_index) {
-  auto request_param = chromeos::assistant::CreateNotificationRequestParam(
-      notification_id, consistent_token, opaque_token, action_index);
-
-  return V1InteractionBuilder()
-      .SetClientInputName(chromeos::assistant::kClientInputRequestNotification)
-      .AddClientInputParams(chromeos::assistant::kNotificationRequestParamsKey,
-                            request_param)
-      .Proto();
-}
-
-Interaction CreateNotificationDismissedInteraction(
-    const std::string& notification_id,
-    const std::string& consistent_token,
-    const std::string& opaque_token,
-    const std::vector<std::string>& grouping_keys) {
-  auto dismiss_param = chromeos::assistant::CreateNotificationDismissedParam(
-      notification_id, consistent_token, opaque_token, grouping_keys);
-
-  return V1InteractionBuilder()
-      .SetClientInputName(chromeos::assistant::kClientInputDismissNotification)
-      .AddClientInputParams(chromeos::assistant::kNotificationDismissParamsKey,
-                            dismiss_param)
-      .Proto();
-}
-
-Interaction CreateEditReminderInteraction(const std::string& reminder_id) {
-  auto intent_input = chromeos::assistant::CreateEditReminderParam(reminder_id);
-
-  return V1InteractionBuilder()
-      .SetClientInputName(chromeos::assistant::kClientInputEditReminder)
-      .AddClientInputParams(chromeos::assistant::kEditReminderParamsKey,
-                            intent_input)
-      .Proto();
-}
-
-Interaction CreateOpenProviderResponseInteraction(const int interaction_id,
-                                                  const bool provider_found) {
-  return V1InteractionBuilder()
-      .SetInResponseTo(interaction_id)
-      .SetStatusCodeFromEntityFound(provider_found)
-      .Proto();
-}
-
-Interaction CreateSendFeedbackInteraction(
-    bool assistant_debug_info_allowed,
-    const std::string& feedback_description,
-    const std::string& screenshot_png) {
-  auto feedback_arg = chromeos::assistant::CreateFeedbackParam(
-      assistant_debug_info_allowed, feedback_description, screenshot_png);
-
-  return V1InteractionBuilder()
-      .SetClientInputName(chromeos::assistant::kClientInputText)
-      .AddClientInputParams(chromeos::assistant::kTextParamsKey,
-                            chromeos::assistant::CreateTextParam(
-                                chromeos::assistant::kFeedbackText))
-      .AddClientInputParams(chromeos::assistant::kFeedbackParamsKey,
-                            feedback_arg)
-      .Proto();
-}
-
-Interaction CreateTextQueryInteraction(const std::string& query) {
-  return V1InteractionBuilder()
-      .SetClientInputName(chromeos::assistant::kClientInputText)
-      .AddClientInputParams(chromeos::assistant::kTextParamsKey,
-                            chromeos::assistant::CreateTextParam(query))
-      .Proto();
-}
-
-}  // namespace ash::libassistant
diff --git a/chromeos/ash/services/libassistant/util.h b/chromeos/ash/services/libassistant/util.h
deleted file mode 100644
index b4a09ff..0000000
--- a/chromeos/ash/services/libassistant/util.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_UTIL_H_
-#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_UTIL_H_
-
-#include <optional>
-#include <string>
-#include <vector>
-
-namespace ash::assistant {
-struct AndroidAppInfo;
-}
-
-namespace assistant {
-namespace api {
-class Interaction;
-}  // namespace api
-}  // namespace assistant
-
-namespace base {
-class FilePath;
-}  // namespace base
-
-namespace chromeos::assistant {
-struct DeviceSetting;
-}
-
-namespace ash::libassistant {
-
-// Creates the configuration for libassistant.
-std::string CreateLibAssistantConfig(
-    std::optional<std::string> s3_server_uri_override,
-    std::optional<std::string> device_id_override);
-
-// Returns the path where all downloaded LibAssistant resources are stored.
-base::FilePath GetBaseAssistantDir();
-
-::assistant::api::Interaction CreateVerifyProviderResponseInteraction(
-    const int interaction_id,
-    const std::vector<assistant::AndroidAppInfo>& apps_info);
-
-::assistant::api::Interaction CreateGetDeviceSettingInteraction(
-    int interaction_id,
-    const std::vector<chromeos::assistant::DeviceSetting>& device_settings);
-
-// `action_index` is the index of the actions and buttons.
-::assistant::api::Interaction CreateNotificationRequestInteraction(
-    const std::string& notification_id,
-    const std::string& consistent_token,
-    const std::string& opaque_token,
-    const int action_index);
-
-// `grouping_keys` are the keys to group multiple notifications together.
-::assistant::api::Interaction CreateNotificationDismissedInteraction(
-    const std::string& notification_id,
-    const std::string& consistent_token,
-    const std::string& opaque_token,
-    const std::vector<std::string>& grouping_keys);
-
-::assistant::api::Interaction CreateEditReminderInteraction(
-    const std::string& reminder_id);
-
-::assistant::api::Interaction CreateOpenProviderResponseInteraction(
-    const int interaction_id,
-    const bool provider_found);
-
-::assistant::api::Interaction CreateSendFeedbackInteraction(
-    bool assistant_debug_info_allowed,
-    const std::string& feedback_description,
-    const std::string& screenshot_png = std::string());
-
-::assistant::api::Interaction CreateTextQueryInteraction(
-    const std::string& query);
-
-}  // namespace ash::libassistant
-
-#endif  // CHROMEOS_ASH_SERVICES_LIBASSISTANT_UTIL_H_
diff --git a/clank b/clank
index 283021f..cfb3b18 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 283021f4101c7fdf0b717c7ab26c6f8059b28746
+Subproject commit cfb3b184379b5491aafc36c95a2d8effd010eea2
diff --git a/components/autofill/core/browser/webdata/autofill_sync_metadata_table.cc b/components/autofill/core/browser/webdata/autofill_sync_metadata_table.cc
index bc6a1bb..0e5e713 100644
--- a/components/autofill/core/browser/webdata/autofill_sync_metadata_table.cc
+++ b/components/autofill/core/browser/webdata/autofill_sync_metadata_table.cc
@@ -4,6 +4,7 @@
 
 #include "components/autofill/core/browser/webdata/autofill_sync_metadata_table.h"
 
+#include "base/logging.h"
 #include "components/autofill/core/browser/webdata/autofill_table_utils.h"
 #include "components/sync/base/data_type.h"
 #include "components/sync/model/metadata_batch.h"
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/BinaryStatePermissionPreference.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/BinaryStatePermissionPreference.java
index 39282646..57e3f3d 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/BinaryStatePermissionPreference.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/BinaryStatePermissionPreference.java
@@ -19,6 +19,7 @@
 import org.chromium.components.browser_ui.settings.ManagedPreferencesUtils;
 import org.chromium.components.browser_ui.widget.RadioButtonWithDescription;
 import org.chromium.components.content_settings.ContentSettingValues;
+import org.chromium.ui.base.ViewUtils;
 
 /** A binary state radio group preference for components/permissions/features.cc */
 @NullMarked
@@ -105,6 +106,10 @@
 
         RadioButtonWithDescription selectedRadioButton = findRadioButton(mSetting);
         if (selectedRadioButton != null) selectedRadioButton.setChecked(true);
+
+        if (mManagedPrefDelegate != null && mManagedPrefDelegate.isPreferenceClickDisabled(this)) {
+            ViewUtils.setEnabledRecursive(holder.itemView, false);
+        }
     }
 
     public void setIconMarginEnd(int marginEnd) {
diff --git a/components/collaboration/internal/messaging/storage/messaging_backend_database_impl.cc b/components/collaboration/internal/messaging/storage/messaging_backend_database_impl.cc
index 1c00a36d..cbf4c267 100644
--- a/components/collaboration/internal/messaging/storage/messaging_backend_database_impl.cc
+++ b/components/collaboration/internal/messaging/storage/messaging_backend_database_impl.cc
@@ -6,6 +6,7 @@
 
 #include "base/files/file_util.h"
 #include "base/functional/bind.h"
+#include "base/logging.h"
 #include "base/task/thread_pool.h"
 
 namespace collaboration::messaging {
diff --git a/components/collaboration/internal/messaging/storage/messaging_backend_database_impl_unittest.cc b/components/collaboration/internal/messaging/storage/messaging_backend_database_impl_unittest.cc
index 7bfbae6..f302ac6 100644
--- a/components/collaboration/internal/messaging/storage/messaging_backend_database_impl_unittest.cc
+++ b/components/collaboration/internal/messaging/storage/messaging_backend_database_impl_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
diff --git a/components/data_sharing/internal/group_data_store.cc b/components/data_sharing/internal/group_data_store.cc
index 96d1c59..e0683c6 100644
--- a/components/data_sharing/internal/group_data_store.cc
+++ b/components/data_sharing/internal/group_data_store.cc
@@ -14,6 +14,7 @@
 #include "base/functional/callback_forward.h"
 #include "base/functional/callback_helpers.h"
 #include "base/location.h"
+#include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/task_traits.h"
diff --git a/components/dbus/properties/types.h b/components/dbus/properties/types.h
index 25cfb62..25488e61 100644
--- a/components/dbus/properties/types.h
+++ b/components/dbus/properties/types.h
@@ -331,6 +331,9 @@
     }
   }
 
+  std::vector<T>& value() { return value_; }
+  const std::vector<T>& value() const { return value_; }
+
   static std::string GetSignature() {
     return std::string("a") + T::GetSignature();
   }
@@ -631,6 +634,11 @@
     return variant->GetAs<T>();
   }
 
+  template <typename T>
+  const T* GetAs(const std::string& key) const {
+    return const_cast<DbusDictionary*>(this)->GetAs<T>(key);
+  }
+
  private:
   friend class DbusTypeImpl<DbusDictionary>;
 
diff --git a/components/enterprise/connectors/core/BUILD.gn b/components/enterprise/connectors/core/BUILD.gn
index 1647b95..95bc0a1 100644
--- a/components/enterprise/connectors/core/BUILD.gn
+++ b/components/enterprise/connectors/core/BUILD.gn
@@ -91,6 +91,8 @@
   testonly = true
 
   sources = [
+    "realtime_reporting_test_environment.cc",
+    "realtime_reporting_test_environment.h",
     "realtime_reporting_test_server.cc",
     "realtime_reporting_test_server.h",
     "reporting_test_utils.cc",
@@ -99,7 +101,10 @@
 
   deps = [
     ":core",
+    "//base/test:test_support",
+    "//components/enterprise",
     "//components/enterprise/common/proto:browser_events_proto",
+    "//components/enterprise/common/proto:chrome_reporting_entity",
     "//components/enterprise/common/proto:upload_request_response",
     "//components/policy/core/common:common_constants",
     "//components/policy/core/common:test_support",
diff --git a/components/enterprise/connectors/core/realtime_reporting_test_environment.cc b/components/enterprise/connectors/core/realtime_reporting_test_environment.cc
new file mode 100644
index 0000000..56c68492
--- /dev/null
+++ b/components/enterprise/connectors/core/realtime_reporting_test_environment.cc
@@ -0,0 +1,64 @@
+// 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 "components/enterprise/connectors/core/realtime_reporting_test_environment.h"
+
+#include "base/base_switches.h"
+#include "base/check.h"
+#include "base/strings/strcat.h"
+#include "build/build_config.h"
+#include "components/enterprise/browser/enterprise_switches.h"
+#include "components/enterprise/connectors/core/features.h"
+#include "components/enterprise/connectors/core/reporting_test_utils.h"
+#include "components/policy/core/common/policy_switches.h"
+
+namespace enterprise_connectors::test {
+
+RealtimeReportingTestEnvironment::RealtimeReportingTestEnvironment(
+    std::unique_ptr<policy::EmbeddedPolicyTestServer> policy_server,
+    std::unique_ptr<RealtimeReportingTestServer> reporting_server)
+    : policy_server_(std::move(policy_server)),
+      reporting_server_(std::move(reporting_server)) {
+  CHECK(policy_server_);
+  CHECK(reporting_server_);
+}
+
+RealtimeReportingTestEnvironment::~RealtimeReportingTestEnvironment() = default;
+
+// static
+std::unique_ptr<RealtimeReportingTestEnvironment>
+RealtimeReportingTestEnvironment::Create(
+    const std::set<std::string>& enabled_event_names,
+    const std::map<std::string, std::vector<std::string>>&
+        enabled_opt_in_events) {
+  std::unique_ptr<policy::EmbeddedPolicyTestServer> policy_server =
+      CreatePolicyTestServerForSecurityEvents(enabled_event_names,
+                                              enabled_opt_in_events);
+  if (!policy_server) {
+    return nullptr;
+  }
+  return std::make_unique<RealtimeReportingTestEnvironment>(
+      std::move(policy_server),
+      std::make_unique<RealtimeReportingTestServer>());
+}
+
+bool RealtimeReportingTestEnvironment::Start() {
+  return policy_server_->Start() && reporting_server_->Start();
+}
+
+std::vector<std::string> RealtimeReportingTestEnvironment::GetArguments() {
+  return {
+#if !BUILDFLAG(IS_CHROMEOS)
+      base::StrCat({"--", switches::kEnableChromeBrowserCloudManagement}),
+#endif
+      base::StrCat({"--", policy::switches::kDeviceManagementUrl, "=",
+                    policy_server_->GetServiceURL().spec()}),
+      base::StrCat({"--", policy::switches::kRealtimeReportingUrl, "=",
+                    reporting_server_->GetServiceURL().spec()}),
+      base::StrCat({"--", switches::kEnableFeatures, "=",
+                    kEnterpriseRealtimeEventReportingOnIOS.name}),
+  };
+}
+
+}  // namespace enterprise_connectors::test
diff --git a/components/enterprise/connectors/core/realtime_reporting_test_environment.h b/components/enterprise/connectors/core/realtime_reporting_test_environment.h
new file mode 100644
index 0000000..8c4e2bda
--- /dev/null
+++ b/components/enterprise/connectors/core/realtime_reporting_test_environment.h
@@ -0,0 +1,60 @@
+// 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 COMPONENTS_ENTERPRISE_CONNECTORS_CORE_REALTIME_REPORTING_TEST_ENVIRONMENT_H_
+#define COMPONENTS_ENTERPRISE_CONNECTORS_CORE_REALTIME_REPORTING_TEST_ENVIRONMENT_H_
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "components/enterprise/connectors/core/realtime_reporting_test_server.h"
+#include "components/policy/test_support/embedded_policy_test_server.h"
+
+namespace enterprise_connectors::test {
+
+// A set of fake servers for testing security event reporting.
+class RealtimeReportingTestEnvironment {
+ public:
+  RealtimeReportingTestEnvironment(
+      std::unique_ptr<policy::EmbeddedPolicyTestServer> policy_server,
+      std::unique_ptr<RealtimeReportingTestServer> reporting_server);
+  ~RealtimeReportingTestEnvironment();
+
+  RealtimeReportingTestEnvironment() = delete;
+  RealtimeReportingTestEnvironment(const RealtimeReportingTestEnvironment&) =
+      delete;
+  RealtimeReportingTestEnvironment& operator=(
+      const RealtimeReportingTestEnvironment&) = delete;
+
+  // Create a new environment with the given reporting settings. Returns
+  // `nullptr` if any server could not be created.
+  static std::unique_ptr<RealtimeReportingTestEnvironment> Create(
+      const std::set<std::string>& enabled_event_names =
+          std::set<std::string>(),
+      const std::map<std::string, std::vector<std::string>>&
+          enabled_opt_in_events =
+              std::map<std::string, std::vector<std::string>>());
+
+  // Bind each server to a port and start listening for requests. Returns true
+  // iff all servers successfully started.
+  bool Start();
+
+  // Get arguments to append to the test process's command line.
+  std::vector<std::string> GetArguments();
+
+  RealtimeReportingTestServer* reporting_server() const {
+    return reporting_server_.get();
+  }
+
+ private:
+  std::unique_ptr<policy::EmbeddedPolicyTestServer> policy_server_;
+  std::unique_ptr<RealtimeReportingTestServer> reporting_server_;
+};
+
+}  // namespace enterprise_connectors::test
+
+#endif  // COMPONENTS_ENTERPRISE_CONNECTORS_CORE_REALTIME_REPORTING_TEST_ENVIRONMENT_H_
diff --git a/components/enterprise/connectors/core/realtime_reporting_test_server.cc b/components/enterprise/connectors/core/realtime_reporting_test_server.cc
index b5c6d47..97a463c 100644
--- a/components/enterprise/connectors/core/realtime_reporting_test_server.cc
+++ b/components/enterprise/connectors/core/realtime_reporting_test_server.cc
@@ -9,6 +9,8 @@
 #include "base/functional/bind.h"
 #include "base/json/json_reader.h"
 #include "base/values.h"
+#include "components/enterprise/common/proto/synced/browser_events.pb.h"
+#include "components/enterprise/common/proto/synced_from_google3/chrome_reporting_entity.pb.h"
 #include "net/http/http_status_code.h"
 
 namespace enterprise_connectors::test {
@@ -16,11 +18,49 @@
 namespace {
 
 using ::chrome::cros::reporting::proto::Event;
+using ::chrome::cros::reporting::proto::EventResult;
+using ::chrome::cros::reporting::proto::EventResult_Parse;
 using ::chrome::cros::reporting::proto::LoginEvent;
+using ::chrome::cros::reporting::proto::SafeBrowsingInterstitialEvent;
 using ::chrome::cros::reporting::proto::UploadEventsRequest;
 
 constexpr char kRealtimeReportingUrl[] = "/v1/events";
 
+void ParseLoginEvent(const base::Value::Dict* event_details_json,
+                     LoginEvent* event) {
+  if (const std::string* url = event_details_json->FindString("url")) {
+    event->set_url(*url);
+  }
+  if (const std::string* login_user_name =
+          event_details_json->FindString("loginUserName")) {
+    event->set_login_user_name(*login_user_name);
+  }
+}
+
+void ParseInterstitialEvent(const base::Value::Dict* event_details_json,
+                            SafeBrowsingInterstitialEvent* event) {
+  if (const std::string* url = event_details_json->FindString("url")) {
+    event->set_url(*url);
+  }
+  event->set_clicked_through(
+      event_details_json->FindBool("clickedThrough").value_or(false));
+  if (const std::string* event_result_name =
+          event_details_json->FindString("eventResult")) {
+    EventResult event_result;
+    if (EventResult_Parse(*event_result_name, &event_result)) {
+      event->set_event_result(std::move(event_result));
+    }
+  }
+  if (const std::string* reason_name =
+          event_details_json->FindString("reason")) {
+    SafeBrowsingInterstitialEvent::InterstitialReason reason;
+    if (SafeBrowsingInterstitialEvent::InterstitialReason_Parse(*reason_name,
+                                                                &reason)) {
+      event->set_reason(std::move(reason));
+    }
+  }
+}
+
 std::optional<Event> ParseEvent(const base::Value::Dict* event_json) {
   if (!event_json) {
     return std::nullopt;
@@ -29,16 +69,10 @@
   const base::Value::Dict* event_details_json;
   // TODO(crbug.com/412683254): Add branches for other event types.
   if ((event_details_json = event_json->FindDict("loginEvent"))) {
-    LoginEvent* login_event = event.mutable_login_event();
-    const std::string* url = event_details_json->FindString("url");
-    if (url) {
-      login_event->set_url(*url);
-    }
-    const std::string* login_user_name =
-        event_details_json->FindString("loginUserName");
-    if (login_user_name) {
-      login_event->set_login_user_name(*login_user_name);
-    }
+    ParseLoginEvent(event_details_json, event.mutable_login_event());
+  } else if ((event_details_json = event_json->FindDict("interstitialEvent"))) {
+    ParseInterstitialEvent(event_details_json,
+                           event.mutable_interstitial_event());
   } else {
     return std::nullopt;
   }
diff --git a/components/enterprise/connectors/core/reporting_test_utils.cc b/components/enterprise/connectors/core/reporting_test_utils.cc
index 5889370..af65c76 100644
--- a/components/enterprise/connectors/core/reporting_test_utils.cc
+++ b/components/enterprise/connectors/core/reporting_test_utils.cc
@@ -356,16 +356,18 @@
       });
 }
 
-void EventReportValidatorBase::ExpectSecurityInterstitialShown(
+void EventReportValidatorBase::ExpectSecurityInterstitialEvent(
     const std::string& expected_url,
     const std::string& expected_reason,
     const std::string& expected_profile_username,
     const std::string& expected_profile_identifier,
     const std::string& result,
+    const bool expected_click_through,
     int expected_net_error_code) {
   EXPECT_CALL(*client_, UploadSecurityEventReport)
       .WillOnce([this, expected_url, expected_reason, expected_profile_username,
-                 expected_profile_identifier, result, expected_net_error_code](
+                 expected_profile_identifier, result, expected_click_through,
+                 expected_net_error_code](
                     bool include_device_info, base::Value::Dict report,
                     base::OnceCallback<void(policy::CloudPolicyClient::Result)>
                         callback) {
@@ -384,7 +386,7 @@
         ValidateField(event, kKeyURL, expected_url);
         ValidateField(event, kKeyReason, expected_reason);
         ValidateField(event, kKeyNetErrorCode, expected_net_error_code);
-        ValidateField(event, kKeyClickedThrough, false);
+        ValidateField(event, kKeyClickedThrough, expected_click_through);
         ValidateField(event, kKeyProfileUserName, expected_profile_username);
         ValidateField(event, kKeyProfileIdentifier,
                       expected_profile_identifier);
diff --git a/components/enterprise/connectors/core/reporting_test_utils.h b/components/enterprise/connectors/core/reporting_test_utils.h
index ab89ed0a..69f5faf 100644
--- a/components/enterprise/connectors/core/reporting_test_utils.h
+++ b/components/enterprise/connectors/core/reporting_test_utils.h
@@ -60,12 +60,13 @@
 
   // TODO(crbug.com/396436374): Use secutiry interstital event proto instead of
   // raw json string for validation.
-  void ExpectSecurityInterstitialShown(
+  void ExpectSecurityInterstitialEvent(
       const std::string& expected_url,
       const std::string& expected_reason,
       const std::string& expected_profile_username,
       const std::string& expected_profile_identifier,
       const std::string& result,
+      const bool expected_click_through,
       int expected_net_error_code);
 
  protected:
diff --git a/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java b/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java
index 2847258..8b48cab 100644
--- a/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java
+++ b/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java
@@ -26,7 +26,7 @@
     // update the histogram suffix ImageFetcherClients in histograms.xml as well.
     public static final String ASSISTANT_DETAILS_UMA_CLIENT_NAME = "AssistantDetails";
     public static final String ASSISTANT_INFO_BOX_UMA_CLIENT_NAME = "AssistantInfoBox";
-    public static final String AUTOFILL_CARD_ART_UMA_CLIENT_NAME = "AutofillCardArt";
+    public static final String AUTOFILL_IMAGE_FETCHER_UMA_CLIENT_NAME = "AutofillImageFetcher";
     public static final String CRYPTIDS_UMA_CLIENT_NAME = "Cryptids";
     public static final String DATA_SHARING_UMA_CLIENT_NAME = "DataSharing";
     public static final String OMNIBOX_UMA_CLIENT_NAME = "Omnibox";
diff --git a/components/ip_protection/common/ip_protection_probabilistic_reveal_token_data_storage.cc b/components/ip_protection/common/ip_protection_probabilistic_reveal_token_data_storage.cc
index fba22eb2..bbc53c68 100644
--- a/components/ip_protection/common/ip_protection_probabilistic_reveal_token_data_storage.cc
+++ b/components/ip_protection/common/ip_protection_probabilistic_reveal_token_data_storage.cc
@@ -10,6 +10,7 @@
 #include "base/base64.h"
 #include "base/base64url.h"
 #include "base/files/file_util.h"
+#include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/numerics/byte_conversions.h"
 #include "components/ip_protection/common/ip_protection_probabilistic_reveal_token_fetcher.h"
diff --git a/components/language/core/browser/language_usage_metrics.h b/components/language/core/browser/language_usage_metrics.h
index 02a6135..6a46c33 100644
--- a/components/language/core/browser/language_usage_metrics.h
+++ b/components/language/core/browser/language_usage_metrics.h
@@ -35,7 +35,7 @@
       const language::UrlLanguageHistogram& language_counts);
 
   // Maps |locale| to a hash value in the "LanguageName" enum.
-  // Deprecated - please use the enum "LocaleCodeISO639" which maps the full
+  // Deprecated - please use the enum "LocaleCodeBCP47" which maps the full
   // locale including country variant to a base::HashMetricName value.
   //
   // The language hash is calculated by splitting the locale on "-" and bit
diff --git a/components/lens/lens_features.cc b/components/lens/lens_features.cc
index dab9daf..9103c70 100644
--- a/components/lens/lens_features.cc
+++ b/components/lens/lens_features.cc
@@ -95,6 +95,10 @@
              "LensOverlayCornerSliders",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+BASE_FEATURE(kLensSearchProtectedPage,
+             "LensSearchProtectedPage",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 const base::FeatureParam<int> kLensOverlayMinRamMb{&kLensOverlay, "min_ram_mb",
                                                    /*default=value=*/-1};
 const base::FeatureParam<std::string> kActivityUrl{
@@ -1045,4 +1049,8 @@
   return kLensOverlaySliderChangedTimeout.Get();
 }
 
+bool IsLensSearchProtectedPageEnabled() {
+  return base::FeatureList::IsEnabled(kLensSearchProtectedPage);
+}
+
 }  // namespace lens::features
diff --git a/components/lens/lens_features.h b/components/lens/lens_features.h
index 92a3acba..5d713d2 100644
--- a/components/lens/lens_features.h
+++ b/components/lens/lens_features.h
@@ -81,6 +81,10 @@
 COMPONENT_EXPORT(LENS_FEATURES)
 BASE_DECLARE_FEATURE(kLensOverlayCornerSliders);
 
+// Enables the protected error page in the Lens side panel.
+COMPONENT_EXPORT(LENS_FEATURES)
+BASE_DECLARE_FEATURE(kLensSearchProtectedPage);
+
 // The base URL for Lens.
 COMPONENT_EXPORT(LENS_FEATURES)
 extern const base::FeatureParam<std::string> kHomepageURLForLens;
@@ -813,5 +817,9 @@
 COMPONENT_EXPORT(LENS_FEATURES)
 extern int GetLensOverlaySliderChangedTimeout();
 
+// Whether the protected page for the side panel is enabled.
+COMPONENT_EXPORT(LENS_FEATURES)
+bool IsLensSearchProtectedPageEnabled();
+
 }  // namespace lens::features
 #endif  // COMPONENTS_LENS_LENS_FEATURES_H_
diff --git a/components/lens/lens_overlay_side_panel_result.h b/components/lens/lens_overlay_side_panel_result.h
index 2198a36..0755e94 100644
--- a/components/lens/lens_overlay_side_panel_result.h
+++ b/components/lens/lens_overlay_side_panel_result.h
@@ -24,8 +24,10 @@
   // The error page was shown due to the initial full image query failing due to
   // error.
   kErrorPageShownStartQueryError = 3,
+  // The error page was shown because page was protected.
+  kErrorPageShownProtected = 4,
 
-  kMaxValue = kErrorPageShownStartQueryError
+  kMaxValue = kErrorPageShownProtected
 };
 // LINT.ThenChange(//tools/metrics/histograms/metadata/lens/enums.xml:LensOverlaySidePanelResultStatus)
 }  // namespace lens
diff --git a/components/omnibox/browser/document_provider.cc b/components/omnibox/browser/document_provider.cc
index ea2d90c..38f1973 100644
--- a/components/omnibox/browser/document_provider.cc
+++ b/components/omnibox/browser/document_provider.cc
@@ -524,6 +524,11 @@
 
   debouncer_->CancelRequest();
 
+  if (auto* remote_suggestions_service =
+          client_->GetRemoteSuggestionsService(/*create_if_necessary=*/false)) {
+    remote_suggestions_service->StopCreatingDocumentSuggestionsRequest();
+  }
+
   // If the request was sent, then log its duration and that it was invalidated.
   if (loader_) {
     DCHECK(!time_run_invoked_.is_null());
@@ -542,11 +547,6 @@
     LogTotalTime(time_run_invoked_, true);
     time_run_invoked_ = base::TimeTicks();
   }
-
-  if (auto* remote_suggestions_service =
-          client_->GetRemoteSuggestionsService(/*create_if_necessary=*/false)) {
-    remote_suggestions_service->StopCreatingDocumentSuggestionsRequest();
-  }
 }
 
 void DocumentProvider::DeleteMatch(const AutocompleteMatch& match) {
diff --git a/components/omnibox/browser/document_suggestions_service.h b/components/omnibox/browser/document_suggestions_service.h
index f51bcd2..8dfc66f 100644
--- a/components/omnibox/browser/document_suggestions_service.h
+++ b/components/omnibox/browser/document_suggestions_service.h
@@ -60,7 +60,7 @@
                                         StartCallback start_callback,
                                         CompletionCallback completion_callback);
 
-  // Advises the service to stop any process that creates a suggestion request.
+  // Stops creating the request. Already created requests aren't affected.
   void StopCreatingDocumentSuggestionsRequest();
 
   signin::Tribool account_is_subject_to_enterprise_policies() {
diff --git a/components/omnibox/browser/enterprise_search_aggregator_provider.cc b/components/omnibox/browser/enterprise_search_aggregator_provider.cc
index f18ca5b..34a38f8 100644
--- a/components/omnibox/browser/enterprise_search_aggregator_provider.cc
+++ b/components/omnibox/browser/enterprise_search_aggregator_provider.cc
@@ -487,6 +487,13 @@
   if (!due_to_user_inactivity) {
     AutocompleteProvider::Stop(clear_cached_results, due_to_user_inactivity);
     debouncer_->CancelRequest();
+
+    if (auto* remote_suggestions_service = client_->GetRemoteSuggestionsService(
+            /*create_if_necessary=*/false)) {
+      remote_suggestions_service
+          ->StopCreatingEnterpriseSearchAggregatorSuggestionsRequest();
+    }
+
     if (loader_) {
       LogResponseTime(true);
       loader_.reset();
diff --git a/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.cc b/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.cc
index 0eb6933..f1f1d13f 100644
--- a/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.cc
+++ b/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.cc
@@ -152,6 +152,11 @@
       signin::ConsentLevel::kSignin);
 }
 
+void EnterpriseSearchAggregatorSuggestionsService::
+    StopCreatingEnterpriseSearchAggregatorSuggestionsRequest() {
+  token_fetcher_.reset();
+}
+
 void EnterpriseSearchAggregatorSuggestionsService::AccessTokenAvailable(
     std::unique_ptr<network::ResourceRequest> request,
     std::string request_body,
diff --git a/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.h b/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.h
index 635c1a3..ade53df 100644
--- a/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.h
+++ b/components/omnibox/browser/enterprise_search_aggregator_suggestions_service.h
@@ -64,6 +64,9 @@
       CompletionCallback completion_callback,
       bool in_keyword_mode);
 
+  // Stops creating the request. Already created requests aren't affected.
+  void StopCreatingEnterpriseSearchAggregatorSuggestionsRequest();
+
  private:
   // Called when an access token request completes (successfully or not).
   void AccessTokenAvailable(std::unique_ptr<network::ResourceRequest> request,
diff --git a/components/omnibox/browser/remote_suggestions_service.cc b/components/omnibox/browser/remote_suggestions_service.cc
index e4419b2..0802d93 100644
--- a/components/omnibox/browser/remote_suggestions_service.cc
+++ b/components/omnibox/browser/remote_suggestions_service.cc
@@ -517,6 +517,14 @@
           in_keyword_mode);
 }
 
+void RemoteSuggestionsService::
+    StopCreatingEnterpriseSearchAggregatorSuggestionsRequest() {
+  if (enterprise_search_aggregator_suggestions_service_) {
+    enterprise_search_aggregator_suggestions_service_
+        ->StopCreatingEnterpriseSearchAggregatorSuggestionsRequest();
+  }
+}
+
 std::unique_ptr<network::SimpleURLLoader>
 RemoteSuggestionsService::StartDeletionRequest(
     const std::string& deletion_url,
diff --git a/components/omnibox/browser/remote_suggestions_service.h b/components/omnibox/browser/remote_suggestions_service.h
index a0870f7..9bf31ba 100644
--- a/components/omnibox/browser/remote_suggestions_service.h
+++ b/components/omnibox/browser/remote_suggestions_service.h
@@ -211,8 +211,7 @@
                                         StartCallback start_callback,
                                         CompletionCallback completion_callback);
 
-  // Advises the service to stop any process that creates a document suggestion
-  // request.
+  // Stops creating the request. Already created requests aren't affected.
   void StopCreatingDocumentSuggestionsRequest();
 
   // Creates and starts an enterprise search aggregator suggestion request using
@@ -225,6 +224,9 @@
       CompletionCallback completion_callback,
       bool in_keyword_mode);
 
+  // Stops creating the request. Already created requests aren't affected.
+  void StopCreatingEnterpriseSearchAggregatorSuggestionsRequest();
+
   // Creates and returns a loader to delete personalized suggestions.
   //
   // `deletion_url` must be a valid URL.
diff --git a/components/optimization_guide/content/browser/BUILD.gn b/components/optimization_guide/content/browser/BUILD.gn
index 6f5fb2e..3a31555 100644
--- a/components/optimization_guide/content/browser/BUILD.gn
+++ b/components/optimization_guide/content/browser/BUILD.gn
@@ -44,6 +44,28 @@
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
 }
 
+source_set("page_context_eligibility_api") {
+  public = [ "page_context_eligibility_api.h" ]
+  sources = [ "page_context_eligibility_api.cc" ]
+}
+
+static_library("page_context_eligibility") {
+  public = [ "page_context_eligibility.h" ]
+  sources = [ "page_context_eligibility.cc" ]
+
+  public_deps = [
+    ":page_context_eligibility_api",
+    "//base",
+    "//components/optimization_guide/core:optimization_guide_library_holder",
+  ]
+
+  if (build_with_internal_optimization_guide) {
+    data_deps = [
+      "//components/optimization_guide/internal:optimization_guide_internal",
+    ]
+  }
+}
+
 source_set("unit_tests") {
   testonly = true
   sources = [
diff --git a/components/optimization_guide/content/browser/page_context_eligibility.cc b/components/optimization_guide/content/browser/page_context_eligibility.cc
new file mode 100644
index 0000000..4ccc124
--- /dev/null
+++ b/components/optimization_guide/content/browser/page_context_eligibility.cc
@@ -0,0 +1,52 @@
+// 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 "components/optimization_guide/content/browser/page_context_eligibility.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/no_destructor.h"
+#include "components/optimization_guide/content/browser/page_context_eligibility_api.h"
+#include "components/optimization_guide/core/optimization_guide_library_holder.h"
+
+namespace optimization_guide {
+
+PageContextEligibility::PageContextEligibility(
+    const PageContextEligibilityAPI* api)
+    : api_(api) {}
+PageContextEligibility::~PageContextEligibility() = default;
+
+// static
+PageContextEligibility* PageContextEligibility::Get() {
+  static base::NoDestructor<std::unique_ptr<PageContextEligibility>>
+      page_context_eligibility{Create()};
+  return page_context_eligibility->get();
+}
+
+// static
+DISABLE_CFI_DLSYM
+std::unique_ptr<PageContextEligibility> PageContextEligibility::Create() {
+  // TODO(crbug.com/414828945): Move this creation out of this file if multiple
+  // use cases for it in browser.
+  static base::NoDestructor<std::unique_ptr<OptimizationGuideLibraryHolder>>
+      holder{OptimizationGuideLibraryHolder::Create()};
+  // Pointer will be null if the library was not created.
+  OptimizationGuideLibraryHolder* holder_ptr = holder->get();
+  if (!holder_ptr) {
+    return {};
+  }
+
+  auto get_api = reinterpret_cast<PageContextEligibilityAPIGetter>(
+      holder_ptr->GetFunctionPointer("GetPageContextEligibilityAPI"));
+  if (!get_api) {
+    return {};
+  }
+
+  const PageContextEligibilityAPI* api = get_api();
+  if (!api) {
+    return {};
+  }
+  return base::WrapUnique(new PageContextEligibility(api));
+}
+
+}  // namespace optimization_guide
diff --git a/components/optimization_guide/content/browser/page_context_eligibility.h b/components/optimization_guide/content/browser/page_context_eligibility.h
new file mode 100644
index 0000000..9f9246e
--- /dev/null
+++ b/components/optimization_guide/content/browser/page_context_eligibility.h
@@ -0,0 +1,44 @@
+// 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 COMPONENTS_OPTIMIZATION_GUIDE_CONTENT_BROWSER_PAGE_CONTEXT_ELIGIBILITY_H_
+#define COMPONENTS_OPTIMIZATION_GUIDE_CONTENT_BROWSER_PAGE_CONTEXT_ELIGIBILITY_H_
+
+#include <memory>
+#include <optional>
+
+#include "base/component_export.h"
+#include "base/memory/raw_ptr.h"
+#include "base/scoped_native_library.h"
+#include "base/types/pass_key.h"
+#include "components/optimization_guide/content/browser/page_context_eligibility_api.h"
+
+namespace optimization_guide {
+
+class PageContextEligibility {
+ public:
+  explicit PageContextEligibility(const PageContextEligibilityAPI* api);
+  ~PageContextEligibility();
+  PageContextEligibility(const PageContextEligibility& other) = delete;
+  PageContextEligibility& operator=(const PageContextEligibility& other) =
+      delete;
+  PageContextEligibility(PageContextEligibility&& other) = delete;
+  PageContextEligibility& operator=(PageContextEligibility&& other) = delete;
+
+  // Gets a lazily initialized global instance of PageContextEligibility. May
+  // return null if the underlying library could not be loaded.
+  static PageContextEligibility* Get();
+
+  // Exposes the raw PageContextEligibilityAPI functions defined by the library.
+  const PageContextEligibilityAPI& api() const { return *api_; }
+
+ private:
+  static std::unique_ptr<PageContextEligibility> Create();
+
+  raw_ptr<const PageContextEligibilityAPI> api_;
+};
+
+}  // namespace optimization_guide
+
+#endif  // COMPONENTS_OPTIMIZATION_GUIDE_CONTENT_BROWSER_PAGE_CONTEXT_ELIGIBILITY_H_
diff --git a/components/optimization_guide/content/browser/page_context_eligibility_api.cc b/components/optimization_guide/content/browser/page_context_eligibility_api.cc
new file mode 100644
index 0000000..c595855
--- /dev/null
+++ b/components/optimization_guide/content/browser/page_context_eligibility_api.cc
@@ -0,0 +1,27 @@
+// 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 "components/optimization_guide/content/browser/page_context_eligibility_api.h"
+
+extern "C" {
+
+namespace optimization_guide {
+
+MetaTag::MetaTag(const std::string& name, const std::string& content)
+    : name(name), content(content) {}
+MetaTag::MetaTag(const MetaTag& other) = default;
+MetaTag& MetaTag::MetaTag::operator=(const MetaTag& other) = default;
+MetaTag::~MetaTag() = default;
+
+FrameMetadata::FrameMetadata(const std::string& host,
+                             const std::string& path,
+                             std::vector<MetaTag> meta_tags)
+    : host(host), path(path), meta_tags(std::move(meta_tags)) {}
+FrameMetadata::FrameMetadata(const FrameMetadata& other) = default;
+FrameMetadata& FrameMetadata::FrameMetadata::operator=(
+    const FrameMetadata& other) = default;
+FrameMetadata::~FrameMetadata() = default;
+}  // namespace optimization_guide
+
+}  // extern "C"
diff --git a/components/optimization_guide/content/browser/page_context_eligibility_api.h b/components/optimization_guide/content/browser/page_context_eligibility_api.h
new file mode 100644
index 0000000..87a02302
--- /dev/null
+++ b/components/optimization_guide/content/browser/page_context_eligibility_api.h
@@ -0,0 +1,59 @@
+// 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 COMPONENTS_OPTIMIZATION_GUIDE_CONTENT_BROWSER_PAGE_CONTEXT_ELIGIBILITY_API_H_
+#define COMPONENTS_OPTIMIZATION_GUIDE_CONTENT_BROWSER_PAGE_CONTEXT_ELIGIBILITY_API_H_
+
+#include <string>
+#include <vector>
+
+extern "C" {
+
+namespace optimization_guide {
+
+// A meta tag represented by its name and content attributes.
+struct MetaTag {
+  explicit MetaTag(const std::string& name, const std::string& content);
+  MetaTag(const MetaTag& other);
+  MetaTag& operator=(const MetaTag& other);
+  ~MetaTag();
+
+  std::string name;
+  std::string content;
+};
+
+// Metadata about a frame.
+struct FrameMetadata {
+  explicit FrameMetadata(const std::string& host,
+                         const std::string& path,
+                         std::vector<MetaTag> meta_tags);
+  FrameMetadata(const FrameMetadata& other);
+  FrameMetadata& operator=(const FrameMetadata& other);
+  ~FrameMetadata();
+
+  // The host of the URL of the frame.
+  std::string host;
+  // The path of the URL of the frame.
+  std::string path;
+  std::vector<MetaTag> meta_tags;
+};
+
+// Table of C API functions defined within the library.
+struct PageContextEligibilityAPI {
+  // Whether the page is context eligible.
+  bool (*IsPageContextEligible)(
+      const std::string& host,
+      const std::string& path,
+      std::vector<optimization_guide::FrameMetadata> frame_metadata);
+};
+
+// Signature of the GetPageContextEligibilityAPI() function which the shared
+// library exports.
+using PageContextEligibilityAPIGetter = const PageContextEligibilityAPI* (*)();
+
+}  // namespace optimization_guide
+
+}  // extern "C"
+
+#endif  // COMPONENTS_OPTIMIZATION_GUIDE_CONTENT_BROWSER_PAGE_CONTEXT_ELIGIBILITY_API_H_
diff --git a/components/optimization_guide/core/BUILD.gn b/components/optimization_guide/core/BUILD.gn
index 9f20a8c..e7ddf75 100644
--- a/components/optimization_guide/core/BUILD.gn
+++ b/components/optimization_guide/core/BUILD.gn
@@ -684,6 +684,13 @@
   }
 }
 
+source_set("optimization_guide_library_holder") {
+  public = [ "optimization_guide_library_holder.h" ]
+  sources = [ "optimization_guide_library_holder.cc" ]
+
+  public_deps = [ "//base" ]
+}
+
 action("on_device_model_execution_proto_generator") {
   script =
       "//components/optimization_guide/tools/gen_on_device_proto_descriptors.py"
diff --git a/components/optimization_guide/core/optimization_guide_library_holder.cc b/components/optimization_guide/core/optimization_guide_library_holder.cc
new file mode 100644
index 0000000..6cdf1951
--- /dev/null
+++ b/components/optimization_guide/core/optimization_guide_library_holder.cc
@@ -0,0 +1,78 @@
+// 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 "components/optimization_guide/core/optimization_guide_library_holder.h"
+
+#include <memory>
+#include <optional>
+
+#include "base/base_paths.h"
+#include "base/check_is_test.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/raw_ptr.h"
+#include "base/path_service.h"
+#include "base/scoped_native_library.h"
+#include "base/types/pass_key.h"
+
+#if BUILDFLAG(IS_MAC)
+#include "base/apple/bundle_locations.h"
+#include "base/apple/foundation_util.h"
+#endif
+
+namespace optimization_guide {
+
+namespace {
+constexpr std::string_view kSharedLibraryName = "optimization_guide_internal";
+}
+
+base::FilePath GetSharedLibraryPath() {
+  base::FilePath base_dir;
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_FUCHSIA)
+#if BUILDFLAG(IS_MAC)
+  if (base::apple::AmIBundled()) {
+    base_dir = base::apple::FrameworkBundlePath().Append("Libraries");
+  } else {
+#endif  // BUILDFLAG(IS_MAC)
+    CHECK(base::PathService::Get(base::DIR_MODULE, &base_dir));
+#if BUILDFLAG(IS_MAC)
+  }
+#endif  // BUILDFLAG(IS_MAC)
+#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) &&
+        // !BUILDFLAG(IS_FUCHSIA)
+
+  return base_dir.AppendASCII(
+      base::GetNativeLibraryName(std::string(kSharedLibraryName)));
+}
+
+OptimizationGuideLibraryHolder::OptimizationGuideLibraryHolder(
+    base::PassKey<OptimizationGuideLibraryHolder>,
+    base::ScopedNativeLibrary library)
+    : library_(std::move(library)) {}
+
+OptimizationGuideLibraryHolder::~OptimizationGuideLibraryHolder() = default;
+
+// static
+DISABLE_CFI_DLSYM
+std::unique_ptr<OptimizationGuideLibraryHolder>
+OptimizationGuideLibraryHolder::Create() {
+  base::NativeLibraryLoadError error;
+  base::NativeLibrary library =
+      base::LoadNativeLibrary(GetSharedLibraryPath(), &error);
+  if (!library) {
+    return {};
+  }
+
+  base::ScopedNativeLibrary scoped_library(library);
+  return std::make_unique<OptimizationGuideLibraryHolder>(
+      base::PassKey<OptimizationGuideLibraryHolder>(),
+      std::move(scoped_library));
+}
+
+void* OptimizationGuideLibraryHolder::GetFunctionPointer(
+    const char* function_name) {
+  return library_.GetFunctionPointer(function_name);
+}
+
+}  // namespace optimization_guide
diff --git a/components/optimization_guide/core/optimization_guide_library_holder.h b/components/optimization_guide/core/optimization_guide_library_holder.h
new file mode 100644
index 0000000..1b18616
--- /dev/null
+++ b/components/optimization_guide/core/optimization_guide_library_holder.h
@@ -0,0 +1,51 @@
+// 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 COMPONENTS_OPTIMIZATION_GUIDE_CORE_OPTIMIZATION_GUIDE_LIBRARY_HOLDER_H_
+#define COMPONENTS_OPTIMIZATION_GUIDE_CORE_OPTIMIZATION_GUIDE_LIBRARY_HOLDER_H_
+
+#include <memory>
+#include <optional>
+
+#include "base/memory/raw_ptr.h"
+#include "base/scoped_native_library.h"
+#include "base/types/pass_key.h"
+
+namespace optimization_guide {
+
+base::FilePath GetSharedLibraryPath();
+
+// A OptimizationGuideLibraryHolder object encapsulates a reference to the
+// PageContextEligibilityAPI shared library, exposing the library's API
+// functions to callers and ensuring that the library remains loaded and usable
+// throughout the object's lifetime.
+class OptimizationGuideLibraryHolder {
+ public:
+  OptimizationGuideLibraryHolder(base::PassKey<OptimizationGuideLibraryHolder>,
+                                 base::ScopedNativeLibrary library);
+  ~OptimizationGuideLibraryHolder();
+
+  OptimizationGuideLibraryHolder(const OptimizationGuideLibraryHolder& other) =
+      delete;
+  OptimizationGuideLibraryHolder& operator=(
+      const OptimizationGuideLibraryHolder& other) = delete;
+
+  OptimizationGuideLibraryHolder(OptimizationGuideLibraryHolder&& other) =
+      default;
+  OptimizationGuideLibraryHolder& operator=(
+      OptimizationGuideLibraryHolder&& other) = default;
+
+  // Creates an instance of OptimizationGuideLibraryHolder. May return nullopt
+  // if the underlying library could not be loaded.
+  static std::unique_ptr<OptimizationGuideLibraryHolder> Create();
+
+  void* GetFunctionPointer(const char* function_name);
+
+ private:
+  base::ScopedNativeLibrary library_;
+};
+
+}  // namespace optimization_guide
+
+#endif  // COMPONENTS_OPTIMIZATION_GUIDE_CORE_OPTIMIZATION_GUIDE_LIBRARY_HOLDER_H_
diff --git a/components/policy/core/common/policy_proto_decoders_unittest.cc b/components/policy/core/common/policy_proto_decoders_unittest.cc
index 8fab36c..9d3b619 100644
--- a/components/policy/core/common/policy_proto_decoders_unittest.cc
+++ b/components/policy/core/common/policy_proto_decoders_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "components/policy/core/common/policy_proto_decoders.h"
 
-#include "base/json/json_reader.h"
 #include "base/strings/string_number_conversions.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/cloud/test/policy_builder.h"
@@ -196,10 +195,8 @@
   expected_policy_map_.Set(key::kManagedBookmarks, POLICY_LEVEL_MANDATORY,
                            POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
                            base::Value(invalidDummyJson), nullptr);
-  std::u16string kExpectedMessage =
-      base::JSONReader::UsingRust()
-          ? u"EOF while parsing an object at line 3 column 2"
-          : u"Line: 3, column: 3, Syntax error.";
+  const std::u16string kExpectedMessage =
+      u"EOF while parsing an object at line 3 column 2";
   expected_policy_map_.AddMessage(
       key::kManagedBookmarks, PolicyMap::MessageType::kError,
       IDS_POLICY_PROTO_PARSING_ERROR, {kExpectedMessage});
diff --git a/components/power_bookmarks/storage/power_bookmark_database_impl.cc b/components/power_bookmarks/storage/power_bookmark_database_impl.cc
index 1aaf216d2..892bc8f4 100644
--- a/components/power_bookmarks/storage/power_bookmark_database_impl.cc
+++ b/components/power_bookmarks/storage/power_bookmark_database_impl.cc
@@ -6,6 +6,7 @@
 
 #include "base/check.h"
 #include "base/files/file_util.h"
+#include "base/logging.h"
 #include "base/notreached.h"
 #include "base/strings/pattern.h"
 #include "base/strings/strcat.h"
diff --git a/components/privacy_sandbox/OWNERS b/components/privacy_sandbox/OWNERS
index aa054585..c48b3bad 100644
--- a/components/privacy_sandbox/OWNERS
+++ b/components/privacy_sandbox/OWNERS
@@ -1,6 +1,3 @@
-# Android UI
-andzaytsev@google.com
-
 # PAT settings
 # Notice and consent framework
 # UXR and HaTS frameworks
@@ -15,6 +12,3 @@
 
 # Backup for emergency approvals
 kmg@google.com
-
-# Owners for the PrivacySandboxSurveyService files
-per-file privacy_sandbox_survey_service*=kjarosz@google.com,dembski@google.com
diff --git a/components/privacy_sandbox/privacy_sandbox_attestations/preload/manifest.json b/components/privacy_sandbox/privacy_sandbox_attestations/preload/manifest.json
index 554ad63..f15ca59 100644
--- a/components/privacy_sandbox/privacy_sandbox_attestations/preload/manifest.json
+++ b/components/privacy_sandbox/privacy_sandbox_attestations/preload/manifest.json
@@ -1,6 +1,6 @@
 {
   "manifest_version": 2,
   "name": "Privacy Sandbox Attestations",
-  "version": "2025.4.23.0",
+  "version": "2025.4.30.0",
   "pre_installed": true
 }
\ No newline at end of file
diff --git a/components/privacy_sandbox/privacy_sandbox_attestations/preload/privacy-sandbox-attestations.dat b/components/privacy_sandbox/privacy_sandbox_attestations/preload/privacy-sandbox-attestations.dat
index 4416b55..826defc2 100644
--- a/components/privacy_sandbox/privacy_sandbox_attestations/preload/privacy-sandbox-attestations.dat
+++ b/components/privacy_sandbox/privacy_sandbox_attestations/preload/privacy-sandbox-attestations.dat
Binary files differ
diff --git a/components/services/storage/dom_storage/async_dom_storage_database.cc b/components/services/storage/dom_storage/async_dom_storage_database.cc
index cf10edf5..b8b1cef3 100644
--- a/components/services/storage/dom_storage/async_dom_storage_database.cc
+++ b/components/services/storage/dom_storage/async_dom_storage_database.cc
@@ -17,6 +17,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "base/task/sequenced_task_runner.h"
 #include "third_party/leveldatabase/env_chromium.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
@@ -80,8 +81,31 @@
                       [](std::vector<BatchDatabaseTask> tasks,
                          const DomStorageDatabase& db) {
                         leveldb::WriteBatch batch;
-                        for (auto& task : tasks)
+                        size_t iteration_count = 0;
+                        for (auto& task : tasks) {
+                          iteration_count++;
+                          size_t current_batch_size = batch.ApproximateSize();
                           std::move(task).Run(&batch, db);
+                          size_t new_batch_size = batch.ApproximateSize();
+                          size_t growth = new_batch_size - current_batch_size;
+                          base::UmaHistogramCustomCounts(
+                              "Storage.DomStorage."
+                              "BatchTaskGrowthSizeBytes",
+                              growth, 1, 100 * 1024 * 1024, 50);
+                          const size_t kTargetBatchSizesMB[] = {20, 100, 500};
+                          for (size_t batch_size_mb : kTargetBatchSizesMB) {
+                            size_t target_batch_size =
+                                batch_size_mb * 1024 * 1024;
+                            if (current_batch_size < target_batch_size &&
+                                new_batch_size >= target_batch_size) {
+                              base::UmaHistogramCounts10000(
+                                  base::StringPrintf("Storage.DomStorage."
+                                                     "IterationsToReach%zuMB",
+                                                     batch_size_mb),
+                                  iteration_count);
+                            }
+                          }
+                        }
                         return db.Commit(&batch);
                       },
                       std::move(tasks)),
diff --git a/components/translate/core/browser/translate_browser_metrics.h b/components/translate/core/browser/translate_browser_metrics.h
index 47d1014..10d9161 100644
--- a/components/translate/core/browser/translate_browser_metrics.h
+++ b/components/translate/core/browser/translate_browser_metrics.h
@@ -63,12 +63,12 @@
 void ReportLanguageDetectionContentLength(size_t length);
 
 // Called when a request is sent to the translate server to report the source
-// language of the translated page. Buckets are labelled with LocaleCodeISO639
+// language of the translated page. Buckets are labelled with LocaleCodeBCP47
 // values.
 void ReportTranslateSourceLanguage(std::string_view language);
 
 // Called when a request is sent to the translate server to report the target
-// language for the translated page. Buckets are labelled with LocaleCodeISO639
+// language for the translated page. Buckets are labelled with LocaleCodeBCP47
 // values.
 void ReportTranslateTargetLanguage(std::string_view language);
 
diff --git a/components/viz/service/display/renderer_pixeltest.cc b/components/viz/service/display/renderer_pixeltest.cc
index e07e75b..d8df32c9 100644
--- a/components/viz/service/display/renderer_pixeltest.cc
+++ b/components/viz/service/display/renderer_pixeltest.cc
@@ -71,7 +71,6 @@
 #include "ui/gfx/geometry/mask_filter_info.h"
 #include "ui/gfx/geometry/skia_conversions.h"
 #include "ui/gfx/geometry/transform_util.h"
-#include "ui/gfx/test/icc_profiles.h"
 #include "ui/gfx/video_types.h"
 #include "ui/gl/gl_implementation.h"
 
@@ -6217,29 +6216,103 @@
 using PrimaryID = gfx::ColorSpace::PrimaryID;
 using TransferID = gfx::ColorSpace::TransferID;
 
+enum class NamedColorSpace {
+  kBt709Bt709,
+  kWideGamutColorSpinGamma28,
+  kBt709LinearHdr,
+  kBt709Linear,
+  kBt709SrgbHdr,
+  kBt709Srgb,
+  kXyzD50Linear,
+  kXyzD50SrgbHdr,
+  kHdr10,
+  kHlg,
+  kScrgbLinear80Nits,
+};
+
+const char* ToString(NamedColorSpace named_color_space) {
+  // Note that these names are used in the test parametrization stringification
+  // and thus used in test filter files.
+  switch (named_color_space) {
+    case NamedColorSpace::kBt709Bt709:
+      return "Bt709Bt709";
+    case NamedColorSpace::kWideGamutColorSpinGamma28:
+      return "WideGamutColorSpinGamma28";
+    case NamedColorSpace::kBt709LinearHdr:
+      return "Bt709LinearHdr";
+    case NamedColorSpace::kBt709Linear:
+      return "Bt709Linear";
+    case NamedColorSpace::kBt709SrgbHdr:
+      return "Bt709SrgbHdr";
+    case NamedColorSpace::kBt709Srgb:
+      return "Bt709Srgb";
+    case NamedColorSpace::kXyzD50Linear:
+      return "XyzD50Linear";
+    case NamedColorSpace::kXyzD50SrgbHdr:
+      return "XyzD50SrgbHdr";
+    case NamedColorSpace::kHdr10:
+      return "Hdr10";
+    case NamedColorSpace::kHlg:
+      return "Hlg";
+    case NamedColorSpace::kScrgbLinear80Nits:
+      return "ScrgbLinear80Nits";
+  }
+  NOTREACHED();
+}
+
+gfx::ColorSpace GetColorSpace(NamedColorSpace named_color_space) {
+  switch (named_color_space) {
+    case NamedColorSpace::kBt709Bt709:
+      return gfx::ColorSpace(PrimaryID::BT709, TransferID::BT709);
+    case NamedColorSpace::kWideGamutColorSpinGamma28:
+      return gfx::ColorSpace(PrimaryID::WIDE_GAMUT_COLOR_SPIN,
+                             TransferID::GAMMA28);
+    case NamedColorSpace::kBt709LinearHdr:
+      return gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR_HDR);
+    case NamedColorSpace::kBt709Linear:
+      return gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR);
+    case NamedColorSpace::kBt709SrgbHdr:
+      return gfx::ColorSpace(PrimaryID::BT709, TransferID::SRGB_HDR);
+    case NamedColorSpace::kBt709Srgb:
+      return gfx::ColorSpace(PrimaryID::BT709, TransferID::SRGB);
+    case NamedColorSpace::kXyzD50Linear:
+      return gfx::ColorSpace(PrimaryID::XYZ_D50, TransferID::LINEAR);
+    case NamedColorSpace::kXyzD50SrgbHdr:
+      return gfx::ColorSpace(PrimaryID::XYZ_D50, TransferID::SRGB_HDR);
+    case NamedColorSpace::kHdr10:
+      return gfx::ColorSpace::CreateHDR10();
+    case NamedColorSpace::kHlg:
+      return gfx::ColorSpace::CreateHLG();
+    case NamedColorSpace::kScrgbLinear80Nits:
+      return gfx::ColorSpace::CreateSCRGBLinear80Nits();
+  }
+  NOTREACHED();
+}
+
 class ColorTransformPixelTest
     : public VizPixelTest,
       public testing::WithParamInterface<std::tuple<RendererType,
-                                                    gfx::ColorSpace,
-                                                    gfx::ColorSpace,
+                                                    NamedColorSpace,
+                                                    NamedColorSpace,
                                                     bool,
                                                     bool>> {
  public:
+  static std::string GetParamName(
+      const testing::TestParamInfo<ParamType>& info) {
+    return base::StringPrintf(
+        "%s_%s_%s_%s%s", testing::PrintToString(std::get<0>(info.param)),
+        ToString(std::get<1>(info.param)), ToString(std::get<2>(info.param)),
+        std::get<3>(info.param) ? "premul" : "unpremul",
+        std::get<4>(info.param) ? "_ColorConversionInRenderer" : "");
+  }
+
   ColorTransformPixelTest() : VizPixelTest(std::get<0>(GetParam())) {
     // Note that this size of 17 is not random -- it is chosen to match the
     // size of LUTs that are created. If we did not match the LUT size exactly,
     // then the error for LUT based transforms is much larger.
     this->device_viewport_size_ = gfx::Size(17, 5);
-    this->src_color_space_ = std::get<1>(GetParam());
-    this->dst_color_space_ = std::get<2>(GetParam());
-    if (!this->src_color_space_.IsValid()) {
-      this->src_color_space_ =
-          gfx::ICCProfileForTestingNoAnalyticTrFn().GetColorSpace();
-    }
-    if (!this->dst_color_space_.IsValid()) {
-      this->dst_color_space_ =
-          gfx::ICCProfileForTestingNoAnalyticTrFn().GetColorSpace();
-    }
+    this->src_color_space_ = GetColorSpace(std::get<1>(GetParam()));
+    this->dst_color_space_ = GetColorSpace(std::get<2>(GetParam()));
     this->display_color_spaces_ =
         gfx::DisplayColorSpaces(this->dst_color_space_);
     if (this->dst_color_space_.IsWide()) {
@@ -6313,13 +6386,6 @@
   }
 
   void Basic() {
-#if BUILDFLAG(IS_IOS)
-    if (this->src_color_space_.IsToneMappedByDefault() &&
-        !this->dst_color_space_.IsHDR()) {
-      GTEST_SKIP() << "Skipping tonemapped src for non-hdr dst";
-    }
-#endif
-
     gfx::Rect rect(this->device_viewport_size_);
     std::vector<uint8_t> input_colors(4 * rect.width() * rect.height(), 0);
     std::vector<SkColor> expected_output_colors(rect.width() * rect.height());
@@ -6455,8 +6521,7 @@
                           .SetAvgAbsErrorLimit(avg_abs_error_limit)
                           .SetAbsErrorLimit(max_abs_error_limit);
     EXPECT_TRUE(
-        this->RunPixelTest(&pass_list, &expected_output_colors, comparator))
-        << " src:" << src_color_space_ << ", dst:" << dst_color_space_;
+        this->RunPixelTest(&pass_list, &expected_output_colors, comparator));
   }
 
   base::test::ScopedFeatureList features_;
@@ -6483,28 +6548,22 @@
   Basic();
 }
 
-gfx::ColorSpace src_color_spaces[] = {
-    gfx::ColorSpace(PrimaryID::BT709, TransferID::BT709),
-    gfx::ColorSpace(PrimaryID::WIDE_GAMUT_COLOR_SPIN, TransferID::GAMMA28),
-    gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR),
-    gfx::ColorSpace(PrimaryID::BT709, TransferID::SRGB),
-    gfx::ColorSpace(PrimaryID::BT709, TransferID::SRGB_HDR),
-    gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR_HDR),
-    gfx::ColorSpace::CreateHDR10(),
+NamedColorSpace src_color_spaces[] = {
+    NamedColorSpace::kBt709Bt709,   NamedColorSpace::kWideGamutColorSpinGamma28,
+    NamedColorSpace::kBt709Linear,  NamedColorSpace::kBt709Srgb,
+    NamedColorSpace::kBt709SrgbHdr, NamedColorSpace::kBt709LinearHdr,
+    NamedColorSpace::kHdr10,
 };
 
-gfx::ColorSpace dst_color_spaces[] = {
-    gfx::ColorSpace(PrimaryID::BT709, TransferID::BT709),
-    gfx::ColorSpace(PrimaryID::WIDE_GAMUT_COLOR_SPIN, TransferID::GAMMA28),
-    gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR),
-    gfx::ColorSpace(PrimaryID::BT709, TransferID::SRGB),
-    gfx::ColorSpace(PrimaryID::BT709, TransferID::SRGB_HDR),
-    gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR_HDR),
+NamedColorSpace dst_color_spaces[] = {
+    NamedColorSpace::kBt709Bt709,   NamedColorSpace::kWideGamutColorSpinGamma28,
+    NamedColorSpace::kBt709Linear,  NamedColorSpace::kBt709Srgb,
+    NamedColorSpace::kBt709SrgbHdr, NamedColorSpace::kBt709LinearHdr,
 };
 
-gfx::ColorSpace intermediate_color_spaces[] = {
-    gfx::ColorSpace(PrimaryID::XYZ_D50, TransferID::LINEAR),
-    gfx::ColorSpace(PrimaryID::XYZ_D50, TransferID::SRGB_HDR),
+NamedColorSpace intermediate_color_spaces[] = {
+    NamedColorSpace::kXyzD50Linear,
+    NamedColorSpace::kXyzD50SrgbHdr,
 };
 
 INSTANTIATE_TEST_SUITE_P(
@@ -6514,7 +6573,8 @@
                      testing::ValuesIn(src_color_spaces),
                      testing::ValuesIn(intermediate_color_spaces),
                      testing::Bool(),
-                     testing::Values(false)));
+                     testing::Values(false)),
+    &ColorTransformPixelTest::GetParamName);
 
 INSTANTIATE_TEST_SUITE_P(
     ToColorSpace,
@@ -6523,7 +6583,8 @@
                      testing::ValuesIn(intermediate_color_spaces),
                      testing::ValuesIn(dst_color_spaces),
                      testing::Bool(),
-                     testing::Values(false)));
+                     testing::Values(false)),
+    &ColorTransformPixelTest::GetParamName);
 
 // Test cases that simulate HDR content with tone mapping, which may require
 // color conversion when the destination color space is not suitable for
@@ -6533,16 +6594,17 @@
     ColorTransformPixelTest,
     testing::Combine(testing::ValuesIn(GetGpuRendererTypes()),
                      testing::ValuesIn({
-                         gfx::ColorSpace::CreateExtendedSRGB(),
-                         gfx::ColorSpace::CreateHDR10(),
-                         gfx::ColorSpace::CreateHLG(),
+                         NamedColorSpace::kBt709SrgbHdr,
+                         NamedColorSpace::kHdr10,
+                         NamedColorSpace::kHlg,
                      }),
                      testing::ValuesIn({
-                         gfx::ColorSpace::CreateExtendedSRGB(),
-                         gfx::ColorSpace::CreateSCRGBLinear80Nits(),
+                         NamedColorSpace::kBt709SrgbHdr,
+                         NamedColorSpace::kScrgbLinear80Nits,
                      }),
                      testing::Bool(),
-                     testing::Bool()));
+                     testing::Bool()),
+    &ColorTransformPixelTest::GetParamName);
 
 // GetGpuRendererTypes() can return an empty list, e.g. on Fuchsia ARM64.
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ColorTransformPixelTest);
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc b/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc
index bfe012d..585db32 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc
@@ -157,13 +157,74 @@
       base::BindOnce([](bool* result) { *result = true; }, &on_finished_called);
   base::OnceCallback<void(gfx::GpuFenceHandle)> return_release_fence_cb;
 
-#if !BUILDFLAG(SKIA_USE_METAL)
+  gpu::SyncToken sync_token = PaintRootRenderPass(
+      output_rect, std::move(on_finished), std::move(return_release_fence_cb));
+  EXPECT_TRUE(sync_token.HasData());
+
+  // Copy the output
+  const gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
+  auto request = std::make_unique<CopyOutputRequest>(
+      CopyOutputRequest::ResultFormat::RGBA,
+      CopyOutputRequest::ResultDestination::kSystemMemory,
+      base::BindOnce(&SkiaOutputSurfaceImplTest::CopyRequestCallbackOnGpuThread,
+                     base::Unretained(this), output_rect, color_space));
+  request->set_result_task_runner(
+      TestGpuServiceHolder::GetInstance()->gpu_main_thread_task_runner());
+  copy_output::RenderPassGeometry geometry;
+  geometry.result_bounds = output_rect;
+  geometry.result_selection = output_rect;
+  geometry.sampling_bounds = output_rect;
+  geometry.readback_offset = gfx::Vector2d(0, 0);
+
+  output_surface_->CopyOutput(geometry, color_space, std::move(request),
+                              gpu::Mailbox());
+  output_surface_->SwapBuffersSkipped(kSurfaceRect);
+  output_surface_->Flush();
+  BlockMainThread();
+
+  // EndPaint draw is deferred until CopyOutput.
+  base::OnceClosure closure =
+      base::BindOnce(&SkiaOutputSurfaceImplTest::CheckSyncTokenOnGpuThread,
+                     base::Unretained(this), sync_token);
+
+  output_surface_->ScheduleGpuTaskForTesting(std::move(closure), {sync_token});
+  BlockMainThread();
+
+  // Let the cb to come back.
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(on_finished_called);
+}
+
+// TODO(crbug.com/40922049): Re-enable this test
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_EndPaintReleaseFence DISABLED_EndPaintReleaseFence
+#else
+#define MAYBE_EndPaintReleaseFence EndPaintReleaseFence
+#endif
+TEST_F(SkiaOutputSurfaceImplTest, MAYBE_EndPaintReleaseFence) {
+  // Skip test for Skia Graphite
+  gpu::GrContextType gr_context_type =
+      GetGpuService()->gpu_preferences().gr_context_type;
+  if (gr_context_type == gpu::GrContextType::kGraphiteDawn ||
+      gr_context_type == gpu::GrContextType::kGraphiteMetal) {
+    GTEST_SKIP();
+  }
+  OutputSurface::ReshapeParams reshape_params;
+  reshape_params.size = kSurfaceRect.size();
+  output_surface_->Reshape(reshape_params);
+  constexpr gfx::Rect output_rect(0, 0, 10, 10);
+
+  bool on_finished_called = false;
+  base::OnceClosure on_finished =
+      base::BindOnce([](bool* result) { *result = true; }, &on_finished_called);
+  base::OnceCallback<void(gfx::GpuFenceHandle)> return_release_fence_cb;
+
   bool on_return_release_fence_called = false;
   // This callback is unsupported when using Metal.
   return_release_fence_cb = base::BindOnce(
       [](bool* result, gfx::GpuFenceHandle handle) { *result = true; },
       &on_return_release_fence_called);
-#endif  // !BUILDFLAG(SKIA_USE_METAL)
 
   gpu::SyncToken sync_token = PaintRootRenderPass(
       output_rect, std::move(on_finished), std::move(return_release_fence_cb));
@@ -202,9 +263,7 @@
   base::RunLoop().RunUntilIdle();
 
   EXPECT_TRUE(on_finished_called);
-#if !BUILDFLAG(SKIA_USE_METAL)
   EXPECT_TRUE(on_return_release_fence_called);
-#endif  // !BUILDFLAG(SKIA_USE_METAL)
 }
 
 // Draws two frames and calls Reshape() between the two frames changing the
diff --git a/components/viz/service/surfaces/surface_saved_frame.cc b/components/viz/service/surfaces/surface_saved_frame.cc
index c5d91fa..9c390fb 100644
--- a/components/viz/service/surfaces/surface_saved_frame.cc
+++ b/components/viz/service/surfaces/surface_saved_frame.cc
@@ -160,7 +160,6 @@
       slot->is_software = is_software;
       slot->sync_token = shared_image->creation_sync_token();
       slot->shared_image = shared_image;
-      slot->draw_data = draw_data_[index];
       slot->release_callback = base::BindOnce(
           [](scoped_refptr<gpu::ClientSharedImage> image,
              const gpu::SyncToken& sync_token, bool is_lost) {
@@ -194,8 +193,7 @@
     return nullptr;
   }
 
-  RenderPassDrawData draw_data(render_pass);
-  draw_data_[shared_pass_index] = draw_data;
+  const gfx::Size size = render_pass.output_rect.size();
 
   auto request = std::make_unique<CopyOutputRequest>(
       kResultFormat, kResultDestination,
@@ -219,17 +217,16 @@
       gpu::SharedImageUsageSet flags = gpu::SHARED_IMAGE_USAGE_CPU_WRITE_ONLY;
       shared_image =
           shared_image_interface_->CreateSharedImageForSoftwareCompositor(
-              {image_format, draw_data.size, color_space, flags,
+              {image_format, size, color_space, flags,
                "ViewTransitionTexture"});
     } else {
       gpu::SharedImageUsageSet flags = gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
                                        gpu::SHARED_IMAGE_USAGE_DISPLAY_WRITE;
       shared_image = shared_image_interface_->CreateSharedImage(
-          {image_format, draw_data.size, color_space, flags,
-           "ViewTransitionTexture"},
+          {image_format, size, color_space, flags, "ViewTransitionTexture"},
           gpu::kNullSurfaceHandle);
     }
-    request->set_result_selection(gfx::Rect(draw_data.size));
+    request->set_result_selection(gfx::Rect(size));
     request->set_blit_request(BlitRequest(
         gfx::Point(), LetterboxingBehavior::kDoNotLetterbox,
         shared_image->mailbox(), shared_image->creation_sync_token(),
@@ -299,7 +296,6 @@
     result->sync_token = shared_image_interface_->GenVerifiedSyncToken();
     result->release_callback =
         base::DoNothingWithBoundArgs(result->shared_image);
-    result->draw_data.size = kDefaultTextureSizeForTesting;
     result->is_software = true;
   }
 
@@ -321,11 +317,6 @@
   DCHECK(IsValid());
 }
 
-SurfaceSavedFrame::RenderPassDrawData::RenderPassDrawData() = default;
-SurfaceSavedFrame::RenderPassDrawData::RenderPassDrawData(
-    const CompositorRenderPass& render_pass)
-    : size(render_pass.output_rect.size()) {}
-
 SurfaceSavedFrame::OutputCopyResult::OutputCopyResult() = default;
 SurfaceSavedFrame::OutputCopyResult::OutputCopyResult(
     OutputCopyResult&& other) {
@@ -351,8 +342,6 @@
 
   shared_image = std::move(other.shared_image);
 
-  draw_data = std::move(other.draw_data);
-
   release_callback = std::move(other.release_callback);
 
   is_software = other.is_software;
diff --git a/components/viz/service/surfaces/surface_saved_frame.h b/components/viz/service/surfaces/surface_saved_frame.h
index d1e141aa..f9844b08 100644
--- a/components/viz/service/surfaces/surface_saved_frame.h
+++ b/components/viz/service/surfaces/surface_saved_frame.h
@@ -34,14 +34,6 @@
   using CopyFinishedCallback =
       base::OnceCallback<void(const CompositorFrameTransitionDirective&)>;
 
-  struct RenderPassDrawData {
-    RenderPassDrawData();
-    explicit RenderPassDrawData(const CompositorRenderPass& render_pass);
-
-    // This represents the size of the copied texture.
-    gfx::Size size;
-  };
-
   struct OutputCopyResult {
     OutputCopyResult();
     OutputCopyResult(OutputCopyResult&& other);
@@ -58,10 +50,6 @@
     // Software image representation.
     scoped_refptr<gpu::ClientSharedImage> shared_image;
 
-    // This is information needed to draw the texture as if it was a part of the
-    // original frame.
-    RenderPassDrawData draw_data;
-
     // Is this a software or a GPU copy result?
     bool is_software = false;
 
@@ -161,9 +149,6 @@
   base::flat_map<size_t, scoped_refptr<gpu::ClientSharedImage>>
       blit_shared_images_;
 
-  // Stored draw data for the shared index.
-  base::flat_map<size_t, RenderPassDrawData> draw_data_;
-
   std::optional<FrameResult> frame_result_;
 
   // This is the number of copy requests we requested. We decrement this value
diff --git a/components/viz/service/transitions/transferable_resource_tracker.cc b/components/viz/service/transitions/transferable_resource_tracker.cc
index 500895f7..16b7e83 100644
--- a/components/viz/service/transitions/transferable_resource_tracker.cc
+++ b/components/viz/service/transitions/transferable_resource_tracker.cc
@@ -63,17 +63,17 @@
 
   DCHECK(output_copy.shared_image);
   if (output_copy.is_software) {
-      resource = TransferableResource::MakeSoftwareSharedImage(
-          output_copy.shared_image, gpu::SyncToken(),
-          output_copy.draw_data.size, output_copy.shared_image->format());
-      resource.color_space = output_copy.shared_image->color_space();
+    resource = TransferableResource::MakeSoftwareSharedImage(
+        output_copy.shared_image, gpu::SyncToken(),
+        output_copy.shared_image->size(), output_copy.shared_image->format());
+    resource.color_space = output_copy.shared_image->color_space();
   } else {
-      resource = TransferableResource::MakeGpu(
-          output_copy.shared_image, GL_TEXTURE_2D, output_copy.sync_token,
-          output_copy.draw_data.size, output_copy.shared_image->format(),
-          /*is_overlay_candidate=*/false,
-          TransferableResource::ResourceSource::kViewTransition);
-      resource.color_space = output_copy.shared_image->color_space();
+    resource = TransferableResource::MakeGpu(
+        output_copy.shared_image, GL_TEXTURE_2D, output_copy.sync_token,
+        output_copy.shared_image->size(), output_copy.shared_image->format(),
+        /*is_overlay_candidate=*/false,
+        TransferableResource::ResourceSource::kViewTransition);
+    resource.color_space = output_copy.shared_image->color_space();
   }
 
   TransferableResourceHolder::ResourceReleaseCallback release_callback;
@@ -94,7 +94,6 @@
 
   PositionedResource result;
   result.resource = resource;
-  result.draw_data = output_copy.draw_data;
   return result;
 }
 
diff --git a/components/viz/service/transitions/transferable_resource_tracker.h b/components/viz/service/transitions/transferable_resource_tracker.h
index ce9ae4b..1429572 100644
--- a/components/viz/service/transitions/transferable_resource_tracker.h
+++ b/components/viz/service/transitions/transferable_resource_tracker.h
@@ -30,7 +30,6 @@
   // This represents a resource that is positioned somewhere on screen.
   struct VIZ_SERVICE_EXPORT PositionedResource {
     TransferableResource resource;
-    SurfaceSavedFrame::RenderPassDrawData draw_data;
   };
 
   // A SurfaceSavedFrame can be converted to a ResourceFrame via
diff --git a/components/webapps/services/web_app_origin_association/web_app_origin_association_parser_impl_unittest.cc b/components/webapps/services/web_app_origin_association/web_app_origin_association_parser_impl_unittest.cc
index a8e2421..28dec86d 100644
--- a/components/webapps/services/web_app_origin_association/web_app_origin_association_parser_impl_unittest.cc
+++ b/components/webapps/services/web_app_origin_association/web_app_origin_association_parser_impl_unittest.cc
@@ -8,7 +8,6 @@
 #include <string>
 #include <utility>
 
-#include "base/json/json_reader.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -118,12 +117,7 @@
   ASSERT_TRUE(!association);
   ASSERT_FALSE(errors.empty());
   ASSERT_EQ(1u, errors.size());
-  if (base::JSONReader::UsingRust()) {
-    EXPECT_EQ(errors[0]->message,
-              "EOF while parsing a list at line 1 column 5");
-  } else {
-    EXPECT_EQ(errors[0]->message, "Line: 1, column: 6, Syntax error.");
-  }
+  EXPECT_EQ(errors[0]->message, "EOF while parsing a list at line 1 column 5");
 
   histogram_tester_.ExpectBucketCount(
       kParseResultHistogram,
diff --git a/components/webapps/services/web_app_origin_association/web_app_origin_association_parser_unittest.cc b/components/webapps/services/web_app_origin_association/web_app_origin_association_parser_unittest.cc
index afa40c9..5ad3b20 100644
--- a/components/webapps/services/web_app_origin_association/web_app_origin_association_parser_unittest.cc
+++ b/components/webapps/services/web_app_origin_association/web_app_origin_association_parser_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "components/webapps/services/web_app_origin_association/web_app_origin_association_parser.h"
 
-#include "base/json/json_reader.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -65,11 +64,7 @@
   EXPECT_TRUE(IsAssociationNull(association));
   EXPECT_EQ(1u, GetErrorCount());
 
-  if (base::JSONReader::UsingRust()) {
-    EXPECT_EQ(errors()[0], "EOF while parsing a value at line 1 column 0");
-  } else {
-    EXPECT_EQ(errors()[0], "Line: 1, column: 1, Unexpected token.");
-  }
+  EXPECT_EQ(errors()[0], "EOF while parsing a value at line 1 column 0");
 }
 
 TEST_F(WebAppOriginAssociationParserTest, NoContentParses) {
diff --git a/content/browser/android/web_contents_observer_proxy.cc b/content/browser/android/web_contents_observer_proxy.cc
index 6ccd1473..856ffc9 100644
--- a/content/browser/android/web_contents_observer_proxy.cc
+++ b/content/browser/android/web_contents_observer_proxy.cc
@@ -11,6 +11,7 @@
 #include "base/android/scoped_java_ref.h"
 #include "base/feature_list.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/trace_event/named_trigger.h"
 #include "base/trace_event/trace_event.h"
 #include "content/browser/android/navigation_handle_proxy.h"
 #include "content/browser/media/session/media_session_android.h"
@@ -173,6 +174,7 @@
   TRACE_EVENT0("browser", "Java_WebContentsObserverProxy_didFinishNavigation");
 
   if (navigation_handle->IsInPrimaryMainFrame()) {
+    base::trace_event::EmitNamedTrigger("did-finish-navigation-in-pmf");
     Java_WebContentsObserverProxy_didFinishNavigationInPrimaryMainFrame(
         AttachCurrentThread(), java_observer_,
         navigation_handle->GetJavaNavigationHandle());
diff --git a/content/browser/devtools/protocol/bluetooth_emulation_handler.cc b/content/browser/devtools/protocol/bluetooth_emulation_handler.cc
index c431b125..b7d4ca0 100644
--- a/content/browser/devtools/protocol/bluetooth_emulation_handler.cc
+++ b/content/browser/devtools/protocol/bluetooth_emulation_handler.cc
@@ -178,6 +178,27 @@
   }
 }
 
+constexpr std::string_view ToDescriptorOperation(
+    bluetooth::mojom::DescriptorOperationType type) {
+  switch (type) {
+    case bluetooth::mojom::DescriptorOperationType::kRead:
+      return BluetoothEmulation::CharacteristicOperationTypeEnum::Read;
+    case bluetooth::mojom::DescriptorOperationType::kWrite:
+      return BluetoothEmulation::DescriptorOperationTypeEnum::Write;
+  }
+}
+
+std::optional<bluetooth::mojom::DescriptorOperationType> ToDescriptorOperation(
+    std::string_view type) {
+  if (type == BluetoothEmulation::DescriptorOperationTypeEnum::Read) {
+    return bluetooth::mojom::DescriptorOperationType::kRead;
+  } else if (type == BluetoothEmulation::DescriptorOperationTypeEnum::Write) {
+    return bluetooth::mojom::DescriptorOperationType::kWrite;
+  } else {
+    return std::nullopt;
+  }
+}
+
 std::string getParentId(const std::string& id) {
   // This decoding mechanism aligns with the identifier formatting mechanism in
   // FakePeripheral::AddFakeService,
@@ -396,10 +417,10 @@
     return;
   }
 
-  std::string serviceId = getParentId(in_characteristicId);
-  std::string address = getParentId(serviceId);
+  std::string service_id = getParentId(in_characteristicId);
+  std::string address = getParentId(service_id);
   fake_central_->SimulateCharacteristicOperationResponse(
-      *operation_type, in_characteristicId, serviceId, address, in_code,
+      *operation_type, in_characteristicId, service_id, address, in_code,
       in_data ? std::optional(base::ToVector(*in_data)) : std::nullopt,
       base::BindOnce(
           [](std::unique_ptr<SimulateCharacteristicOperationResponseCallback>
@@ -418,6 +439,55 @@
                in_type})));
 }
 
+void BluetoothEmulationHandler::SimulateDescriptorOperationResponse(
+    const std::string& descriptor_id,
+    const std::string& in_type,
+    int in_code,
+    std::optional<Binary> in_data,
+    std::unique_ptr<SimulateDescriptorOperationResponseCallback> callback) {
+  if (!is_enabled()) {
+    std::move(callback)->sendFailure(
+        Response::ServerError("BluetoothEmulation not enabled"));
+    return;
+  }
+  auto operation_type = ToDescriptorOperation(in_type);
+  if (!operation_type) {
+    std::move(callback)->sendFailure(Response::InvalidParams(
+        base::StrCat({"Unknown descriptor operation type ", in_type})));
+    return;
+  }
+  if (operation_type == bluetooth::mojom::DescriptorOperationType::kRead &&
+      ((in_code == bluetooth::mojom::kGATTSuccess) != in_data.has_value())) {
+    std::move(callback)->sendFailure(Response::InvalidParams(
+        base::StrCat({"Descriptor operation type ", in_type, " with code ",
+                      base::NumberToString(in_code),
+                      in_data ? " does not expect" : " expects", " data"})));
+    return;
+  }
+
+  std::string characteristic_id = getParentId(descriptor_id);
+  std::string service_id = getParentId(characteristic_id);
+  std::string address = getParentId(service_id);
+  fake_central_->SimulateDescriptorOperationResponse(
+      *operation_type, descriptor_id, characteristic_id, service_id, address,
+      in_code, in_data ? std::optional(base::ToVector(*in_data)) : std::nullopt,
+      base::BindOnce(
+          [](std::unique_ptr<SimulateDescriptorOperationResponseCallback>
+                 callback,
+             const std::string& error_message, bool success) {
+            if (!success) {
+              std::move(callback)->sendFailure(
+                  Response::ServerError(error_message));
+              return;
+            }
+            std::move(callback)->sendSuccess();
+          },
+          std::move(callback),
+          base::StrCat(
+              {"Failed to simulate descriptor response for operation type ",
+               in_type})));
+}
+
 void BluetoothEmulationHandler::AddService(
     const std::string& in_address,
     const std::string& in_serviceUuid,
@@ -530,10 +600,10 @@
     return;
   }
 
-  std::string serviceId = getParentId(in_characteristicId);
-  std::string address = getParentId(serviceId);
+  std::string service_id = getParentId(in_characteristicId);
+  std::string address = getParentId(service_id);
   fake_central_->RemoveFakeCharacteristic(
-      in_characteristicId, serviceId, address,
+      in_characteristicId, service_id, address,
       base::BindOnce(
           [](std::unique_ptr<RemoveCharacteristicCallback> callback,
              const std::string& error_message, bool success) {
@@ -566,10 +636,10 @@
     return;
   }
 
-  std::string serviceId = getParentId(in_characteristicId);
-  std::string address = getParentId(serviceId);
+  std::string service_id = getParentId(in_characteristicId);
+  std::string address = getParentId(service_id);
   fake_central_->AddFakeDescriptor(
-      uuid, in_characteristicId, serviceId, address,
+      uuid, in_characteristicId, service_id, address,
       base::BindOnce(
           [](std::unique_ptr<AddDescriptorCallback> callback,
              const std::string& error_message,
@@ -596,11 +666,11 @@
     return;
   }
 
-  std::string characteristicId = getParentId(in_descriptorId);
-  std::string serviceId = getParentId(characteristicId);
-  std::string address = getParentId(serviceId);
+  std::string characteristic_id = getParentId(in_descriptorId);
+  std::string service_id = getParentId(characteristic_id);
+  std::string address = getParentId(service_id);
   fake_central_->RemoveFakeDescriptor(
-      in_descriptorId, characteristicId, serviceId, address,
+      in_descriptorId, characteristic_id, service_id, address,
       base::BindOnce(
           [](std::unique_ptr<RemoveDescriptorCallback> callback,
              const std::string& error_message, bool success) {
@@ -636,4 +706,13 @@
           : std::nullopt);
 }
 
+void BluetoothEmulationHandler::DispatchDescriptorOperationEvent(
+    bluetooth::mojom::DescriptorOperationType type,
+    const std::optional<std::vector<uint8_t>>& data,
+    const std::string& descriptor_id) {
+  frontend_->DescriptorOperationReceived(
+      descriptor_id, std::string(ToDescriptorOperation(type)),
+      data ? std::optional(Binary::fromVector(*data)) : std::nullopt);
+}
+
 }  // namespace content::protocol
diff --git a/content/browser/devtools/protocol/bluetooth_emulation_handler.h b/content/browser/devtools/protocol/bluetooth_emulation_handler.h
index 0362cae..f6c7d4f 100644
--- a/content/browser/devtools/protocol/bluetooth_emulation_handler.h
+++ b/content/browser/devtools/protocol/bluetooth_emulation_handler.h
@@ -69,6 +69,14 @@
       std::unique_ptr<SimulateCharacteristicOperationResponseCallback> callback)
       override;
 
+  void SimulateDescriptorOperationResponse(
+      const std::string& descriptor_id,
+      const std::string& in_type,
+      int in_code,
+      std::optional<Binary> in_data,
+      std::unique_ptr<SimulateDescriptorOperationResponseCallback> callback)
+      override;
+
   void AddService(const std::string& in_address,
                   const std::string& in_serviceUuid,
                   std::unique_ptr<AddServiceCallback> callback) override;
@@ -100,6 +108,10 @@
       const std::optional<std::vector<uint8_t>>& data,
       const std::optional<bluetooth::mojom::WriteType> write_type,
       const std::string& characteristic_id) override;
+  void DispatchDescriptorOperationEvent(
+      bluetooth::mojom::DescriptorOperationType type,
+      const std::optional<std::vector<uint8_t>>& data,
+      const std::string& descriptor_id) override;
 
   bool is_enabled() { return fake_central_.is_bound(); }
 
diff --git a/content/browser/devtools/protocol/storage_handler.cc b/content/browser/devtools/protocol/storage_handler.cc
index 067b455..8b80483 100644
--- a/content/browser/devtools/protocol/storage_handler.cc
+++ b/content/browser/devtools/protocol/storage_handler.cc
@@ -16,6 +16,7 @@
 
 #include "base/barrier_closure.h"
 #include "base/functional/bind.h"
+#include "base/functional/overloaded.h"
 #include "base/notreached.h"
 #include "base/scoped_observation.h"
 #include "base/strings/string_number_conversions.h"
@@ -53,6 +54,7 @@
 #include "content/browser/attribution_reporting/common_source_info.h"
 #include "content/browser/attribution_reporting/create_report_result.h"
 #include "content/browser/attribution_reporting/event_level_result.mojom.h"
+#include "content/browser/attribution_reporting/send_result.h"
 #include "content/browser/attribution_reporting/storable_source.h"
 #include "content/browser/attribution_reporting/store_source_result.mojom.h"
 #include "content/browser/devtools/protocol/browser_handler.h"
@@ -67,6 +69,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/storage_partition.h"
+#include "net/base/net_errors.h"
 #include "net/base/schemeful_site.h"
 #include "services/network/public/mojom/trust_tokens.mojom.h"
 #include "storage/browser/quota/quota_manager.h"
@@ -2439,6 +2442,44 @@
       ToAggregatableResult(result.aggregatable_status()));
 }
 
+void StorageHandler::OnReportSent(const AttributionReport& report,
+                                  bool is_debug_report,
+                                  const SendResult& result) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  std::optional<int> net_error;
+  std::optional<String> net_error_name;
+  std::optional<int> http_status_code;
+  Storage::AttributionReportingReportResult out_result = std::visit(
+      base::Overloaded{
+          [&](SendResult::Sent result) {
+            if (result.status >= 0) {
+              http_status_code = result.status;
+            } else {
+              net_error = result.status;
+              net_error_name = String(net::ErrorToShortString(result.status));
+            }
+            return Storage::AttributionReportingReportResultEnum::Sent;
+          },
+          [](SendResult::Dropped) {
+            return Storage::AttributionReportingReportResultEnum::Prohibited;
+          },
+          [](SendResult::Expired) {
+            return Storage::AttributionReportingReportResultEnum::Expired;
+          },
+          [](SendResult::AssemblyFailure) {
+            return Storage::AttributionReportingReportResultEnum::
+                FailedToAssemble;
+          },
+      },
+      result.result);
+
+  frontend_->AttributionReportingReportSent(
+      report.ReportURL(is_debug_report).spec(),
+      std::make_unique<base::Value::Dict>(report.ReportBody()), out_result,
+      net_error, std::move(net_error_name), http_status_code);
+}
+
 Response StorageHandler::SetAttributionReportingTracking(bool enable) {
   if (enable) {
     auto* manager = GetAttributionManager();
diff --git a/content/browser/devtools/protocol/storage_handler.h b/content/browser/devtools/protocol/storage_handler.h
index 275414d4..dccd4f3a 100644
--- a/content/browser/devtools/protocol/storage_handler.h
+++ b/content/browser/devtools/protocol/storage_handler.h
@@ -216,6 +216,9 @@
       attribution_reporting::mojom::StoreSourceResult) override;
   void OnTriggerHandled(std::optional<uint64_t> cleared_debug_key,
                         const CreateReportResult&) override;
+  void OnReportSent(const AttributionReport&,
+                    bool is_debug_report,
+                    const SendResult&) override;
 
   void NotifySharedStorageAccessed(
       base::Time access_time,
diff --git a/content/browser/devtools/protocol_config.json b/content/browser/devtools/protocol_config.json
index 642c6c2d..9132ffac 100644
--- a/content/browser/devtools/protocol_config.json
+++ b/content/browser/devtools/protocol_config.json
@@ -186,6 +186,7 @@
                     "simulateAdvertisement",
                     "simulateGATTOperationResponse",
                     "simulateCharacteristicOperationResponse",
+                    "simulateDescriptorOperationResponse",
                     "addService",
                     "removeService",
                     "addCharacteristic",
diff --git a/content/browser/interest_group/ad_auction_service_impl_unittest.cc b/content/browser/interest_group/ad_auction_service_impl_unittest.cc
index 04a31b97..af556d8 100644
--- a/content/browser/interest_group/ad_auction_service_impl_unittest.cc
+++ b/content/browser/interest_group/ad_auction_service_impl_unittest.cc
@@ -4224,78 +4224,6 @@
   EXPECT_EQ(group.ads.value()[0].render_url(), "https://example.com/render");
 }
 
-// UpdateJSONParserCrash fails on Android or with the Rust parser because in
-// those conditions the data decoder doesn't use a separate process to parse
-// JSON. On other platforms, the C++ parser runs out-of-proc for safety.
-#if !BUILDFLAG(IS_ANDROID)
-
-// The server response is valid, but we simulate the JSON parser (which may
-// run in a separate process) crashing, so the update doesn't happen.
-TEST_F(AdAuctionServiceImplTest, UpdateJSONParserCrash) {
-  // Disable the Rust JSON parser, as it is in-process and cannot crash.
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatureState(base::features::kUseRustJsonParser, false);
-
-  network_responder_->RegisterUpdateResponse(kUpdateUrlPath, R"({
-"ads": [{"renderURL": "https://example.com/new_render"
-        }]
-})");
-
-  blink::InterestGroup interest_group = CreateInterestGroup();
-  // Set a long expiration delta so that we can advance to the next rate limit
-  // period without the interest group expiring.
-  interest_group.expiry = base::Time::Now() + base::Days(30);
-  interest_group.update_url = kUpdateUrlA;
-  interest_group.bidding_url = kBiddingLogicUrlA;
-  interest_group.trusted_bidding_signals_url = kTrustedBiddingSignalsUrlA;
-  interest_group.trusted_bidding_signals_keys.emplace();
-  interest_group.trusted_bidding_signals_keys->push_back("key1");
-  interest_group.ads.emplace();
-  blink::InterestGroup::Ad ad(
-      /*render_gurl=*/GURL("https://example.com/render"),
-      /*metadata=*/std::nullopt);
-  interest_group.ads->emplace_back(std::move(ad));
-  JoinInterestGroupAndFlush(interest_group);
-  EXPECT_EQ(1, GetJoinCount(kOriginA, kInterestGroupName));
-
-  // Simulate the JSON service crashing instead of returning a result.
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder;
-  in_process_data_decoder.SimulateJsonParserCrash(
-      /*drop=*/true);
-
-  UpdateInterestGroupNoFlush();
-  task_environment()->RunUntilIdle();
-
-  // Check that the ads didn't change.
-  scoped_refptr<StorageInterestGroups> groups =
-      GetInterestGroupsForOwner(kOriginA);
-  ASSERT_EQ(groups->size(), 1u);
-  auto group = groups->GetInterestGroups()[0]->interest_group;
-  ASSERT_TRUE(group.ads.has_value());
-  ASSERT_EQ(group.ads->size(), 1u);
-  EXPECT_EQ(group.ads.value()[0].render_url(), "https://example.com/render");
-
-  // Try another IG update, this time with no crash. It should succceed.
-  // (We need to advance time since this next attempt is rate-limited).
-  in_process_data_decoder.SimulateJsonParserCrash(
-      /*drop=*/false);
-  task_environment()->FastForwardBy(
-      InterestGroupStorage::kUpdateSucceededBackoffPeriod);
-  UpdateInterestGroupNoFlush();
-  task_environment()->RunUntilIdle();
-
-  // Check that the ads *did* change this time.
-  groups = GetInterestGroupsForOwner(kOriginA);
-  ASSERT_EQ(groups->size(), 1u);
-  group = groups->GetInterestGroups()[0]->interest_group;
-  ASSERT_TRUE(group.ads.has_value());
-  ASSERT_EQ(group.ads->size(), 1u);
-  EXPECT_EQ(group.ads.value()[0].render_url(),
-            "https://example.com/new_render");
-}
-
-#endif  // !BUILDFLAG(IS_ANDROID)
-
 // Trigger an update, but block it via ContentBrowserClient policy.
 // The update shouldn't happen.
 TEST_F(AdAuctionServiceImplTest, UpdateBlockedByContentBrowserClient) {
diff --git a/content/renderer/pepper/pepper_platform_video_capture.cc b/content/renderer/pepper/pepper_platform_video_capture.cc
index 9b1e89b..0df9ae1 100644
--- a/content/renderer/pepper/pepper_platform_video_capture.cc
+++ b/content/renderer/pepper/pepper_platform_video_capture.cc
@@ -15,6 +15,7 @@
 #include "content/renderer/render_thread_impl.h"
 #include "media/base/video_frame.h"
 #include "third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h"
+#include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.h"
 
 namespace content {
 
@@ -46,16 +47,20 @@
     return;
   blink::WebVideoCaptureImplManager* manager =
       RenderThreadImpl::current()->video_capture_impl_manager();
-  stop_capture_cb_ = manager->StartCapture(
-      session_id_, params,
-      base::BindPostTaskToCurrentDefault(
-          base::BindRepeating(&PepperPlatformVideoCapture::OnStateUpdate,
-                              weak_factory_.GetWeakPtr())),
-      base::BindPostTaskToCurrentDefault(
-          base::BindRepeating(&PepperPlatformVideoCapture::OnFrameReady,
-                              weak_factory_.GetWeakPtr())),
-      /*sub_capture_target_version_cb=*/base::DoNothing(),
-      /*frame_dropped_cb=*/base::DoNothing());
+
+  blink::VideoCaptureCallbacks video_capture_callbacks;
+  video_capture_callbacks.state_update_cb = base::BindPostTaskToCurrentDefault(
+      base::BindRepeating(&PepperPlatformVideoCapture::OnStateUpdate,
+                          weak_factory_.GetWeakPtr()));
+  video_capture_callbacks.deliver_frame_cb = base::BindPostTaskToCurrentDefault(
+      base::BindRepeating(&PepperPlatformVideoCapture::OnFrameReady,
+                          weak_factory_.GetWeakPtr()));
+  // TODO(crbug.com/409110236): Ensures what's is the expected callback
+  // functions from WebVideoCaptureImplManager::StartCapture().
+  video_capture_callbacks.frame_dropped_cb = base::DoNothing();
+  video_capture_callbacks.sub_capture_target_version_cb = base::DoNothing();
+  stop_capture_cb_ = manager->StartCapture(session_id_, params,
+                                           std::move(video_capture_callbacks));
 }
 
 void PepperPlatformVideoCapture::StopCapture() {
diff --git a/device/bluetooth/emulation/fake_central.cc b/device/bluetooth/emulation/fake_central.cc
index 04523edc..5496a5f9 100644
--- a/device/bluetooth/emulation/fake_central.cc
+++ b/device/bluetooth/emulation/fake_central.cc
@@ -262,6 +262,35 @@
   }
 }
 
+void FakeCentral::SimulateDescriptorOperationResponse(
+    mojom::DescriptorOperationType type,
+    const std::string& descriptor_id,
+    const std::string& characteristic_id,
+    const std::string& service_id,
+    const std::string& peripheral_address,
+    uint16_t code,
+    const std::optional<std::vector<uint8_t>>& data,
+    SimulateCharacteristicOperationResponseCallback callback) {
+  FakeRemoteGattDescriptor* fake_remote_gatt_descriptor =
+      GetFakeRemoteGattDescriptor(peripheral_address, service_id,
+                                  characteristic_id, descriptor_id);
+  if (fake_remote_gatt_descriptor == nullptr) {
+    std::move(callback).Run(false);
+    return;
+  }
+
+  switch (type) {
+    case mojom::DescriptorOperationType::kRead:
+      fake_remote_gatt_descriptor->SimulateReadResponse(code, data);
+      std::move(callback).Run(true);
+      break;
+    case mojom::DescriptorOperationType::kWrite:
+      fake_remote_gatt_descriptor->SimulateWriteResponse(code);
+      std::move(callback).Run(true);
+      break;
+  }
+}
+
 bool FakeCentral::AllResponsesConsumed() {
   return std::ranges::all_of(devices_, [](const auto& e) {
     // static_cast is safe because the parent class's devices_ is only
@@ -852,6 +881,15 @@
   }
 }
 
+void FakeCentral::DispatchDescriptorOperationEvent(
+    mojom::DescriptorOperationType type,
+    const std::optional<std::vector<uint8_t>>& data,
+    const std::string& descriptor_id) {
+  if (client_.is_bound()) {
+    client_->DispatchDescriptorOperationEvent(type, data, descriptor_id);
+  }
+}
+
 void FakeCentral::SetClient(
     ::mojo::PendingAssociatedRemote<mojom::FakeCentralClient> client) {
   CHECK(!client_.is_bound());
diff --git a/device/bluetooth/emulation/fake_central.h b/device/bluetooth/emulation/fake_central.h
index a9304bf..f932f80 100644
--- a/device/bluetooth/emulation/fake_central.h
+++ b/device/bluetooth/emulation/fake_central.h
@@ -79,6 +79,15 @@
       uint16_t code,
       const std::optional<std::vector<uint8_t>>& data,
       SimulateCharacteristicOperationResponseCallback callback) override;
+  void SimulateDescriptorOperationResponse(
+      mojom::DescriptorOperationType type,
+      const std::string& descriptor_id,
+      const std::string& characteristic_id,
+      const std::string& service_id,
+      const std::string& peripheral_address,
+      uint16_t code,
+      const std::optional<std::vector<uint8_t>>& data,
+      SimulateDescriptorOperationResponseCallback callback) override;
   void AddFakeService(const std::string& peripheral_address,
                       const device::BluetoothUUID& service_uuid,
                       AddFakeServiceCallback callback) override;
@@ -246,6 +255,10 @@
       const std::optional<std::vector<uint8_t>>& data,
       const std::optional<mojom::WriteType> write_type,
       const std::string& characteristic_id);
+  void DispatchDescriptorOperationEvent(
+      mojom::DescriptorOperationType type,
+      const std::optional<std::vector<uint8_t>>& data,
+      const std::string& descriptor_id);
 
  private:
   ~FakeCentral() override;
diff --git a/device/bluetooth/emulation/fake_peripheral.cc b/device/bluetooth/emulation/fake_peripheral.cc
index 75b2375..5abb9c2 100644
--- a/device/bluetooth/emulation/fake_peripheral.cc
+++ b/device/bluetooth/emulation/fake_peripheral.cc
@@ -28,7 +28,8 @@
       system_connected_(false),
       gatt_connected_(false),
       last_service_id_(0),
-      pending_gatt_discovery_(false) {}
+      pending_gatt_discovery_(false),
+      fake_central_(*fake_central) {}
 
 FakePeripheral::~FakePeripheral() = default;
 
@@ -352,8 +353,7 @@
 }
 
 void FakePeripheral::DispatchConnectionEvent() {
-  auto* fake_central = static_cast<FakeCentral*>(GetAdapter());
-  fake_central->DispatchGATTOperationEvent(
+  fake_central_->DispatchGATTOperationEvent(
       bluetooth::mojom::GATTOperationType::kConnect, address_);
 
   if (!next_connection_response_) {
@@ -365,8 +365,7 @@
 }
 
 void FakePeripheral::DispatchDiscoveryEvent() {
-  auto* fake_central = static_cast<FakeCentral*>(GetAdapter());
-  fake_central->DispatchGATTOperationEvent(
+  fake_central_->DispatchGATTOperationEvent(
       bluetooth::mojom::GATTOperationType::kDiscovery, address_);
 
   if (!next_discovery_response_) {
diff --git a/device/bluetooth/emulation/fake_peripheral.h b/device/bluetooth/emulation/fake_peripheral.h
index 162adb55..e763ff2a 100644
--- a/device/bluetooth/emulation/fake_peripheral.h
+++ b/device/bluetooth/emulation/fake_peripheral.h
@@ -81,6 +81,8 @@
   // Remove a fake service with |identifier| from this peripheral.
   bool RemoveFakeService(const std::string& identifier);
 
+  FakeCentral& fake_central() const { return fake_central_.get(); }
+
   // BluetoothDevice overrides:
   uint32_t GetBluetoothClass() const override;
 #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID)
@@ -179,6 +181,8 @@
   // Used to decide if the GattServicesDiscovered method is called.
   std::optional<uint16_t> next_discovery_response_;
 
+  const raw_ref<FakeCentral> fake_central_;
+
   // Mutable because IsGattServicesDiscoveryComplete needs to post a task but
   // is const.
   mutable base::WeakPtrFactory<FakePeripheral> weak_ptr_factory_{this};
diff --git a/device/bluetooth/emulation/fake_remote_gatt_characteristic.cc b/device/bluetooth/emulation/fake_remote_gatt_characteristic.cc
index 133cd9f..64371dae 100644
--- a/device/bluetooth/emulation/fake_remote_gatt_characteristic.cc
+++ b/device/bluetooth/emulation/fake_remote_gatt_characteristic.cc
@@ -33,12 +33,9 @@
           case mojom::kGATTSuccess:
             std::move(callback).Run();
             break;
-          case mojom::kGATTInvalidHandle:
+          default:
             std::move(error_callback)
                 .Run(device::BluetoothGattService::GattErrorCode::kFailed);
-            break;
-          default:
-            NOTREACHED();
         }
       },
       std::move(callback), std::move(error_callback));
@@ -58,10 +55,10 @@
     const std::string& characteristic_id,
     const device::BluetoothUUID& characteristic_uuid,
     mojom::CharacteristicPropertiesPtr properties,
-    device::BluetoothRemoteGattService* service)
+    FakeRemoteGattService* service)
     : characteristic_id_(characteristic_id),
       characteristic_uuid_(characteristic_uuid),
-      service_(service) {
+      fake_service_(*service) {
   properties_ = PROPERTY_NONE;
   if (properties->broadcast) {
     properties_ |= PROPERTY_BROADCAST;
@@ -140,15 +137,12 @@
   std::vector<uint8_t> response_value;
   switch (gatt_code) {
     case mojom::kGATTSuccess:
-      CHECK(value);
-      response_value = std::move(value.value());
-      break;
-    case mojom::kGATTInvalidHandle:
-      CHECK(!value);
-      response_code = device::BluetoothGattService::GattErrorCode::kFailed;
+      if (value) {
+        response_value = std::move(value.value());
+      }
       break;
     default:
-      NOTREACHED();
+      response_code = device::BluetoothGattService::GattErrorCode::kFailed;
   }
 
   auto callbacks = std::move(read_callbacks_);
@@ -208,7 +202,7 @@
 
 device::BluetoothRemoteGattService* FakeRemoteGattCharacteristic::GetService()
     const {
-  return service_;
+  return &fake_service_.get();
 }
 
 void FakeRemoteGattCharacteristic::ReadRemoteCharacteristic(
@@ -397,13 +391,10 @@
     mojom::CharacteristicOperationType type,
     const std::optional<std::vector<uint8_t>>& data,
     const std::optional<mojom::WriteType> write_type) {
-  FakeRemoteGattService* fake_service =
-      static_cast<FakeRemoteGattService*>(service_);
-  FakePeripheral* fake_peripheral =
-      static_cast<FakePeripheral*>(fake_service->GetDevice());
-  auto* fake_central = static_cast<FakeCentral*>(fake_peripheral->GetAdapter());
-  fake_central->DispatchCharacteristicOperationEvent(type, data, write_type,
-                                                     characteristic_id_);
+  fake_service_->fake_peripheral()
+      .fake_central()
+      .DispatchCharacteristicOperationEvent(type, data, write_type,
+                                            characteristic_id_);
 }
 
 }  // namespace bluetooth
diff --git a/device/bluetooth/emulation/fake_remote_gatt_characteristic.h b/device/bluetooth/emulation/fake_remote_gatt_characteristic.h
index 47e8810..e3e50f0 100644
--- a/device/bluetooth/emulation/fake_remote_gatt_characteristic.h
+++ b/device/bluetooth/emulation/fake_remote_gatt_characteristic.h
@@ -24,6 +24,8 @@
 
 namespace bluetooth {
 
+class FakeRemoteGattService;
+
 // Implements device::BluetoothRemoteGattCharacteristics. Meant to be used
 // by FakeRemoteGattService to keep track of the characteristic's state and
 // attributes.
@@ -37,7 +39,7 @@
   FakeRemoteGattCharacteristic(const std::string& characteristic_id,
                                const device::BluetoothUUID& characteristic_uuid,
                                mojom::CharacteristicPropertiesPtr properties,
-                               device::BluetoothRemoteGattService* service);
+                               FakeRemoteGattService* service);
   ~FakeRemoteGattCharacteristic() override;
 
   // Adds a fake descriptor with |descriptor_uuid| to this characteristic.
@@ -90,6 +92,8 @@
   // characteristic. Returns kNone if no value has been written yet.
   mojom::WriteType last_write_type() { return last_write_type_; }
 
+  FakeRemoteGattService& fake_service() const { return fake_service_.get(); }
+
   // device::BluetoothGattCharacteristic overrides:
   std::string GetIdentifier() const override;
   device::BluetoothUUID GetUUID() const override;
@@ -153,7 +157,7 @@
   const std::string characteristic_id_;
   const device::BluetoothUUID characteristic_uuid_;
   Properties properties_;
-  raw_ptr<device::BluetoothRemoteGattService> service_;
+  const raw_ref<FakeRemoteGattService> fake_service_;
 
   // Last successfully written value to the characteristic.
   std::optional<std::vector<uint8_t>> last_written_value_;
diff --git a/device/bluetooth/emulation/fake_remote_gatt_descriptor.cc b/device/bluetooth/emulation/fake_remote_gatt_descriptor.cc
index 866ffbd..b2e6d7c4 100644
--- a/device/bluetooth/emulation/fake_remote_gatt_descriptor.cc
+++ b/device/bluetooth/emulation/fake_remote_gatt_descriptor.cc
@@ -9,17 +9,43 @@
 #include "base/containers/to_vector.h"
 #include "base/functional/bind.h"
 #include "base/task/single_thread_task_runner.h"
+#include "device/bluetooth/emulation/fake_central.h"
+#include "device/bluetooth/emulation/fake_peripheral.h"
+#include "device/bluetooth/emulation/fake_remote_gatt_characteristic.h"
 #include "device/bluetooth/public/mojom/emulation/fake_bluetooth.mojom.h"
 
 namespace bluetooth {
 
+namespace {
+
+FakeRemoteGattDescriptor::ResponseCallback CreateResponseCallback(
+    base::OnceClosure callback,
+    device::BluetoothGattDescriptor::ErrorCallback error_callback) {
+  return base::BindOnce(
+      [](base::OnceClosure callback,
+         device::BluetoothGattDescriptor::ErrorCallback error_callback,
+         uint16_t gatt_code) {
+        switch (gatt_code) {
+          case mojom::kGATTSuccess:
+            std::move(callback).Run();
+            break;
+          default:
+            std::move(error_callback)
+                .Run(device::BluetoothGattService::GattErrorCode::kFailed);
+        }
+      },
+      std::move(callback), std::move(error_callback));
+}
+
+}  // namespace
+
 FakeRemoteGattDescriptor::FakeRemoteGattDescriptor(
     const std::string& descriptor_id,
     const device::BluetoothUUID& descriptor_uuid,
-    device::BluetoothRemoteGattCharacteristic* characteristic)
+    FakeRemoteGattCharacteristic* characteristic)
     : descriptor_id_(descriptor_id),
       descriptor_uuid_(descriptor_uuid),
-      characteristic_(characteristic) {}
+      fake_characteristic_(*characteristic) {}
 
 FakeRemoteGattDescriptor::~FakeRemoteGattDescriptor() = default;
 
@@ -35,6 +61,34 @@
   next_write_response_.emplace(gatt_code);
 }
 
+void FakeRemoteGattDescriptor::SimulateReadResponse(
+    uint16_t gatt_code,
+    const std::optional<std::vector<uint8_t>>& value) {
+  std::optional<device::BluetoothGattService::GattErrorCode> response_code;
+  std::vector<uint8_t> response_value;
+  switch (gatt_code) {
+    case mojom::kGATTSuccess:
+      if (value) {
+        response_value = std::move(value.value());
+      }
+      break;
+    default:
+      response_code = device::BluetoothGattService::GattErrorCode::kFailed;
+  }
+
+  auto callbacks = std::move(read_callbacks_);
+  for (auto& callback : callbacks) {
+    std::move(callback).Run(response_code, response_value);
+  }
+}
+
+void FakeRemoteGattDescriptor::SimulateWriteResponse(uint16_t gatt_code) {
+  auto callbacks = std::move(write_callbacks_);
+  for (auto& callback : callbacks) {
+    std::move(callback).Run(gatt_code);
+  }
+}
+
 bool FakeRemoteGattDescriptor::AllResponsesConsumed() {
   return !next_read_response_ && !next_write_response_;
 }
@@ -58,7 +112,7 @@
 
 device::BluetoothRemoteGattCharacteristic*
 FakeRemoteGattDescriptor::GetCharacteristic() const {
-  return characteristic_;
+  return &fake_characteristic_.get();
 }
 
 void FakeRemoteGattDescriptor::ReadRemoteDescriptor(ValueCallback callback) {
@@ -80,48 +134,46 @@
 }
 
 void FakeRemoteGattDescriptor::DispatchReadResponse(ValueCallback callback) {
-  DCHECK(next_read_response_);
+  DispatchDescriptorOperationEvent(
+      bluetooth::mojom::DescriptorOperationType::kRead,
+      /*data=*/std::nullopt);
+  read_callbacks_.push_back(std::move(callback));
+  if (!next_read_response_) {
+    return;
+  }
   uint16_t gatt_code = next_read_response_->gatt_code();
   std::optional<std::vector<uint8_t>> value = next_read_response_->value();
   next_read_response_.reset();
-
-  switch (gatt_code) {
-    case mojom::kGATTSuccess:
-      DCHECK(value);
-      value_ = std::move(value.value());
-      std::move(callback).Run(/*error_code=*/std::nullopt, value_);
-      break;
-    case mojom::kGATTInvalidHandle:
-      DCHECK(!value);
-      std::move(callback).Run(
-          device::BluetoothGattService::GattErrorCode::kFailed,
-          /*value=*/std::vector<uint8_t>());
-      break;
-    default:
-      NOTREACHED();
-  }
+  SimulateReadResponse(gatt_code, value);
 }
 
 void FakeRemoteGattDescriptor::DispatchWriteResponse(
     base::OnceClosure callback,
     ErrorCallback error_callback,
     std::vector<uint8_t> value) {
-  DCHECK(next_write_response_);
+  DispatchDescriptorOperationEvent(
+      bluetooth::mojom::DescriptorOperationType::kWrite, value);
+  write_callbacks_.push_back(
+      CreateResponseCallback(std::move(callback), std::move(error_callback)));
+  if (!next_write_response_) {
+    return;
+  }
+
   uint16_t gatt_code = next_write_response_.value();
   next_write_response_.reset();
-
-  switch (gatt_code) {
-    case mojom::kGATTSuccess:
-      last_written_value_ = std::move(value);
-      std::move(callback).Run();
-      break;
-    case mojom::kGATTInvalidHandle:
-      std::move(error_callback)
-          .Run(device::BluetoothGattService::GattErrorCode::kFailed);
-      break;
-    default:
-      NOTREACHED();
+  if (gatt_code == mojom::kGATTSuccess) {
+    last_written_value_ = value;
   }
+  SimulateWriteResponse(gatt_code);
+}
+
+void FakeRemoteGattDescriptor::DispatchDescriptorOperationEvent(
+    mojom::DescriptorOperationType type,
+    const std::optional<std::vector<uint8_t>>& data) {
+  fake_characteristic_->fake_service()
+      .fake_peripheral()
+      .fake_central()
+      .DispatchDescriptorOperationEvent(type, data, descriptor_id_);
 }
 
 }  // namespace bluetooth
diff --git a/device/bluetooth/emulation/fake_remote_gatt_descriptor.h b/device/bluetooth/emulation/fake_remote_gatt_descriptor.h
index 67b38b8..a7482a7b 100644
--- a/device/bluetooth/emulation/fake_remote_gatt_descriptor.h
+++ b/device/bluetooth/emulation/fake_remote_gatt_descriptor.h
@@ -14,9 +14,12 @@
 #include "device/bluetooth/bluetooth_remote_gatt_descriptor.h"
 #include "device/bluetooth/emulation/fake_read_response.h"
 #include "device/bluetooth/public/cpp/bluetooth_uuid.h"
+#include "device/bluetooth/public/mojom/emulation/fake_bluetooth.mojom.h"
 
 namespace bluetooth {
 
+class FakeRemoteGattCharacteristic;
+
 // Implements device::BluetoothRemoteGattDescriptors. Meant to be used
 // by FakeRemoteGattCharacteristic to keep track of the descriptor's state and
 // attributes.
@@ -24,10 +27,11 @@
 // Not intended for direct use by clients.  See README.md.
 class FakeRemoteGattDescriptor : public device::BluetoothRemoteGattDescriptor {
  public:
-  FakeRemoteGattDescriptor(
-      const std::string& descriptor_id,
-      const device::BluetoothUUID& descriptor_uuid,
-      device::BluetoothRemoteGattCharacteristic* characteristic);
+  using ResponseCallback = base::OnceCallback<void(uint16_t gatt_code)>;
+
+  FakeRemoteGattDescriptor(const std::string& descriptor_id,
+                           const device::BluetoothUUID& descriptor_uuid,
+                           FakeRemoteGattCharacteristic* characteristic);
   ~FakeRemoteGattDescriptor() override;
 
   // If |gatt_code| is mojom::kGATTSuccess the next read request will call
@@ -40,6 +44,11 @@
   // success callback. Otherwise it will call its error callback.
   void SetNextWriteResponse(uint16_t gatt_code);
 
+  void SimulateReadResponse(uint16_t gatt_code,
+                            const std::optional<std::vector<uint8_t>>& value);
+
+  void SimulateWriteResponse(uint16_t gatt_code);
+
   // Returns the last successfully written value to the descriptor. Returns
   // nullopt if no value has been written yet.
   const std::optional<std::vector<uint8_t>>& last_written_value() {
@@ -70,10 +79,13 @@
                              ErrorCallback error_callback,
                              std::vector<uint8_t> value);
 
+  void DispatchDescriptorOperationEvent(
+      mojom::DescriptorOperationType type,
+      const std::optional<std::vector<uint8_t>>& data);
+
   const std::string descriptor_id_;
   const device::BluetoothUUID descriptor_uuid_;
-  raw_ptr<device::BluetoothRemoteGattCharacteristic> characteristic_;
-  std::vector<uint8_t> value_;
+  const raw_ref<FakeRemoteGattCharacteristic> fake_characteristic_;
 
   // Last successfully written value to the descriptor.
   std::optional<std::vector<uint8_t>> last_written_value_;
@@ -86,6 +98,9 @@
   // is called.
   std::optional<uint16_t> next_write_response_;
 
+  std::vector<ValueCallback> read_callbacks_;
+  std::vector<ResponseCallback> write_callbacks_;
+
   base::WeakPtrFactory<FakeRemoteGattDescriptor> weak_ptr_factory_{this};
 };
 
diff --git a/device/bluetooth/emulation/fake_remote_gatt_service.cc b/device/bluetooth/emulation/fake_remote_gatt_service.cc
index 2bc658a8..a39a774 100644
--- a/device/bluetooth/emulation/fake_remote_gatt_service.cc
+++ b/device/bluetooth/emulation/fake_remote_gatt_service.cc
@@ -12,7 +12,7 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
-#include "device/bluetooth/bluetooth_device.h"
+#include "device/bluetooth/emulation/fake_peripheral.h"
 #include "device/bluetooth/emulation/fake_remote_gatt_characteristic.h"
 #include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "device/bluetooth/public/mojom/emulation/fake_bluetooth.mojom.h"
@@ -23,11 +23,11 @@
     const std::string& service_id,
     const device::BluetoothUUID& service_uuid,
     bool is_primary,
-    device::BluetoothDevice* device)
+    FakePeripheral* device)
     : service_id_(service_id),
       service_uuid_(service_uuid),
       is_primary_(is_primary),
-      device_(device) {}
+      fake_peripheral_(*device) {}
 
 FakeRemoteGattService::~FakeRemoteGattService() = default;
 
@@ -72,7 +72,7 @@
 }
 
 device::BluetoothDevice* FakeRemoteGattService::GetDevice() const {
-  return device_;
+  return &fake_peripheral_.get();
 }
 
 std::vector<device::BluetoothRemoteGattService*>
diff --git a/device/bluetooth/emulation/fake_remote_gatt_service.h b/device/bluetooth/emulation/fake_remote_gatt_service.h
index 4f02be2..05fc9c8 100644
--- a/device/bluetooth/emulation/fake_remote_gatt_service.h
+++ b/device/bluetooth/emulation/fake_remote_gatt_service.h
@@ -22,6 +22,8 @@
 
 namespace bluetooth {
 
+class FakePeripheral;
+
 // Implements device::BluetoothRemoteGattService. Meant to be used by
 // FakePeripheral to keep track of the service's state and attributes.
 //
@@ -31,7 +33,7 @@
   FakeRemoteGattService(const std::string& service_id,
                         const device::BluetoothUUID& service_uuid,
                         bool is_primary,
-                        device::BluetoothDevice* device);
+                        FakePeripheral* device);
   ~FakeRemoteGattService() override;
 
   // Returns true if there are no pending responses for any characterstics.
@@ -46,6 +48,8 @@
   // Removes a fake characteristic with |identifier| from this service.
   bool RemoveFakeCharacteristic(const std::string& identifier);
 
+  FakePeripheral& fake_peripheral() const { return fake_peripheral_.get(); }
+
   // device::BluetoothGattService overrides:
   std::string GetIdentifier() const override;
   device::BluetoothUUID GetUUID() const override;
@@ -60,7 +64,7 @@
   const std::string service_id_;
   const device::BluetoothUUID service_uuid_;
   const bool is_primary_;
-  raw_ptr<device::BluetoothDevice> device_;
+  const raw_ref<FakePeripheral> fake_peripheral_;
 
   size_t last_characteristic_id_ = 0;
 };
diff --git a/device/bluetooth/public/mojom/emulation/fake_bluetooth.mojom b/device/bluetooth/public/mojom/emulation/fake_bluetooth.mojom
index fa71067..94c8b80 100644
--- a/device/bluetooth/public/mojom/emulation/fake_bluetooth.mojom
+++ b/device/bluetooth/public/mojom/emulation/fake_bluetooth.mojom
@@ -60,6 +60,12 @@
   kUnsubscribeFromNotifications,
 };
 
+// Descriptor operation type
+enum DescriptorOperationType {
+  kRead,
+  kWrite,
+};
+
 // Stores the external appearance description of the device.
 struct Appearance {
   bool has_value;
@@ -243,6 +249,19 @@
     uint16 code,
     array<uint8>? data) => (bool success);
 
+  // Simulates the response |code| and |data| from the fake GATT Descriptor
+  // with |descriptor_id| in the fake characteristic with |characteristic_id| in
+  // the fake service with |service_id| in |peripheral_address| peripheral for a
+  // descriptor operation of |type|.
+  SimulateDescriptorOperationResponse(
+    DescriptorOperationType type,
+    string descriptor_id,
+    string characteristic_id,
+    string service_id,
+    string peripheral_address,
+    uint16 code,
+    array<uint8>? data) => (bool success);
+
   // Adds a fake GATT Service with |service_uuid| to |peripheral_address|
   // peripheral. The service will be found found when discovering the
   // peripheral's GATT Attributes. Runs its callback with the fake service's Id.
@@ -431,4 +450,10 @@
       array<uint8>? data,
       WriteType? write_type,
       string characteristic_id);
+  // Called when the descriptor with |descriptor_id| receives a request
+  // of descriptor operation |type| along with |data|.
+  DispatchDescriptorOperationEvent(
+    DescriptorOperationType type,
+    array<uint8>? data,
+    string descriptor_id);
 };
diff --git a/docs/speed/perf_lab_platforms.md b/docs/speed/perf_lab_platforms.md
index b39a068..aca28f6e 100644
--- a/docs/speed/perf_lab_platforms.md
+++ b/docs/speed/perf_lab_platforms.md
@@ -8,6 +8,7 @@
 
 ### Android
 
+ * [android-byra-perf](https://ci.chromium.org/p/chrome/builders/ci/android-byra-perf): AL Byra.
  * [android-go-wembley-perf](https://ci.chromium.org/p/chrome/builders/ci/android-go-wembley-perf): Android U.
  * [android-go-wembley_webview-perf](https://ci.chromium.org/p/chrome/builders/ci/android-go-wembley_webview-perf): Android U.
  * [android-pixel-fold-perf](https://ci.chromium.org/p/chrome/builders/ci/android-pixel-fold-perf): Android U.
diff --git a/extensions/browser/api/messaging/message_service_bindings.cc b/extensions/browser/api/messaging/message_service_bindings.cc
index 1e1b547..ccd12083 100644
--- a/extensions/browser/api/messaging/message_service_bindings.cc
+++ b/extensions/browser/api/messaging/message_service_bindings.cc
@@ -228,11 +228,6 @@
 bool IsValidSourceUrl(content::RenderProcessHost& process,
                       const GURL& source_url,
                       const PortContext& source_context) {
-  if (!base::FeatureList::IsEnabled(
-          extensions_features::kExtensionSourceUrlEnforcement)) {
-    return true;
-  }
-
   // Some scenarios may end up with an empty `source_url` (e.g. this may have
   // been triggered by the ExtensionApiTabTest.TabConnect test).
   //
diff --git a/extensions/browser/sandboxed_unpacker_unittest.cc b/extensions/browser/sandboxed_unpacker_unittest.cc
index 394cc3d..b13617b 100644
--- a/extensions/browser/sandboxed_unpacker_unittest.cc
+++ b/extensions/browser/sandboxed_unpacker_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/files/file_util.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
-#include "base/json/json_reader.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
 #include "base/path_service.h"
@@ -510,17 +509,10 @@
   // Check that there is no _locales folder.
   base::FilePath install_path = GetInstallPath().Append(kLocaleFolder);
   EXPECT_FALSE(base::PathExists(install_path));
-  if (base::JSONReader::UsingRust()) {
-    EXPECT_TRUE(base::MatchPattern(GetInstallErrorMessage(),
-                                   u"*_locales?en_US?messages.json': EOF while "
-                                   u"parsing a string at line 4*"))
-        << GetInstallErrorMessage();
-  } else {
-    EXPECT_TRUE(base::MatchPattern(
-        GetInstallErrorMessage(),
-        u"*_locales?en_US?messages.json': Line: 4, column: 1,*"))
-        << GetInstallErrorMessage();
-  }
+  EXPECT_TRUE(base::MatchPattern(GetInstallErrorMessage(),
+                                 u"*_locales?en_US?messages.json': EOF while "
+                                 u"parsing a string at line 4*"))
+      << GetInstallErrorMessage();
   ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE,
             GetInstallErrorType());
   EXPECT_EQ(static_cast<int>(
@@ -566,21 +558,6 @@
             GetInstallErrorDetail());
 }
 
-TEST_F(SandboxedUnpackerTest, JsonParserFails) {
-  // Disable the Rust JSON parser, as it is in-process and cannot crash.
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatureState(base::features::kUseRustJsonParser, false);
-
-  in_process_data_decoder().SimulateJsonParserCrash(true);
-  InitSandboxedUnpacker();
-
-  SetupUnpacker("good_package.crx", "");
-  EXPECT_FALSE(InstallSucceeded());
-  EXPECT_FALSE(GetInstallErrorMessage().empty());
-  ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE,
-            GetInstallErrorType());
-}
-
 TEST_F(SandboxedUnpackerTest, ImageDecoderFails) {
   in_process_data_decoder().SimulateImageDecoderCrash(true);
   InitSandboxedUnpacker();
diff --git a/extensions/common/extension_features.cc b/extensions/common/extension_features.cc
index 499026f..dde8122 100644
--- a/extensions/common/extension_features.cc
+++ b/extensions/common/extension_features.cc
@@ -109,10 +109,6 @@
              "AllowLegacyMV2Extensions",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kExtensionSourceUrlEnforcement,
-             "ExtensionSourceUrlEnforcement",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kExtensionWARForRedirect,
              "ExtensionWARForRedirect",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/extensions/common/extension_features.h b/extensions/common/extension_features.h
index c354572..ce5c4626 100644
--- a/extensions/common/extension_features.h
+++ b/extensions/common/extension_features.h
@@ -132,9 +132,6 @@
 // policy is no longer supported.
 BASE_DECLARE_FEATURE(kAllowLegacyMV2Extensions);
 
-// IsValidSourceUrl enforcement for ExtensionHostMsg_OpenChannelToExtension IPC.
-BASE_DECLARE_FEATURE(kExtensionSourceUrlEnforcement);
-
 // Controls whether server-side redirects are subject to extensions' web
 // accessible resource restrictions.
 BASE_DECLARE_FEATURE(kExtensionWARForRedirect);
diff --git a/extensions/common/extension_l10n_util_unittest.cc b/extensions/common/extension_l10n_util_unittest.cc
index 7792f41..1210f71 100644
--- a/extensions/common/extension_l10n_util_unittest.cc
+++ b/extensions/common/extension_l10n_util_unittest.cc
@@ -10,7 +10,6 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/json/json_reader.h"
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -106,19 +105,10 @@
                          errors::kLocalesInvalidLocale,
                          base::UTF16ToUTF8(de_messages_file.LossyDisplayName()),
                          "Variable $VAR$ used but not defined.")));
-  if (base::JSONReader::UsingRust()) {
-    EXPECT_THAT(error,
-                testing::HasSubstr(ErrorUtils::FormatErrorMessage(
-                    errors::kLocalesInvalidLocale,
-                    base::UTF16ToUTF8(es_messages_file.LossyDisplayName()),
-                    "expected value at line 1 column 24")));
-  } else {
-    EXPECT_THAT(error,
-                testing::HasSubstr(ErrorUtils::FormatErrorMessage(
-                    errors::kLocalesInvalidLocale,
-                    base::UTF16ToUTF8(es_messages_file.LossyDisplayName()),
-                    "Line: 1, column: 24, Unexpected token.")));
-  }
+  EXPECT_THAT(error, testing::HasSubstr(ErrorUtils::FormatErrorMessage(
+                         errors::kLocalesInvalidLocale,
+                         base::UTF16ToUTF8(es_messages_file.LossyDisplayName()),
+                         "expected value at line 1 column 24")));
   EXPECT_THAT(error, testing::HasSubstr(ErrorUtils::FormatErrorMessage(
                          errors::kLocalesInvalidLocale,
                          base::UTF16ToUTF8(fr_messages_file.LossyDisplayName()),
@@ -277,19 +267,11 @@
   std::string error;
   EXPECT_FALSE(extension_l10n_util::LoadMessageCatalogs(
       src_path, "en_US", GzippedMessagesPermission::kDisallow, &error));
-  if (base::JSONReader::UsingRust()) {
-    EXPECT_NE(std::string::npos,
-              error.find(ErrorUtils::FormatErrorMessage(
-                  errors::kLocalesInvalidLocale,
-                  base::UTF16ToUTF8(messages_file.LossyDisplayName()),
-                  "EOF while parsing a value at line 1 column 9")));
-  } else {
-    EXPECT_NE(std::string::npos,
-              error.find(ErrorUtils::FormatErrorMessage(
-                  errors::kLocalesInvalidLocale,
-                  base::UTF16ToUTF8(messages_file.LossyDisplayName()),
-                  "Line: 1, column: 10,")));
-  }
+  EXPECT_NE(std::string::npos,
+            error.find(ErrorUtils::FormatErrorMessage(
+                errors::kLocalesInvalidLocale,
+                base::UTF16ToUTF8(messages_file.LossyDisplayName()),
+                "EOF while parsing a value at line 1 column 9")));
 }
 
 TEST(ExtensionL10nUtil, LoadMessageCatalogsDuplicateKeys) {
diff --git a/extensions/common/file_util_unittest.cc b/extensions/common/file_util_unittest.cc
index a590e3c..c9b390b 100644
--- a/extensions/common/file_util_unittest.cc
+++ b/extensions/common/file_util_unittest.cc
@@ -442,16 +442,10 @@
       install_dir, ManifestLocation::kUnpacked, Extension::NO_FLAGS, &error));
   ASSERT_TRUE(extension.get() == nullptr);
   ASSERT_FALSE(error.empty());
-  if (base::JSONReader::UsingRust()) {
-    ASSERT_NE(
-        std::string::npos,
-        error.find(manifest_errors::kManifestParseError +
-                   std::string("  expected `,` or `}` at line 2 column 16")));
-  } else {
-    ASSERT_NE(std::string::npos,
-              error.find(manifest_errors::kManifestParseError +
-                         std::string("  Line: 2, column: 16,")));
-  }
+  ASSERT_NE(
+      std::string::npos,
+      error.find(manifest_errors::kManifestParseError +
+                 std::string("  expected `,` or `}` at line 2 column 16")));
 }
 
 TEST_F(FileUtilTest, ValidateThemeUTF8) {
diff --git a/gpu/ipc/common/BUILD.gn b/gpu/ipc/common/BUILD.gn
index 76e42cc..9f8a3d3 100644
--- a/gpu/ipc/common/BUILD.gn
+++ b/gpu/ipc/common/BUILD.gn
@@ -378,6 +378,7 @@
 
   public_deps = [
     ":gpu_preferences_interface",
+    ":shared_image_pool_client_interface",
     ":surface_handle",
     "//mojo/public/mojom/base",
     "//services/viz/public/mojom:shared_image_format",
diff --git a/internal b/internal
index eac1a0f..4c4da7a 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit eac1a0fd11368b363bfe25628d47c633d8f7660b
+Subproject commit 4c4da7a117aa9100f7a27e9f37a7e92b4bfcde60
diff --git a/ios/chrome/browser/alert_view/ui_bundled/BUILD.gn b/ios/chrome/browser/alert_view/ui_bundled/BUILD.gn
index d95cf93..d942eb0b 100644
--- a/ios/chrome/browser/alert_view/ui_bundled/BUILD.gn
+++ b/ios/chrome/browser/alert_view/ui_bundled/BUILD.gn
@@ -16,6 +16,7 @@
     "//ios/chrome/browser/presenters/ui_bundled",
     "//ios/chrome/browser/shared/public/features",
     "//ios/chrome/browser/shared/ui/elements",
+    "//ios/chrome/browser/shared/ui/symbols:symbols",
     "//ios/chrome/browser/shared/ui/util",
     "//ios/chrome/common/ui/colors",
     "//ios/chrome/common/ui/util",
diff --git a/ios/chrome/browser/alert_view/ui_bundled/alert_consumer.h b/ios/chrome/browser/alert_view/ui_bundled/alert_consumer.h
index 57bfc302..d9aff966 100644
--- a/ios/chrome/browser/alert_view/ui_bundled/alert_consumer.h
+++ b/ios/chrome/browser/alert_view/ui_bundled/alert_consumer.h
@@ -43,6 +43,17 @@
 // Sets whether the action buttons should initially be disabled.
 - (void)setActionButtonsAreInitiallyDisabled:
     (BOOL)actionButtonsAreInitiallyDisabled;
+
+// Define the possible states for the progress indicator.
+typedef NS_ENUM(NSInteger, ProgressIndicatorState) {
+  ProgressIndicatorStateNone =
+      0,  // Nothing is shown (or the space is collapsed)
+  ProgressIndicatorStateActivity,  // The spinner is shown
+  ProgressIndicatorStateSuccess,   // The checkmark is shown
+};
+
+// Sets the states for the progress indicator.
+- (void)setProgressState:(ProgressIndicatorState)progressState;
 @end
 
 #endif  // IOS_CHROME_BROWSER_ALERT_VIEW_UI_BUNDLED_ALERT_CONSUMER_H_
diff --git a/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller.h b/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller.h
index a5195da..f8a1cea 100644
--- a/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller.h
+++ b/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller.h
@@ -19,6 +19,10 @@
 // The text in the text fields after presentation.
 @property(nonatomic, readonly) NSArray<NSString*>* textFieldResults;
 
+// Represents the current state of the progress indicator area.
+// Set this property to change between spinner, checkmark, or none.
+@property(nonatomic, assign) ProgressIndicatorState progressState;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_ALERT_VIEW_UI_BUNDLED_ALERT_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller.mm b/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller.mm
index e14f324..0a42581 100644
--- a/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller.mm
+++ b/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller.mm
@@ -13,6 +13,7 @@
 #import "ios/chrome/browser/shared/public/features/features.h"
 #import "ios/chrome/browser/shared/ui/elements/gray_highlight_button.h"
 #import "ios/chrome/browser/shared/ui/elements/text_field_configuration.h"
+#import "ios/chrome/browser/shared/ui/symbols/symbols.h"
 #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/util/constraints_ui_util.h"
@@ -50,6 +51,9 @@
 constexpr CGFloat kSpinnerInsetTop = 12;
 constexpr CGFloat kSpinnerInsetBottom = 14;
 
+constexpr CGFloat kConfirmationImageMarginBottom = 14;
+constexpr CGFloat kConfirmationSymbolPointSize = 22;
+
 constexpr CGFloat kMessageInsetLeading = 20;
 constexpr CGFloat kMessageInsetBottom = 6;
 constexpr CGFloat kMessageInsetTrailing = 20;
@@ -243,7 +247,14 @@
 
 @end
 
-@implementation AlertViewController
+@implementation AlertViewController {
+  // The spinner view shown between the title and the content message, it is
+  // shown only when shouldShowActivityIndicator is true.
+  UIActivityIndicatorView* _spinner;
+  // The checkmark shown when the pending state suggested by the _spinner ends.
+  // It replaces the _spinner in the view.
+  UIImageView* _checkmark;
+}
 
 #pragma mark - Public
 
@@ -356,10 +367,19 @@
   }
 
   if (self.shouldShowActivityIndicator) {
-    UIActivityIndicatorView* spinner = GetLargeUIActivityIndicatorView();
-    [spinner startAnimating];
-    [stackView addArrangedSubview:spinner];
-    [stackView setCustomSpacing:kSpinnerInsetBottom afterView:spinner];
+    _spinner = GetLargeUIActivityIndicatorView();
+    [stackView addArrangedSubview:_spinner];
+    [stackView setCustomSpacing:kSpinnerInsetBottom afterView:_spinner];
+
+    _checkmark = [[UIImageView alloc] init];
+    _checkmark.image = DefaultSymbolWithPointSize(kCheckmarkCircleFillSymbol,
+                                                  kConfirmationSymbolPointSize);
+    _checkmark.tintColor = [UIColor systemGreenColor];
+    [stackView addArrangedSubview:_checkmark];
+    [stackView setCustomSpacing:kConfirmationImageMarginBottom
+                      afterView:_checkmark];
+
+    [self setProgressState:ProgressIndicatorStateActivity];
   }
 
   if (self.message.length) {
@@ -570,6 +590,33 @@
   _imageDarkModeLottieName = [imageDarkModeLottieName copy];
 }
 
+- (void)updateProgressViewsForCurrentState {
+  if (!_shouldShowActivityIndicator || !self.isViewLoaded || !_checkmark ||
+      !_spinner) {
+    return;
+  }
+  if (_progressState == ProgressIndicatorStateActivity) {
+    _checkmark.hidden = YES;
+    _spinner.hidden = NO;
+    [_spinner startAnimating];
+  } else if (_progressState == ProgressIndicatorStateSuccess) {
+    _spinner.hidden = YES;
+    [_spinner stopAnimating];
+    _checkmark.hidden = NO;
+  } else {
+    _spinner.hidden = YES;
+    [_spinner stopAnimating];
+    _checkmark.hidden = YES;
+  }
+}
+
+- (void)setProgressState:(ProgressIndicatorState)progressState {
+  if (_progressState != progressState) {
+    _progressState = progressState;
+    [self updateProgressViewsForCurrentState];
+  }
+}
+
 #pragma mark - UIGestureRecognizerDelegate
 
 - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
diff --git a/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller_unittest.mm b/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller_unittest.mm
index 905d8ac5..e359968 100644
--- a/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller_unittest.mm
+++ b/ios/chrome/browser/alert_view/ui_bundled/alert_view_controller_unittest.mm
@@ -4,6 +4,8 @@
 
 #import "ios/chrome/browser/alert_view/ui_bundled/alert_view_controller.h"
 
+#import <UIKit/UIKit.h>
+
 #import "ios/chrome/browser/alert_view/ui_bundled/alert_action.h"
 #import "testing/platform_test.h"
 
@@ -40,3 +42,135 @@
   }
   EXPECT_FALSE(weakAlert);
 }
+
+namespace {
+UIActivityIndicatorView* GetSpinner(AlertViewController* controller) {
+  return [controller valueForKey:@"_spinner"];
+}
+
+UIImageView* GetCheckmark(AlertViewController* controller) {
+  return [controller valueForKey:@"_checkmark"];
+}
+}  // namespace
+
+// Tests that the Activity state is set correctly after view loads.
+TEST_F(AlertViewControllerTest, ProgressState_ActivityIsSetByLoadView) {
+  AlertViewController* alert = [[AlertViewController alloc] init];
+  [alert setValue:@YES forKey:@"_shouldShowActivityIndicator"];
+
+  (void)alert.view;
+
+  UIActivityIndicatorView* spinner = GetSpinner(alert);
+  UIImageView* checkmark = GetCheckmark(alert);
+
+  ASSERT_TRUE(spinner);
+  ASSERT_TRUE(checkmark);
+  EXPECT_FALSE(spinner.hidden);
+  EXPECT_TRUE(spinner.isAnimating);
+  EXPECT_TRUE(checkmark.hidden);
+}
+
+// Tests setting state to Success updates views correctly.
+TEST_F(AlertViewControllerTest, ProgressState_SetSuccess) {
+  AlertViewController* alert = [[AlertViewController alloc] init];
+  [alert setValue:@YES forKey:@"_shouldShowActivityIndicator"];
+
+  (void)alert.view;
+
+  // Set state to Success
+  [alert setProgressState:ProgressIndicatorStateSuccess];
+  UIActivityIndicatorView* spinner = GetSpinner(alert);
+  UIImageView* checkmark = GetCheckmark(alert);
+
+  // Verify Success state
+  ASSERT_TRUE(spinner);
+  ASSERT_TRUE(checkmark);
+  EXPECT_TRUE(spinner.hidden);
+  EXPECT_FALSE(spinner.isAnimating);
+  EXPECT_FALSE(checkmark.hidden);
+}
+
+// Tests setting state to None updates views correctly.
+TEST_F(AlertViewControllerTest, ProgressState_SetNone) {
+  AlertViewController* alert = [[AlertViewController alloc] init];
+  [alert setValue:@YES forKey:@"_shouldShowActivityIndicator"];
+
+  (void)alert.view;
+
+  // Set state to None
+  [alert setProgressState:ProgressIndicatorStateNone];
+  UIActivityIndicatorView* spinner = GetSpinner(alert);
+  UIImageView* checkmark = GetCheckmark(alert);
+
+  // Verify None state
+  ASSERT_TRUE(spinner);
+  ASSERT_TRUE(checkmark);
+  EXPECT_TRUE(spinner.hidden);
+  EXPECT_FALSE(spinner.isAnimating);
+  EXPECT_TRUE(checkmark.hidden);
+}
+
+// Tests setting state to the current state does not cause changes.
+TEST_F(AlertViewControllerTest, ProgressState_SetSameState) {
+  AlertViewController* alert = [[AlertViewController alloc] init];
+  [alert setValue:@YES forKey:@"_shouldShowActivityIndicator"];
+
+  (void)alert.view;
+  UIActivityIndicatorView* spinner = GetSpinner(alert);
+  UIImageView* checkmark = GetCheckmark(alert);
+
+  // Capture initial state
+  BOOL initialSpinnerHidden = spinner.hidden;
+  BOOL initialSpinnerAnimating = spinner.isAnimating;
+  BOOL initialCheckmarkHidden = checkmark.hidden;
+
+  // Set state to the same state
+  [alert setProgressState:ProgressIndicatorStateActivity];
+
+  // Verify state hasn't visually changed
+  EXPECT_EQ(initialSpinnerHidden, spinner.hidden);
+  EXPECT_EQ(initialSpinnerAnimating, spinner.isAnimating);
+  EXPECT_EQ(initialCheckmarkHidden, checkmark.hidden);
+}
+
+// Tests that if shouldShowActivityIndicator is NO, views are not updated.
+TEST_F(AlertViewControllerTest, ProgressState_IndicatorNotSupported) {
+  AlertViewController* alert = [[AlertViewController alloc] init];
+  [alert setValue:@NO forKey:@"_shouldShowActivityIndicator"];
+
+  (void)alert.view;
+
+  // Verify views were not created
+  EXPECT_FALSE(GetSpinner(alert));
+  EXPECT_FALSE(GetCheckmark(alert));
+
+  [alert setProgressState:ProgressIndicatorStateSuccess];
+
+  // Verify internal state updated, but no views to affect
+  EXPECT_EQ(ProgressIndicatorStateSuccess, alert.progressState);
+}
+
+// Tests that setting state before view loads applies correctly after load.
+TEST_F(AlertViewControllerTest, ProgressState_SetStateBeforeViewLoad) {
+  AlertViewController* alert = [[AlertViewController alloc] init];
+  [alert setValue:@YES forKey:@"_shouldShowActivityIndicator"];
+
+  // Verify internal state is set
+  EXPECT_EQ(ProgressIndicatorStateNone, alert.progressState);
+
+  // Verify views don't exist yet
+  EXPECT_FALSE([alert valueForKey:@"_spinner"]);
+  EXPECT_FALSE([alert valueForKey:@"_checkmark"]);
+
+  // Trigger view loading (which calls viewDidLoad, applying the state)
+  (void)alert.view;
+  UIActivityIndicatorView* spinner = GetSpinner(alert);
+  UIImageView* checkmark = GetCheckmark(alert);
+
+  // Verify Activity state is now applied visually
+  ASSERT_TRUE(spinner);
+  ASSERT_TRUE(checkmark);
+  EXPECT_FALSE(spinner.hidden);
+  EXPECT_TRUE(spinner.isAnimating);
+  EXPECT_TRUE(checkmark.hidden);
+}
diff --git a/ios/chrome/browser/alert_view/ui_bundled/test/fake_alert_consumer.mm b/ios/chrome/browser/alert_view/ui_bundled/test/fake_alert_consumer.mm
index 10f03336..46e5fc24 100644
--- a/ios/chrome/browser/alert_view/ui_bundled/test/fake_alert_consumer.mm
+++ b/ios/chrome/browser/alert_view/ui_bundled/test/fake_alert_consumer.mm
@@ -10,4 +10,6 @@
         darkModeLottieName:imageDarkModeLottieName {
 }
 
+- (void)setProgressState:(ProgressIndicatorState)progressState {
+}
 @end
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/features.mm b/ios/chrome/browser/authentication/ui_bundled/signin/features.mm
index 1f07dcf..2ff4f083 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin/features.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/signin/features.mm
@@ -6,7 +6,7 @@
 
 BASE_FEATURE(kFullscreenSigninPromoManagerMigration,
              "FullscreenSigninPromoManagerMigration",
-             base::FEATURE_ENABLED_BY_DEFAULT);
+             base::FEATURE_DISABLED_BY_DEFAULT);
 
 bool IsFullscreenSigninPromoManagerMigrationEnabled() {
   return base::FeatureList::IsEnabled(kFullscreenSigninPromoManagerMigration);
diff --git a/ios/chrome/browser/autofill/ui_bundled/progress_dialog/BUILD.gn b/ios/chrome/browser/autofill/ui_bundled/progress_dialog/BUILD.gn
index 860403b..354a773 100644
--- a/ios/chrome/browser/autofill/ui_bundled/progress_dialog/BUILD.gn
+++ b/ios/chrome/browser/autofill/ui_bundled/progress_dialog/BUILD.gn
@@ -20,6 +20,7 @@
     "//ios/chrome/browser/shared/model/browser",
     "//ios/chrome/browser/shared/model/web_state_list",
     "//ios/chrome/browser/shared/public/commands",
+    "//ios/chrome/browser/shared/ui/symbols",
   ]
   frameworks = [ "UIKit.framework" ]
 }
@@ -29,8 +30,11 @@
   sources = [ "autofill_progress_dialog_mediator_unittest.mm" ]
   deps = [
     ":progress_dialog",
+    "//base/test:test_support",
     "//components/autofill/core/browser",
+    "//components/autofill/ios/browser:test_support",
     "//ios/chrome/browser/alert_view/ui_bundled",
+    "//ios/chrome/browser/shared/ui/symbols:symbols",
     "//testing/gtest",
     "//third_party/ocmock",
   ]
diff --git a/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator.mm b/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator.mm
index e78eaadf5..ae1694e 100644
--- a/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator.mm
@@ -12,6 +12,7 @@
 #import "ios/chrome/browser/alert_view/ui_bundled/alert_action.h"
 #import "ios/chrome/browser/alert_view/ui_bundled/alert_consumer.h"
 #import "ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator_delegate.h"
+#import "ios/chrome/browser/shared/ui/symbols/symbols.h"
 
 AutofillProgressDialogMediator::AutofillProgressDialogMediator(
     base::WeakPtr<autofill::AutofillProgressDialogControllerImpl>
@@ -31,9 +32,17 @@
 void AutofillProgressDialogMediator::Dismiss(
     bool show_confirmation_before_closing,
     bool is_canceled_by_user) {
-  // TODO(crbug.com/324603292): Check whether we need the confirmation on iOS.
   is_canceled_by_user_ = is_canceled_by_user;
-  [delegate_ dismissDialog];
+  if (show_confirmation_before_closing) {
+    [consumer_ setProgressState:ProgressIndicatorStateSuccess];
+    [consumer_ setActions:@[]];
+
+    // TODO(crbug.com/413453967): Add dismiss delay logic to IOS autofill
+    // progress dialog
+    [delegate_ dismissDialog];
+  } else {
+    [delegate_ dismissDialog];
+  }
 }
 
 void AutofillProgressDialogMediator::InvalidateControllerForCallbacks() {
diff --git a/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator_unittest.mm b/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator_unittest.mm
index 94d2bc2..9320f3e 100644
--- a/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator_unittest.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator_unittest.mm
@@ -10,6 +10,8 @@
 #import "ios/chrome/browser/alert_view/ui_bundled/alert_action.h"
 #import "ios/chrome/browser/alert_view/ui_bundled/alert_consumer.h"
 #import "ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_mediator_delegate.h"
+#import "ios/chrome/browser/shared/ui/symbols/symbols.h"
+#import "testing/gtest/include/gtest/gtest.h"
 #import "testing/platform_test.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
 #import "third_party/ocmock/gtest_support.h"
@@ -57,3 +59,18 @@
 
   EXPECT_OCMOCK_VERIFY(delegate_);
 }
+
+// Tests that when showing confirmation, the consumer is updated correctly.
+TEST_F(AutofillProgressDialogMediatorTest,
+       DismissDialog_ShowConfirmation_UpdatesConsumer) {
+  mediator_->SetConsumer(consumer_);
+
+  // Expectations for the consumer when showing confirmation.
+  OCMExpect([consumer_ setProgressState:ProgressIndicatorStateSuccess]);
+  OCMExpect([consumer_ setActions:@[]]);
+
+  mediator_->Dismiss(/*show_confirmation_before_closing=*/true,
+                     /*is_canceled_by_user=*/false);
+
+  EXPECT_OCMOCK_VERIFY(consumer_);
+}
diff --git a/ios/chrome/browser/enterprise/connectors/reporting/ios_reporting_event_router_unittest.mm b/ios/chrome/browser/enterprise/connectors/reporting/ios_reporting_event_router_unittest.mm
index c7699e33..65c90fa 100644
--- a/ios/chrome/browser/enterprise/connectors/reporting/ios_reporting_event_router_unittest.mm
+++ b/ios/chrome/browser/enterprise/connectors/reporting/ios_reporting_event_router_unittest.mm
@@ -437,9 +437,9 @@
       /*enabled_opt_in_events=*/{});
 
   test::EventReportValidatorBase validator(client_.get());
-  validator.ExpectSecurityInterstitialShown(
+  validator.ExpectSecurityInterstitialEvent(
       "https://phishing.com/", "PHISHING", profile_->GetProfileName(),
-      GetProfileIdentifier(), "EVENT_RESULT_WARNED", 0);
+      GetProfileIdentifier(), "EVENT_RESULT_WARNED", false, 0);
   reporting_event_router_->OnSecurityInterstitialShown(
       GURL("https://phishing.com/"), "PHISHING", 0, false);
 }
@@ -452,11 +452,26 @@
       /*enabled_opt_in_events=*/{});
 
   test::EventReportValidatorBase validator(client_.get());
-  validator.ExpectSecurityInterstitialShown(
+  validator.ExpectSecurityInterstitialEvent(
       "https://phishing.com/", "PHISHING", profile_->GetProfileName(),
-      GetProfileIdentifier(), "EVENT_RESULT_BLOCKED", 0);
+      GetProfileIdentifier(), "EVENT_RESULT_BLOCKED", false, 0);
   reporting_event_router_->OnSecurityInterstitialShown(
       GURL("https://phishing.com/"), "PHISHING", 0, true);
 }
 
+// Tests that interstitial reporting events bypassed as expected.
+TEST_F(IOSReportingEventRouterTest, TestInterstitialProceeded) {
+  test::SetOnSecurityEventReporting(
+      profile_->GetTestingPrefService(), /*enabled=*/true,
+      /*enabled_event_names=*/{kKeyInterstitialEvent},
+      /*enabled_opt_in_events=*/{});
+
+  test::EventReportValidatorBase validator(client_.get());
+  validator.ExpectSecurityInterstitialEvent(
+      "https://phishing.com/", "PHISHING", profile_->GetProfileName(),
+      GetProfileIdentifier(), "EVENT_RESULT_BYPASSED", true, 0);
+  reporting_event_router_->OnSecurityInterstitialProceeded(
+      GURL("https://phishing.com/"), "PHISHING", 0);
+}
+
 }  // namespace enterprise_connectors
diff --git a/ios/chrome/browser/feature_engagement/model/BUILD.gn b/ios/chrome/browser/feature_engagement/model/BUILD.gn
index d60761c..e0cd907 100644
--- a/ios/chrome/browser/feature_engagement/model/BUILD.gn
+++ b/ios/chrome/browser/feature_engagement/model/BUILD.gn
@@ -64,6 +64,7 @@
     "//base/test:test_support",
     "//components/feature_engagement/public",
     "//components/feature_engagement/test:test_support",
+    "//ios/chrome/browser/authentication/ui_bundled/signin:features",
     "//ios/chrome/browser/authentication/ui_bundled/signin:signin_headers",
     "//ios/chrome/browser/default_browser/model:default_browser_interest_signals",
     "//ios/chrome/browser/default_browser/model:test_support",
diff --git a/ios/chrome/browser/feature_engagement/model/event_exporter_unittest.mm b/ios/chrome/browser/feature_engagement/model/event_exporter_unittest.mm
index 27f7192..b97e5e7 100644
--- a/ios/chrome/browser/feature_engagement/model/event_exporter_unittest.mm
+++ b/ios/chrome/browser/feature_engagement/model/event_exporter_unittest.mm
@@ -10,6 +10,7 @@
 #import "components/feature_engagement/public/event_constants.h"
 #import "components/feature_engagement/public/tracker.h"
 #import "components/feature_engagement/test/test_tracker.h"
+#import "ios/chrome/browser/authentication/ui_bundled/signin/features.h"
 #import "ios/chrome/browser/authentication/ui_bundled/signin/signin_utils.h"
 #import "ios/chrome/browser/default_browser/model/default_browser_interest_signals.h"
 #import "ios/chrome/browser/default_browser/model/utils.h"
@@ -468,6 +469,9 @@
 }
 
 TEST_F(EventExporterTest, TestSigninFullscreenPromoImpressionsMigration) {
+  if (!IsFullscreenSigninPromoManagerMigrationEnabled()) {
+    return;
+  }
   // No events to export.
   RequestExportEventsAndVerifyCallback();
   EXPECT_EQ(GetExportEventsCount(), 0);
diff --git a/ios/chrome/browser/flags/BUILD.gn b/ios/chrome/browser/flags/BUILD.gn
index 1809ca36..71c7860 100644
--- a/ios/chrome/browser/flags/BUILD.gn
+++ b/ios/chrome/browser/flags/BUILD.gn
@@ -45,6 +45,7 @@
     "//components/policy/core/common:common_constants",
     "//components/safe_browsing/core/common",
     "//components/safe_browsing/ios/browser/web_ui:features",
+    "//components/search",
     "//components/search_engines:search_engines_switches",
     "//components/search_provider_logos",
     "//components/security_state/core",
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index b347e36..570e2618 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -58,6 +58,7 @@
 #import "components/policy/policy_constants.h"
 #import "components/safe_browsing/core/common/features.h"
 #import "components/safe_browsing/ios/browser/web_ui/features.h"
+#import "components/search/ntp_features.cc"
 #import "components/search_engines/search_engines_switches.h"
 #import "components/segmentation_platform/embedder/home_modules/constants.h"
 #import "components/segmentation_platform/public/constants.h"
@@ -1508,6 +1509,11 @@
      flag_descriptions::kNTPBackgroundCustomizationName,
      flag_descriptions::kNTPBackgroundCustomizationDescription,
      flags_ui::kOsIos, FEATURE_VALUE_TYPE(kNTPBackgroundCustomization)},
+    {"ntp-alpha-background-collections",
+     flag_descriptions::kNtpAlphaBackgroundCollectionsName,
+     flag_descriptions::kNtpAlphaBackgroundCollectionsDescription,
+     flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(ntp_features::kNtpAlphaBackgroundCollections)},
     {"fullscreen-promos-manager-skip-internal-limits",
      flag_descriptions::kFullscreenPromosManagerSkipInternalLimitsName,
      flag_descriptions::kFullscreenPromosManagerSkipInternalLimitsDescription,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index e170ae7a..3b7ed8a 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -1316,6 +1316,11 @@
 const char kNTPBackgroundCustomizationDescription[] =
     "When enabled, the background customization menu is available on the NTP.";
 
+const char kNtpAlphaBackgroundCollectionsName[] =
+    "Enable alpha background collections";
+const char kNtpAlphaBackgroundCollectionsDescription[] =
+    "When enabled, the alpha background collections are available on the NTP.";
+
 const char kSpotlightNeverRetainIndexName[] = "Don't retain spotlight index";
 const char kSpotlightNeverRetainIndexDescription[] =
     "Tentative spotlight memory improvement by not storing a strong pointer to "
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index 931d0e0..b63b841 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -778,6 +778,9 @@
 extern const char kNTPBackgroundCustomizationName[];
 extern const char kNTPBackgroundCustomizationDescription[];
 
+extern const char kNtpAlphaBackgroundCollectionsName[];
+extern const char kNtpAlphaBackgroundCollectionsDescription[];
+
 extern const char kSpotlightNeverRetainIndexName[];
 extern const char kSpotlightNeverRetainIndexDescription[];
 
diff --git a/ios/chrome/browser/intelligence/glic/coordinator/BUILD.gn b/ios/chrome/browser/intelligence/glic/coordinator/BUILD.gn
new file mode 100644
index 0000000..4626e6d7
--- /dev/null
+++ b/ios/chrome/browser/intelligence/glic/coordinator/BUILD.gn
@@ -0,0 +1,17 @@
+# 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.
+
+source_set("coordinator") {
+  sources = [
+    "glic_consent_coordinator.h",
+    "glic_consent_coordinator.mm",
+    "glic_consent_mediator.h",
+    "glic_consent_mediator.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/browser/intelligence/glic/ui",
+    "//ios/chrome/browser/shared/coordinator/chrome_coordinator",
+  ]
+}
diff --git a/ios/chrome/browser/intelligence/glic/coordinator/glic_consent_coordinator.h b/ios/chrome/browser/intelligence/glic/coordinator/glic_consent_coordinator.h
new file mode 100644
index 0000000..c9934ac
--- /dev/null
+++ b/ios/chrome/browser/intelligence/glic/coordinator/glic_consent_coordinator.h
@@ -0,0 +1,15 @@
+// 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 IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_COORDINATOR_GLIC_CONSENT_COORDINATOR_H_
+#define IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_COORDINATOR_GLIC_CONSENT_COORDINATOR_H_
+
+#import "ios/chrome/browser/shared/coordinator/chrome_coordinator/chrome_coordinator.h"
+
+// Coordinator that manages the privacy consent flow shown to new Glic users.
+@interface GlicConsentCoordinator : ChromeCoordinator
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_COORDINATOR_GLIC_CONSENT_COORDINATOR_H_
diff --git a/ios/chrome/browser/intelligence/glic/coordinator/glic_consent_coordinator.mm b/ios/chrome/browser/intelligence/glic/coordinator/glic_consent_coordinator.mm
new file mode 100644
index 0000000..4e589ea
--- /dev/null
+++ b/ios/chrome/browser/intelligence/glic/coordinator/glic_consent_coordinator.mm
@@ -0,0 +1,54 @@
+// 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.
+
+#import "ios/chrome/browser/intelligence/glic/coordinator/glic_consent_coordinator.h"
+
+#import "base/functional/bind.h"
+#import "ios/chrome/browser/intelligence/glic/coordinator/glic_consent_mediator.h"
+#import "ios/chrome/browser/intelligence/glic/ui/glic_consent_view_controller.h"
+
+@interface GlicConsentCoordinator () <UISheetPresentationControllerDelegate>
+
+@end
+
+@implementation GlicConsentCoordinator {
+  GlicConsentMediator* _mediator;
+  GlicConsentViewController* _viewController;
+}
+
+#pragma mark - ChromeCoordinator
+
+// Starts the coordinator.
+- (void)start {
+  _mediator = [[GlicConsentMediator alloc] init];
+  _viewController = [[GlicConsentViewController alloc] init];
+
+  _viewController.sheetPresentationController.delegate = self;
+
+  [self.baseViewController presentViewController:_viewController
+                                        animated:YES
+                                      completion:nil];
+  [super start];
+}
+
+// Stops the coordinator.
+- (void)stop {
+  if (_viewController.presentingViewController) {
+    [self.baseViewController dismissViewControllerAnimated:YES completion:nil];
+  }
+
+  _mediator = nil;
+  _viewController = nil;
+  [super stop];
+}
+
+#pragma mark - UISheetPresentationControllerDelegate
+
+// Handles the dismiss the UI.
+- (void)presentationControllerDidDismiss:
+    (UIPresentationController*)presentationController {
+  [self stop];
+}
+
+@end
diff --git a/ios/chrome/browser/intelligence/glic/coordinator/glic_consent_mediator.h b/ios/chrome/browser/intelligence/glic/coordinator/glic_consent_mediator.h
new file mode 100644
index 0000000..ca81947
--- /dev/null
+++ b/ios/chrome/browser/intelligence/glic/coordinator/glic_consent_mediator.h
@@ -0,0 +1,15 @@
+// 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 IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_COORDINATOR_GLIC_CONSENT_MEDIATOR_H_
+#define IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_COORDINATOR_GLIC_CONSENT_MEDIATOR_H_
+
+#import <Foundation/Foundation.h>
+
+// Glic Consent Mediator.
+@interface GlicConsentMediator : NSObject
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_COORDINATOR_GLIC_CONSENT_MEDIATOR_H_
diff --git a/ios/chrome/browser/intelligence/glic/coordinator/glic_consent_mediator.mm b/ios/chrome/browser/intelligence/glic/coordinator/glic_consent_mediator.mm
new file mode 100644
index 0000000..2e75d5a
--- /dev/null
+++ b/ios/chrome/browser/intelligence/glic/coordinator/glic_consent_mediator.mm
@@ -0,0 +1,11 @@
+// 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.
+
+#import "ios/chrome/browser/intelligence/glic/coordinator/glic_consent_mediator.h"
+
+#import "ios/chrome/browser/intelligence/glic/ui/glic_consent_view_controller.h"
+
+@implementation GlicConsentMediator
+
+@end
diff --git a/ios/chrome/browser/intelligence/glic/ui/BUILD.gn b/ios/chrome/browser/intelligence/glic/ui/BUILD.gn
new file mode 100644
index 0000000..fc66de9
--- /dev/null
+++ b/ios/chrome/browser/intelligence/glic/ui/BUILD.gn
@@ -0,0 +1,15 @@
+# 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.
+
+source_set("ui") {
+  sources = [
+    "glic_consent_view_controller.h",
+    "glic_consent_view_controller.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/common/ui/promo_style",
+  ]
+  frameworks = [ "UIKit.framework" ]
+}
diff --git a/ios/chrome/browser/intelligence/glic/ui/glic_consent_view_controller.h b/ios/chrome/browser/intelligence/glic/ui/glic_consent_view_controller.h
new file mode 100644
index 0000000..110f883
--- /dev/null
+++ b/ios/chrome/browser/intelligence/glic/ui/glic_consent_view_controller.h
@@ -0,0 +1,17 @@
+// 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 IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_UI_GLIC_CONSENT_VIEW_CONTROLLER_H_
+#define IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_UI_GLIC_CONSENT_VIEW_CONTROLLER_H_
+
+#import <UIKit/UIKit.h>
+
+#import "ios/chrome/common/ui/promo_style/promo_style_view_controller.h"
+
+// Glic Consent View Controller.
+@interface GlicConsentViewController : PromoStyleViewController
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_INTELLIGENCE_GLIC_UI_GLIC_CONSENT_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/intelligence/glic/ui/glic_consent_view_controller.mm b/ios/chrome/browser/intelligence/glic/ui/glic_consent_view_controller.mm
new file mode 100644
index 0000000..c806b38
--- /dev/null
+++ b/ios/chrome/browser/intelligence/glic/ui/glic_consent_view_controller.mm
@@ -0,0 +1,39 @@
+// 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.
+
+#import "ios/chrome/browser/intelligence/glic/ui/glic_consent_view_controller.h"
+
+@implementation GlicConsentViewController
+
+#pragma mark - UIViewController
+
+// TODO(crbug.com/414777915): Implement a basic UI.
+- (void)viewDidLoad {
+  self.layoutBehindNavigationBar = YES;
+  self.shouldHideBanner = YES;
+  self.headerImageType = PromoStyleImageType::kNone;
+
+  self.modalPresentationStyle = UIModalPresentationPageSheet;
+
+  // TODO(crbug.com/414777890): Use a custom detent.
+  self.sheetPresentationController.detents = @[
+    [UISheetPresentationControllerDetent mediumDetent],
+    [UISheetPresentationControllerDetent largeDetent]
+  ];
+
+  self.sheetPresentationController.preferredCornerRadius = 16.0;
+
+  UIView* rootView = [[UIView alloc] initWithFrame:UIScreen.mainScreen.bounds];
+  rootView.backgroundColor = [UIColor systemBackgroundColor];
+  [self.view addSubview:rootView];
+
+  // TODO(crbug.com/414778685): Add strings.
+  self.primaryActionString = @"Yes, I'm in";
+  self.secondaryActionString = @"No thanks";
+
+  self.bannerSize = BannerImageSizeType::kStandard;
+  [super viewDidLoad];
+}
+
+@end
diff --git a/ios/chrome/browser/intelligence/page_action_menu/coordinator/BUILD.gn b/ios/chrome/browser/intelligence/page_action_menu/coordinator/BUILD.gn
index b932415..968dd13 100644
--- a/ios/chrome/browser/intelligence/page_action_menu/coordinator/BUILD.gn
+++ b/ios/chrome/browser/intelligence/page_action_menu/coordinator/BUILD.gn
@@ -8,6 +8,7 @@
     "page_action_menu_coordinator.mm",
   ]
   deps = [
+    "//ios/chrome/browser/intelligence/glic/coordinator",
     "//ios/chrome/browser/intelligence/glic/model",
     "//ios/chrome/browser/intelligence/glic/model:glic_service_factory",
     "//ios/chrome/browser/intelligence/proto_wrappers",
diff --git a/ios/chrome/browser/intelligence/page_action_menu/coordinator/page_action_menu_coordinator.mm b/ios/chrome/browser/intelligence/page_action_menu/coordinator/page_action_menu_coordinator.mm
index e6100527..2482eb5 100644
--- a/ios/chrome/browser/intelligence/page_action_menu/coordinator/page_action_menu_coordinator.mm
+++ b/ios/chrome/browser/intelligence/page_action_menu/coordinator/page_action_menu_coordinator.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/intelligence/page_action_menu/coordinator/page_action_menu_coordinator.h"
 
 #import "base/functional/callback_helpers.h"
+#import "ios/chrome/browser/intelligence/glic/coordinator/glic_consent_coordinator.h"
 #import "ios/chrome/browser/intelligence/glic/model/glic_service.h"
 #import "ios/chrome/browser/intelligence/glic/model/glic_service_factory.h"
 #import "ios/chrome/browser/intelligence/proto_wrappers/page_context_wrapper.h"
@@ -15,6 +16,7 @@
 @implementation PageActionMenuCoordinator {
   // The PageContext wrapper used to provide context about a page.
   PageContextWrapper* _pageContextWrapper;
+  GlicConsentCoordinator* _glicConsentCoordinator;
 }
 
 #pragma mark - ChromeCoordinator
@@ -23,7 +25,6 @@
   // TODO(crbug.com/408006823): Have the view controller call this when its
   // button is pressed.
   [self handleEntryPointPressed];
-
   [super start];
 }
 
@@ -35,6 +36,29 @@
 
 // TODO(crbug.com/408006823): Rename this function.
 - (void)handleEntryPointPressed {
+  if ([self shouldShowGlicConsent]) {
+    [self showGlicConsent];
+    return;
+  }
+  [self prepareGlicOverlay];
+}
+
+// TODO(crbug.com/414419915): Present Consent UI when Glic is used for the first
+// time or the user declined it.
+- (BOOL)shouldShowGlicConsent {
+  return NO;
+}
+
+- (void)showGlicConsent {
+  _glicConsentCoordinator = [[GlicConsentCoordinator alloc]
+      initWithBaseViewController:self.baseViewController
+                         browser:self.browser];
+
+  [_glicConsentCoordinator start];
+}
+
+// Prepare Glic overlay.
+- (void)prepareGlicOverlay {
   // Cancel any ongoing page context operation.
   if (_pageContextWrapper) {
     _pageContextWrapper = nil;
diff --git a/ios/chrome/browser/passwords/model/BUILD.gn b/ios/chrome/browser/passwords/model/BUILD.gn
index 9e31684..3e57926 100644
--- a/ios/chrome/browser/passwords/model/BUILD.gn
+++ b/ios/chrome/browser/passwords/model/BUILD.gn
@@ -332,14 +332,11 @@
     "//base/test:test_support",
     "//components/autofill/core/browser:test_support",
     "//components/autofill/ios/common",
-    "//components/enterprise",
-    "//components/enterprise/connectors/core",
     "//components/enterprise/connectors/core:test_support",
     "//components/password_manager/core/browser/features:password_features",
     "//components/password_manager/core/common",
     "//components/plus_addresses:features",
     "//components/policy/core/common:common_constants",
-    "//components/policy/test_support",
     "//components/strings",
     "//components/sync/base",
     "//components/sync/service",
diff --git a/ios/chrome/browser/passwords/model/DEPS b/ios/chrome/browser/passwords/model/DEPS
index 18314cb2..57214192 100644
--- a/ios/chrome/browser/passwords/model/DEPS
+++ b/ios/chrome/browser/passwords/model/DEPS
@@ -17,7 +17,4 @@
     "+ios/chrome/browser/shared/ui/util/rtl_geometry.h",
     "+ios/chrome/browser/shared/ui/util/uikit_ui_util.h",
   ],
-  "^password_controller_egtest.mm": [
-    "+components/policy/test_support/embedded_policy_test_server.h",
-  ],
 }
diff --git a/ios/chrome/browser/passwords/model/password_controller_egtest.mm b/ios/chrome/browser/passwords/model/password_controller_egtest.mm
index 6955ea05..1841a25 100644
--- a/ios/chrome/browser/passwords/model/password_controller_egtest.mm
+++ b/ios/chrome/browser/passwords/model/password_controller_egtest.mm
@@ -8,6 +8,7 @@
 #import <memory>
 
 #import "base/check.h"
+#import "base/strings/strcat.h"
 #import "base/strings/sys_string_conversions.h"
 #import "base/test/ios/wait_util.h"
 #import "base/time/time.h"
@@ -15,16 +16,11 @@
 #import "components/autofill/core/browser/field_types.h"
 #import "components/autofill/core/browser/test_utils/autofill_test_utils.h"
 #import "components/autofill/ios/common/features.h"
-#import "components/enterprise/browser/enterprise_switches.h"
-#import "components/enterprise/connectors/core/features.h"
-#import "components/enterprise/connectors/core/realtime_reporting_test_server.h"
-#import "components/enterprise/connectors/core/reporting_test_utils.h"
+#import "components/enterprise/connectors/core/realtime_reporting_test_environment.h"
 #import "components/password_manager/core/browser/features/password_features.h"
 #import "components/password_manager/core/common/password_manager_features.h"
 #import "components/plus_addresses/features.h"
 #import "components/policy/core/common/policy_loader_ios_constants.h"
-#import "components/policy/core/common/policy_switches.h"
-#import "components/policy/test_support/embedded_policy_test_server.h"
 #import "components/strings/grit/components_strings.h"
 #import "components/sync/base/user_selectable_type.h"
 #import "components/sync/service/sync_prefs.h"
@@ -68,6 +64,7 @@
 using chrome_test_util::SettingsDoneButton;
 using chrome_test_util::TapWebElementWithId;
 using chrome_test_util::UseSuggestedPasswordMatcher;
+using enterprise_connectors::test::RealtimeReportingTestEnvironment;
 
 using testing::ElementWithAccessibilityLabelSubstring;
 
@@ -167,9 +164,7 @@
 @end
 
 @implementation PasswordControllerEGTest {
-  std::unique_ptr<policy::EmbeddedPolicyTestServer> _policyServer;
-  std::unique_ptr<enterprise_connectors::test::RealtimeReportingTestServer>
-      _reportingServer;
+  std::unique_ptr<RealtimeReportingTestEnvironment> _reportingEnvironment;
 }
 
 - (void)setUp {
@@ -178,14 +173,10 @@
     // addresses can be added to the app launch config. `GREYAssertTrue` can
     // only be used after calling the superclass's `-setUp`, so use `CHECK()`
     // instead.
-    _policyServer =
-        enterprise_connectors::test::CreatePolicyTestServerForSecurityEvents(
-            {"loginEvent"}, {{"loginEvent", {"*"}}});
-    CHECK(_policyServer);
-    CHECK(_policyServer->Start());
-    _reportingServer = std::make_unique<
-        enterprise_connectors::test::RealtimeReportingTestServer>();
-    CHECK(_reportingServer->Start());
+    _reportingEnvironment = RealtimeReportingTestEnvironment::Create(
+        {"loginEvent"}, {{"loginEvent", {"*"}}});
+    CHECK(_reportingEnvironment);
+    CHECK(_reportingEnvironment->Start());
   }
 
   // This call launches the application and will wait for the profile to be
@@ -230,23 +221,16 @@
   // Set Enterprise features for testing password-related event reporting. The
   // policy and reporting servers must be started by this point.
   if ([self isRunningTest:@selector(testLoginEventReported)]) {
-    CHECK(_policyServer);
-    CHECK(_reportingServer);
-    config.additional_args.push_back(
-        base::StrCat({"--", switches::kEnableChromeBrowserCloudManagement}));
+    CHECK(_reportingEnvironment);
+    std::vector<std::string> reporting_args =
+        _reportingEnvironment->GetArguments();
+    config.additional_args.insert(config.additional_args.end(),
+                                  reporting_args.begin(), reporting_args.end());
     config.additional_args.push_back(base::StrCat(
         {"-", base::SysNSStringToUTF8(kPolicyLoaderIOSConfigurationKey)}));
     config.additional_args.push_back(
         base::StrCat({"<dict><key>", kEnrollmentTokenPolicyName,
                       "</key><string>", kEnrollmentToken, "</string></dict>"}));
-    config.additional_args.push_back(
-        base::StrCat({"--", policy::switches::kDeviceManagementUrl, "=",
-                      _policyServer->GetServiceURL().spec()}));
-    config.additional_args.push_back(
-        base::StrCat({"--", policy::switches::kRealtimeReportingUrl, "=",
-                      _reportingServer->GetServiceURL().spec()}));
-    config.features_enabled.push_back(
-        enterprise_connectors::kEnterpriseRealtimeEventReportingOnIOS);
     config.relaunch_policy = ForceRelaunchByKilling;
   }
 
@@ -768,7 +752,7 @@
 
   // Use metrics to detect that the report upload completed. This is the best
   // known way to wait because a task environment isn't available here, so
-  // there's nothing for `_reportingServer` to post to when the request
+  // there's nothing for the reporting server to post to when the request
   // arrives. This also precludes helpers like `base::RunLoop` or
   // `net::test_server::ControllableHttpResponse` that require such an
   // environment.
@@ -787,7 +771,7 @@
           forHistogram:@"Enterprise.ReportingEventUploadFailure"]);
 
   std::vector<UploadEventsRequest> requests =
-      _reportingServer->GetUploadedReports();
+      _reportingEnvironment->reporting_server()->GetUploadedReports();
   GREYAssertEqual(1U, requests.size(), @"Wrong number of reports.");
   GREYAssertEqual(std::string("iOS"), requests[0].device().os_platform(),
                   @"Wrong OS platform in report.");
diff --git a/ios/chrome/browser/safe_browsing/model/BUILD.gn b/ios/chrome/browser/safe_browsing/model/BUILD.gn
index 496e353b..5337cef6 100644
--- a/ios/chrome/browser/safe_browsing/model/BUILD.gn
+++ b/ios/chrome/browser/safe_browsing/model/BUILD.gn
@@ -132,6 +132,11 @@
   ]
   deps = [
     "//base",
+    "//components/enterprise/common/proto:browser_events_proto",
+    "//components/enterprise/common/proto:chrome_reporting_entity",
+    "//components/enterprise/common/proto:upload_request_response",
+    "//components/enterprise/connectors/core:test_support",
+    "//components/policy/core/common:common_constants",
     "//components/safe_browsing/core/common",
     "//components/safe_browsing/core/common:safe_browsing_prefs",
     "//components/strings",
@@ -139,6 +144,7 @@
     "//ios/chrome/browser/bookmarks/model:bookmark_storage_type",
     "//ios/chrome/browser/bookmarks/ui_bundled:eg_test_support+eg2",
     "//ios/chrome/browser/infobars/ui_bundled/banners:public",
+    "//ios/chrome/browser/metrics/model:eg_test_support+eg2",
     "//ios/chrome/browser/passwords/model:eg_test_support+eg2",
     "//ios/chrome/browser/passwords/ui_bundled:constants",
     "//ios/chrome/browser/settings/ui_bundled/privacy:privacy_constants",
diff --git a/ios/chrome/browser/safe_browsing/model/safe_browsing_egtest.mm b/ios/chrome/browser/safe_browsing/model/safe_browsing_egtest.mm
index 9f0be088..6a0adf55 100644
--- a/ios/chrome/browser/safe_browsing/model/safe_browsing_egtest.mm
+++ b/ios/chrome/browser/safe_browsing/model/safe_browsing_egtest.mm
@@ -2,11 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#import <memory>
 #import <string>
+#import <vector>
 
+#import "base/check.h"
+#import "base/strings/strcat.h"
 #import "base/strings/string_util.h"
 #import "base/strings/sys_string_conversions.h"
 #import "base/test/ios/wait_util.h"
+#import "base/time/time.h"
+#import "components/enterprise/common/proto/synced/browser_events.pb.h"
+#import "components/enterprise/common/proto/synced_from_google3/chrome_reporting_entity.pb.h"
+#import "components/enterprise/common/proto/upload_request_response.pb.h"
+#import "components/enterprise/connectors/core/realtime_reporting_test_environment.h"
+#import "components/policy/core/common/policy_loader_ios_constants.h"
 #import "components/safe_browsing/core/common/features.h"
 #import "components/safe_browsing/core/common/safe_browsing_prefs.h"
 #import "components/strings/grit/components_strings.h"
@@ -14,6 +24,7 @@
 #import "ios/chrome/browser/bookmarks/ui_bundled/bookmark_earl_grey.h"
 #import "ios/chrome/browser/bookmarks/ui_bundled/bookmark_earl_grey_ui.h"
 #import "ios/chrome/browser/infobars/ui_bundled/banners/infobar_banner_constants.h"
+#import "ios/chrome/browser/metrics/model/metrics_app_interface.h"
 #import "ios/chrome/browser/settings/ui_bundled/privacy/privacy_constants.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
@@ -28,10 +39,18 @@
 #import "net/test/embedded_test_server/http_response.h"
 #import "ui/base/l10n/l10n_util.h"
 
+using ::chrome::cros::reporting::proto::Event;
+using ::chrome::cros::reporting::proto::EventResult;
+using ::chrome::cros::reporting::proto::SafeBrowsingInterstitialEvent;
+using InterstitialReason = ::chrome::cros::reporting::proto::
+    SafeBrowsingInterstitialEvent::InterstitialReason;
+using ::chrome::cros::reporting::proto::UploadEventsRequest;
 using chrome_test_util::BackButton;
 using chrome_test_util::ForwardButton;
+using chrome_test_util::GREYAssertErrorNil;
 using chrome_test_util::SettingsDoneButton;
 using chrome_test_util::TappableBookmarkNodeWithLabel;
+using enterprise_connectors::test::RealtimeReportingTestEnvironment;
 
 namespace {
 
@@ -43,6 +62,13 @@
 const char kMalwareWarningDetails[] =
     "Google Safe Browsing, which recently found malware";
 
+// Policy name and value for setting a fake enterprise enrollment token.
+constexpr char kEnrollmentTokenPolicyName[] = "CloudManagementEnrollmentToken";
+constexpr char kEnrollmentToken[] = "fake-enrollment-token";
+
+// Duration to wait for an enterprise security event report.
+constexpr base::TimeDelta kReportUploadTimeout = base::Seconds(15);
+
 // Request handler for net::EmbeddedTestServer that returns the request URL's
 // path as the body of the response if the request URL's path starts with
 // "/echo". Otherwise, returns nulltpr to allow other handlers to handle the
@@ -101,6 +127,8 @@
   BOOL _safeBrowsingEnhancedPrefDefault;
   // The default value for SafeBrowsingProceedAnywayDisabled pref.
   BOOL _proceedAnywayDisabledPrefDefault;
+  // Fake servers for testing enterprise security event reporting.
+  std::unique_ptr<RealtimeReportingTestEnvironment> _reportingEnvironment;
 }
 @end
 
@@ -133,6 +161,19 @@
         std::string("--enable-features=SafeBrowsingHashPrefixRealTimeLookups"));
   }
 
+  if ([self isRunningEnterpriseReportingTest]) {
+    CHECK(_reportingEnvironment);
+    std::vector<std::string> reporting_args =
+        _reportingEnvironment->GetArguments();
+    config.additional_args.insert(config.additional_args.end(),
+                                  reporting_args.begin(), reporting_args.end());
+    config.additional_args.push_back(base::StrCat(
+        {"-", base::SysNSStringToUTF8(kPolicyLoaderIOSConfigurationKey)}));
+    config.additional_args.push_back(
+        base::StrCat({"<dict><key>", kEnrollmentTokenPolicyName,
+                      "</key><string>", kEnrollmentToken, "</string></dict>"}));
+  }
+
   config.additional_args.push_back(
       std::string("--mark_as_real_time_phishing=") +
       _realTimePhishingURL.spec());
@@ -174,6 +215,15 @@
   _iframeWithPhishingURL =
       _iframeWithPhishingURL.ReplaceComponents(replacements);
 
+  if ([self isRunningEnterpriseReportingTest]) {
+    // `GREYAssertTrue` can't be used before the superclass's `-setUp` call is
+    // complete, so fall back to `CHECK()`.
+    _reportingEnvironment = RealtimeReportingTestEnvironment::Create(
+        {"interstitialEvent"}, {{"interstitialEvent", {"*"}}});
+    CHECK(_reportingEnvironment);
+    CHECK(_reportingEnvironment->Start());
+  }
+
   // `appConfigurationForTestCase` is called during [super setUp], and
   // depends on the URLs initialized above.
   [super setUp];
@@ -204,9 +254,14 @@
   // Ensure that the real-time Safe Browsing opt-in starts in the default
   // (opted-out) state.
   [ChromeEarlGrey setURLKeyedAnonymizedDataCollectionEnabled:NO];
+
+  // Set up histograms for testing enterprise reporting.
+  GREYAssertErrorNil([MetricsAppInterface setupHistogramTester]);
 }
 
 - (void)tearDownHelper {
+  GREYAssertErrorNil([MetricsAppInterface releaseHistogramTester]);
+
   // Ensure that Safe Browsing is reset to its original value.
   [ChromeEarlGrey setBoolValue:_safeBrowsingEnabledPrefDefault
                    forUserPref:prefs::kSafeBrowsingEnabled];
@@ -243,6 +298,60 @@
                          selectorDescription:description];
 }
 
+- (BOOL)isRunningEnterpriseReportingTest {
+  return
+      [self
+          isRunningTest:@selector(testProceedingPastPhishingWarningReported)] ||
+      [self isRunningTest:@selector(testProceedingPastMalwareWarningReported)];
+}
+
+- (void)waitForEnterpriseReports:(int)count {
+  // Use metrics to detect that the report upload completed. This is the best
+  // known way to wait because a task environment isn't available here for the
+  // server's request handler to post to.
+  GREYAssertTrue(
+      base::test::ios::WaitUntilConditionOrTimeout(
+          kReportUploadTimeout,
+          ^{
+            NSError* error = [MetricsAppInterface
+                expectTotalCount:count
+                    forHistogram:@"Enterprise.ReportingEventUploadSuccess"];
+            return error == nil;
+          }),
+      @"Timed out uploading security event.");
+  GREYAssertErrorNil([MetricsAppInterface
+      expectTotalCount:0
+          forHistogram:@"Enterprise.ReportingEventUploadFailure"]);
+}
+
+- (void)assertInterstitialEvent:(const UploadEventsRequest&)request
+                            url:(const GURL&)url
+                 clickedThrough:(BOOL)clickedThrough
+                    eventResult:(EventResult)eventResult
+                         reason:(InterstitialReason)reason {
+  GREYAssertEqual(std::string("iOS"), request.device().os_platform(),
+                  @"Wrong OS platform in report.");
+  GREYAssertEqual(1, request.events_size(), @"Wrong number of events.");
+
+  GREYAssertTrue(request.events(0).has_interstitial_event(),
+                 @"Wrong event type.");
+  const SafeBrowsingInterstitialEvent& event =
+      request.events(0).interstitial_event();
+  GREYAssertEqual(url, GURL(event.url()), @"Wrong interstitial event URL.");
+  if (clickedThrough) {
+    GREYAssertTrue(
+        event.clicked_through(),
+        @"Interstitial event unexpectedly not marked as clicked through.");
+  } else {
+    GREYAssertFalse(
+        event.clicked_through(),
+        @"Interstitial event unexpectedly marked as clicked through.");
+  }
+  GREYAssertEqual(eventResult, event.event_result(),
+                  @"Wrong interstitial event result.");
+  GREYAssertEqual(reason, event.reason(), @"Wrong interstitial event reason.");
+}
+
 #pragma mark - Tests
 // Tests that safe pages are not blocked.
 - (void)testSafePage {
@@ -326,6 +435,50 @@
                                                     IDS_SAFEBROWSING_HEADING)];
 }
 
+// Tests expanding the details on a phishing warning, and proceeding past the
+// warning is reported to an enterprise connector.
+- (void)testProceedingPastPhishingWarningReported {
+  [ChromeEarlGrey loadURL:_safeURL1];
+  [ChromeEarlGrey waitForWebStateContainingText:_safeContent1];
+
+  // Load the phishing page and verify a warning is shown.
+  [ChromeEarlGrey loadURL:_phishingURL];
+  [ChromeEarlGrey waitForWebStateContainingText:l10n_util::GetStringUTF8(
+                                                    IDS_SAFEBROWSING_HEADING)];
+
+  // Tap on the Details button and verify that warning details are shown.
+  [ChromeEarlGrey tapWebStateElementWithID:@"details-button"];
+  [ChromeEarlGrey waitForWebStateContainingText:kPhishingWarningDetails];
+
+  // Verify the server is notified the browser showed a warning.
+  [self waitForEnterpriseReports:1];
+  std::vector<UploadEventsRequest> requests =
+      _reportingEnvironment->reporting_server()->GetUploadedReports();
+  GREYAssertEqual(1U, requests.size(), @"Wrong number of reports.");
+  [self assertInterstitialEvent:requests[0]
+                            url:_phishingURL
+                 clickedThrough:NO
+                    eventResult:EventResult::EVENT_RESULT_WARNED
+                         reason:SafeBrowsingInterstitialEvent::
+                                    SOCIAL_ENGINEERING];
+
+  // Tap on the link to proceed to the unsafe page, and verify that this page is
+  // loaded.
+  [ChromeEarlGrey tapWebStateElementWithID:@"proceed-link"];
+  [ChromeEarlGrey waitForWebStateContainingText:_phishingContent];
+
+  // Verify the server is notified the end user bypassed the warning.
+  [self waitForEnterpriseReports:2];
+  requests = _reportingEnvironment->reporting_server()->GetUploadedReports();
+  GREYAssertEqual(2U, requests.size(), @"Wrong number of reports.");
+  [self assertInterstitialEvent:requests[1]
+                            url:_phishingURL
+                 clickedThrough:YES
+                    eventResult:EventResult::EVENT_RESULT_BYPASSED
+                         reason:SafeBrowsingInterstitialEvent::
+                                    SOCIAL_ENGINEERING];
+}
+
 // Tests that a malware page is blocked, and the "Back to safety" button on the
 // warning page works as expected.
 - (void)testMalwarePage {
@@ -429,6 +582,55 @@
   [ChromeEarlGrey waitForWebStateContainingText:_malwareContent];
 }
 
+// Tests expanding the details on a malware warning, and proceeding past the
+// warning is reported to an enterprise connector.
+- (void)testProceedingPastMalwareWarningReported {
+  [ChromeEarlGrey loadURL:_safeURL1];
+  [ChromeEarlGrey waitForWebStateContainingText:_safeContent1];
+
+  // Load the malware page and verify a warning is shown.
+  [ChromeEarlGrey loadURL:_malwareURL];
+  [ChromeEarlGrey waitForWebStateContainingText:l10n_util::GetStringUTF8(
+                                                    IDS_SAFEBROWSING_HEADING)];
+
+  // Tap on the Details button and verify that warning details are shown.
+  [ChromeEarlGrey tapWebStateElementWithID:@"details-button"];
+  [ChromeEarlGrey waitForWebStateContainingText:kMalwareWarningDetails];
+
+  // Verify the server is notified the browser showed a warning.
+  [self waitForEnterpriseReports:1];
+  std::vector<UploadEventsRequest> requests =
+      _reportingEnvironment->reporting_server()->GetUploadedReports();
+  GREYAssertEqual(1U, requests.size(), @"Wrong number of reports.");
+  [self assertInterstitialEvent:requests[0]
+                            url:_malwareURL
+                 clickedThrough:NO
+                    eventResult:EventResult::EVENT_RESULT_WARNED
+                         reason:SafeBrowsingInterstitialEvent::MALWARE];
+
+  if (@available(iOS 15.1, *)) {
+  } else {
+    // Workaround https://bugs.webkit.org/show_bug.cgi?id=226323, which can
+    // break loading the unsafe page below.
+    return;
+  }
+
+  // Tap on the link to proceed to the unsafe page, and verify that this page is
+  // loaded.
+  [ChromeEarlGrey tapWebStateElementWithID:@"proceed-link"];
+  [ChromeEarlGrey waitForWebStateFrameContainingText:_malwareContent];
+
+  // Verify the server is notified the end user bypassed the warning.
+  [self waitForEnterpriseReports:2];
+  requests = _reportingEnvironment->reporting_server()->GetUploadedReports();
+  GREYAssertEqual(2U, requests.size(), @"Wrong number of reports.");
+  [self assertInterstitialEvent:requests[1]
+                            url:_malwareURL
+                 clickedThrough:YES
+                    eventResult:EventResult::EVENT_RESULT_BYPASSED
+                         reason:SafeBrowsingInterstitialEvent::MALWARE];
+}
+
 // Tests that disabling and re-enabling Safe Browsing works as expected.
 - (void)testDisableAndEnableSafeBrowsing {
   // Disable Safe Browsing and verify that unsafe content is shown.
diff --git a/ios_internal b/ios_internal
index dd18c24..e82bd56 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit dd18c245f49db25fee815e2386da4e9689d1b8d7
+Subproject commit e82bd56d69ca3919d547f78ca8f417e4b8ef7ffc
diff --git a/media/audio/audio_device_description.cc b/media/audio/audio_device_description.cc
index 4bd6285..eb64146 100644
--- a/media/audio/audio_device_description.cc
+++ b/media/audio/audio_device_description.cc
@@ -9,6 +9,7 @@
 #include "base/functional/bind.h"
 #include "base/notreached.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 #include "build/chromecast_buildflags.h"
 #include "media/base/localized_strings.h"
@@ -55,19 +56,19 @@
 }  // namespace
 
 // static
-bool AudioDeviceDescription::IsDefaultDevice(const std::string& device_id) {
+bool AudioDeviceDescription::IsDefaultDevice(std::string_view device_id) {
   return device_id.empty() ||
          device_id == AudioDeviceDescription::kDefaultDeviceId;
 }
 
 // static
 bool AudioDeviceDescription::IsCommunicationsDevice(
-    const std::string& device_id) {
+    std::string_view device_id) {
   return device_id == AudioDeviceDescription::kCommunicationsDeviceId;
 }
 
 // static
-bool AudioDeviceDescription::IsLoopbackDevice(const std::string& device_id) {
+bool AudioDeviceDescription::IsLoopbackDevice(std::string_view device_id) {
   return device_id == kLoopbackInputDeviceId ||
          device_id == kLoopbackWithMuteDeviceId ||
          device_id == kLoopbackWithoutChromeId ||
@@ -76,14 +77,14 @@
 
 // static
 bool AudioDeviceDescription::IsApplicationLoopbackDevice(
-    const std::string& device_id) {
+    std::string_view device_id) {
   return base::StartsWith(device_id, kApplicationLoopbackDeviceId);
 }
 
 // static
 bool AudioDeviceDescription::UseSessionIdToSelectDevice(
     const base::UnguessableToken& session_id,
-    const std::string& device_id) {
+    std::string_view device_id) {
   return !session_id.is_empty() && device_id.empty();
 }
 
@@ -107,22 +108,26 @@
 
 // static
 std::string AudioDeviceDescription::GetDefaultDeviceName(
-    const std::string& real_device_name) {
-  if (real_device_name.empty())
+    std::string_view real_device_name) {
+  if (real_device_name.empty()) {
     return GetDefaultDeviceName();
+  }
   // TODO(guidou): Put the names together in a localized manner.
   // http://crbug.com/788767
-  return GetDefaultDeviceName() + " - " + real_device_name;
+  return base::StringPrintf("%s - %s", GetDefaultDeviceName(),
+                            real_device_name);
 }
 
 // static
 std::string AudioDeviceDescription::GetCommunicationsDeviceName(
-    const std::string& real_device_name) {
-  if (real_device_name.empty())
+    std::string_view real_device_name) {
+  if (real_device_name.empty()) {
     return GetCommunicationsDeviceName();
+  }
   // TODO(guidou): Put the names together in a localized manner.
   // http://crbug.com/788767
-  return GetCommunicationsDeviceName() + " - " + real_device_name;
+  return base::StringPrintf("%s - %s", GetCommunicationsDeviceName(),
+                            real_device_name);
 }
 
 // static
@@ -162,9 +167,9 @@
                                                std::string group_id,
                                                bool is_system_default,
                                                bool is_communications_device)
-    : device_name(device_name),
-      unique_id(unique_id),
-      group_id(group_id),
+    : device_name(std::move(device_name)),
+      unique_id(std::move(unique_id)),
+      group_id(std::move(group_id)),
       is_system_default(is_system_default),
       is_communications_device(is_communications_device) {}
 
diff --git a/media/audio/audio_device_description.h b/media/audio/audio_device_description.h
index d0419cd..eeb763d4 100644
--- a/media/audio/audio_device_description.h
+++ b/media/audio/audio_device_description.h
@@ -47,22 +47,22 @@
 
   // TODO(b/338470954): Rename to IsVirtualDefaultDevice(...)
   // Returns true if |device_id| represents the virtual default device.
-  static bool IsDefaultDevice(const std::string& device_id);
+  static bool IsDefaultDevice(std::string_view device_id);
 
   // TODO(b/338470954): Rename to IsVirtualCommunicationsDevice(...)
   // Returns true if |device_id| represents the virtual communications device.
-  static bool IsCommunicationsDevice(const std::string& device_id);
+  static bool IsCommunicationsDevice(std::string_view device_id);
 
   // Returns true if |device_id| represents a loopback audio capture device.
   // Note that this will not work if |device_id| is hashed, which may be the
   // case in the Renderer.
-  static bool IsLoopbackDevice(const std::string& device_id);
+  static bool IsLoopbackDevice(std::string_view device_id);
 
   // Returns true if |device_id| represents an application loopback audio
   // capture device.
   // Note that this will not work if |device_id| is hashed, which is the case in
   // the Renderer.
-  static bool IsApplicationLoopbackDevice(const std::string& device_id);
+  static bool IsApplicationLoopbackDevice(std::string_view device_id);
 
   // If |device_id| is not empty, |session_id| should be ignored and the output
   // device should be selected basing on |device_id|.
@@ -71,7 +71,7 @@
   // be used.
   static bool UseSessionIdToSelectDevice(
       const base::UnguessableToken& session_id,
-      const std::string& device_id);
+      std::string_view device_id);
 
   // The functions dealing with localization are not reliable in the audio
   // service, and should be avoided there.
@@ -80,7 +80,7 @@
 
   // Returns a localized version of name of the generic "default" device that
   // includes the given |real_device_name|.
-  static std::string GetDefaultDeviceName(const std::string& real_device_name);
+  static std::string GetDefaultDeviceName(std::string_view real_device_name);
 
   // Returns the localized name of the generic default communications device.
   // This device is not supported on all platforms.
@@ -89,7 +89,7 @@
   // Returns a localized version of name of the generic communications device
   // that includes the given |real_device_name|.
   static std::string GetCommunicationsDeviceName(
-      const std::string& real_device_name);
+      std::string_view real_device_name);
 
   // This prepends localized "Default" or "Communications" strings to
   // default and communications device names in |device_descriptions|, and
diff --git a/media/audio/audio_device_description_unittest.cc b/media/audio/audio_device_description_unittest.cc
index 235d83d1..f502703f 100644
--- a/media/audio/audio_device_description_unittest.cc
+++ b/media/audio/audio_device_description_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "media/audio/application_loopback_device_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
+
 namespace media {
 
 TEST(AudioDeviceDescriptionTest, LocalizedGenericLabelLeftUnchanged) {
@@ -41,6 +42,58 @@
   EXPECT_EQ(device_descriptions[3].device_name, "AirPods Stereo");
 }
 
+TEST(AudioDeviceDescriptionTest, GetDefaultDeviceName) {
+  auto default_name = AudioDeviceDescription::GetDefaultDeviceName();
+
+  // Passing an empty string should return `default_name`.
+  EXPECT_EQ(AudioDeviceDescription::GetDefaultDeviceName(std::string()),
+            default_name);
+  EXPECT_EQ(AudioDeviceDescription::GetDefaultDeviceName(""), default_name);
+
+  std::string real_device_name = "Real Device Name";
+
+  // `real_device_name` should be appended.
+  EXPECT_EQ(AudioDeviceDescription::GetDefaultDeviceName(real_device_name),
+            default_name + " - " + real_device_name);
+
+  // This should contain "Real Device", without a null-terminator.
+  std::string_view non_null_terminated_name =
+      std::string_view(real_device_name).substr(0, 11);
+
+  // Verify we properly handle a non-null terminated string_view.
+  EXPECT_EQ(
+      AudioDeviceDescription::GetDefaultDeviceName(non_null_terminated_name),
+      default_name + " - " + std::string(non_null_terminated_name));
+}
+
+#if BUILDFLAG(IS_WIN)
+TEST(AudioDeviceDescriptionTest, GetCommunicationsDeviceName) {
+  auto communication_name =
+      AudioDeviceDescription::GetCommunicationsDeviceName();
+
+  // Passing an empty string should return `communication_name`.
+  EXPECT_EQ(AudioDeviceDescription::GetCommunicationsDeviceName(std::string()),
+            communication_name);
+  EXPECT_EQ(AudioDeviceDescription::GetCommunicationsDeviceName(""),
+            communication_name);
+
+  std::string real_device_name = "Real Device Name";
+
+  // `real_device_name` should be appended.
+  EXPECT_EQ(
+      AudioDeviceDescription::GetCommunicationsDeviceName(real_device_name),
+      communication_name + " - " + real_device_name);
+
+  std::string_view non_null_terminated_name =
+      std::string_view(real_device_name).substr(0, 11);
+
+  // Verify we properly handle a non-null terminated string_view.
+  EXPECT_EQ(AudioDeviceDescription::GetCommunicationsDeviceName(
+                non_null_terminated_name),
+            communication_name + " - " + std::string(non_null_terminated_name));
+}
+#endif
+
 TEST(AudioDeviceDescriptionTest, IsLoopbackDevice) {
   EXPECT_TRUE(AudioDeviceDescription::IsLoopbackDevice(
       AudioDeviceDescription::kLoopbackInputDeviceId));
diff --git a/mojo/public/mojom/base/BUILD.gn b/mojo/public/mojom/base/BUILD.gn
index 476baa0..9770d52 100644
--- a/mojo/public/mojom/base/BUILD.gn
+++ b/mojo/public/mojom/base/BUILD.gn
@@ -16,6 +16,7 @@
     "big_string.mojom",
     "binder.mojom",
     "byte_string.mojom",
+    "error.mojom",
     "file.mojom",
     "file_error.mojom",
     "file_info.mojom",
diff --git a/mojo/public/mojom/base/error.mojom b/mojo/public/mojom/base/error.mojom
new file mode 100644
index 0000000..93761bb
--- /dev/null
+++ b/mojo/public/mojom/base/error.mojom
@@ -0,0 +1,56 @@
+// 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.
+
+module mojo_base.mojom;
+
+// A copy of absl's Status Code. It is copied here to prevent infecting
+// users with absl where Errors are used. kOk is intentionally omitted,
+// because it should never be used.
+// For additional clarity around how each code should be used, please
+// refer to: https://abseil.io/docs/cpp/guides/status-codes
+enum Code {
+  // The request was cancelled, typically by the caller.
+  kCancelled = 1,
+  // There is no way to determine a more specific error code.
+  kUnknown = 2,
+  // The request parameters would never work.
+  kInvalidArgument = 3,
+  // The operation did not complete within the specified deadline.
+  kDeadlineExceeded = 4,
+  // The requested entity does not exist.
+  kNotFound = 5,
+  // The entity being created already exists.
+  kAlreadyExists = 6,
+  // The caller does not have permission to execute the operation.
+  kPermissionDenied = 7,
+  // Some infrastructure resource is exhausted (quota, server capacity, etc).
+  kResourceExhausted = 8,
+  // The system is not in the required state for the operation.
+  kFailedPrecondition = 9,
+  // The operation was aborted, typically due to a concurrency issue like
+  // sequencer check failures, transaction aborts, etc.
+  kAborted = 10,
+  // The client has iterated too far, and should stop.
+  kOutOfRange = 11,
+  // There is no implementation for the requested operation.
+  kUnimplemented = 12,
+  // A serious internal invariant is broken (i.e. worthy of a bug or
+  // outage report).
+  kInternal = 13,
+  // There was a transient error.
+  kUnavailable = 14,
+  // Unrecoverable data loss or corruption.
+  kDataLoss = 15,
+  // The caller’s identity cannot be verified.
+  kUnauthenticated = 16,
+};
+
+// Represents an API error.
+struct Error {
+  // The error code. This can be used to determine whether this is a
+  // client or service error.
+  Code code;
+  // A human readable error string intended for developers.
+  string message;
+};
diff --git a/net/cert/internal/trust_store_chrome.h b/net/cert/internal/trust_store_chrome.h
index e0e7553..cade929f 100644
--- a/net/cert/internal/trust_store_chrome.h
+++ b/net/cert/internal/trust_store_chrome.h
@@ -42,6 +42,12 @@
   // True if the certificate verifier should enforce X.509 constraints encoded
   // in the certificate.
   bool enforce_anchor_constraints;
+  // If non-empty, the ASCII representation of the Trust Anchor ID
+  // (https://tlswg.org/tls-trust-anchor-ids/draft-ietf-tls-trust-anchor-ids.html)
+  // associated with this anchor -- that is, a relative object identifier in
+  // dotted decimal form (e.g., "1234.1"). If empty, this anchor has no
+  // associated Trust Anchor ID.
+  std::string trust_anchor_id;
 };
 
 struct NET_EXPORT ChromeRootCertConstraints {
diff --git a/net/cert/internal/trust_store_chrome_unittest.cc b/net/cert/internal/trust_store_chrome_unittest.cc
index ec92d9a..9b54f4c 100644
--- a/net/cert/internal/trust_store_chrome_unittest.cc
+++ b/net/cert/internal/trust_store_chrome_unittest.cc
@@ -45,6 +45,21 @@
   return builder->GetX509Certificate();
 }
 
+std::shared_ptr<const bssl::ParsedCertificate>
+FindParsedCertificateInCertificateList(const std::string& hash,
+                                       CertificateList certs) {
+  for (const auto& cert : certs) {
+    std::shared_ptr<const bssl::ParsedCertificate> parsed =
+        ToParsedCertificate(*cert);
+    std::string sha256_hex = base::ToLowerASCII(
+        base::HexEncode(crypto::SHA256Hash(parsed->der_cert())));
+    if (sha256_hex == hash) {
+      return parsed;
+    }
+  }
+  return nullptr;
+}
+
 TEST(TrustStoreChromeTestNoFixture, ContainsCert) {
   std::unique_ptr<TrustStoreChrome> trust_store_chrome =
       TrustStoreChrome::CreateTrustStoreForTesting(
@@ -97,14 +112,17 @@
           base::span(kEutlRootCertList),
           /*version=*/1);
 
-  // Check that the single certificate in test_additional.certs is included in
+  const std::string kEUTLCertHash =
+      "f7c7e28fb5e79f314aaac6bbba932f15e1a72069f435d4c9e707f93ca1482ee3";
+
+  // Check that the EUTL certificate in test_additional.certs is included in
   // the EUTL trust store, but not trusted for TLS connection establishment.
   CertificateList certs = CreateCertificateListFromFile(
       GetTestNetDataDirectory().AppendASCII("ssl/chrome_root_store"),
       "test_additional.certs", X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
-  ASSERT_EQ(certs.size(), 1u);
   std::shared_ptr<const bssl::ParsedCertificate> parsed =
-      ToParsedCertificate(*certs[0]);
+      FindParsedCertificateInCertificateList(kEUTLCertHash, certs);
+  ASSERT_TRUE(parsed);
 
   bssl::CertificateTrust eutl_trust =
       trust_store_chrome->eutl_trust_store()->GetTrust(parsed.get());
@@ -212,23 +230,6 @@
       trust_store_chrome->GetConstraintsForCert(other_parsed.get()).empty());
 }
 
-namespace {
-std::shared_ptr<const bssl::ParsedCertificate>
-FindParsedCertificateInCertificateList(const std::string& hash,
-                                       CertificateList certs) {
-  for (const auto& cert : certs) {
-    std::shared_ptr<const bssl::ParsedCertificate> parsed =
-        ToParsedCertificate(*cert);
-    std::string sha256_hex = base::ToLowerASCII(
-        base::HexEncode(crypto::SHA256Hash(parsed->der_cert())));
-    if (sha256_hex == hash) {
-      return parsed;
-    }
-  }
-  return nullptr;
-}
-}  // namespace
-
 TEST(TrustStoreChromeTestNoFixture, EnforceAnchorExpiryAndConstraints) {
   std::unique_ptr<TrustStoreChrome> trust_store_chrome =
       TrustStoreChrome::CreateTrustStoreForTesting(
@@ -294,6 +295,117 @@
   }
 }
 
+// Tests that, for a compiled-in root store, certificates in |additional_certs|
+// are compiled in as trust anchors when indicated, with associated trust anchor
+// IDs when present, with |enforce_anchor_expiry| and
+// |enforce_anchor_constraints| flags enforced.
+TEST(TrustStoreChromeTestNoFixture,
+     LoadCompiledTrustAnchorsWithTrustAnchorIDs) {
+  std::unique_ptr<TrustStoreChrome> trust_store_chrome =
+      TrustStoreChrome::CreateTrustStoreForTesting(
+          base::span<const ChromeRootCertInfo>(kChromeRootCertList),
+          base::span(kEutlRootCertList),
+          /*version=*/1);
+
+  // Map of hex-encoded SHA-256 hashes of |trust_anchors| certificates that have
+  // associated Trust Anchor IDs to their expected CertificateTrust setting.
+  std::map<std::string, bssl::CertificateTrust>
+      expected_trust_anchor_trust_by_hash = {
+          {"687fa451382278fff0c8b11f8d43d576671c6eb2bceab413fb83d965d06d2ff2",
+           bssl::CertificateTrust::ForTrustAnchor()
+               .WithEnforceAnchorExpiry()
+               .WithEnforceAnchorConstraints()},
+      };
+
+  // Map of hex-encoded SHA-256 hashes of |additional_certs| certificates that
+  // are marked as trust anchors, and have associated Trust Anchor IDs, to their
+  // expected CertificateTrust setting.
+  std::map<std::string, bssl::CertificateTrust>
+      expected_additional_certificate_trust_by_hash = {
+          {"72a34ac2b424aed3f6b0b04755b88cc027dccc806fddb22b4cd7c47773973ec0",
+           bssl::CertificateTrust::ForTrustAnchor().WithEnforceAnchorExpiry()},
+          {"e6fe22bf45e4f0d3b85c59e02c0f495418e1eb8d3210f788d48cd5e1cb547cd4",
+           bssl::CertificateTrust::ForTrustAnchor()
+               .WithEnforceAnchorConstraints()},
+          {"973a41276ffd01e027a2aad49e34c37846d3e976ff6a620b6712e33832041aa6",
+           bssl::CertificateTrust::ForTrustAnchor()
+               .WithEnforceAnchorExpiry()
+               .WithEnforceAnchorConstraints()}};
+
+  CertificateList trust_anchor_certs = CreateCertificateListFromFile(
+      GetTestNetDataDirectory().AppendASCII("ssl/chrome_root_store"),
+      "test_store.certs", X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
+
+  CertificateList additional_certs = CreateCertificateListFromFile(
+      GetTestNetDataDirectory().AppendASCII("ssl/chrome_root_store"),
+      "test_additional.certs", X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
+
+  size_t certs_with_tai = 0;
+  for (const auto& cert : kChromeRootCertList) {
+    if (cert.trust_anchor_id.empty()) {
+      continue;
+    }
+
+    certs_with_tai++;
+    std::string hash = base::ToLowerASCII(
+        base::HexEncode(crypto::SHA256Hash(cert.root_cert_der)));
+    bool is_additional_cert =
+        expected_additional_certificate_trust_by_hash.contains(hash);
+    bssl::CertificateTrust expected_trust =
+        is_additional_cert ? expected_additional_certificate_trust_by_hash[hash]
+                           : expected_trust_anchor_trust_by_hash[hash];
+
+    std::shared_ptr<const bssl::ParsedCertificate> parsed_cert =
+        is_additional_cert
+            ? FindParsedCertificateInCertificateList(hash, additional_certs)
+            : FindParsedCertificateInCertificateList(hash, trust_anchor_certs);
+    ASSERT_TRUE(parsed_cert);
+
+    // Check that the certificate is present in the trust store as an anchor,
+    // with the expected settings for expiry and X.509 constraints.
+    // TODO(crbug.com/414630735): check that the correct Trust Anchor ID is
+    // stored in TrustStoreChrome, once implemented. (Right now TrustStoreChrome
+    // throws out Trust Anchor IDs and doesn't keep them around.)
+    bssl::CertificateTrust trust =
+        trust_store_chrome->GetTrust(parsed_cert.get());
+    EXPECT_TRUE(trust.IsTrustAnchor());
+    EXPECT_EQ(trust.enforce_anchor_expiry,
+              expected_trust.enforce_anchor_expiry);
+    EXPECT_EQ(trust.enforce_anchor_constraints,
+              expected_trust.enforce_anchor_constraints);
+  }
+  EXPECT_EQ(4u, certs_with_tai);
+}
+
+// Tests that, for a compiled-in root store, certificates in |additional_certs|
+// are compiled in as trust anchors when indicated, even if they have no
+// associated Trust Anchor ID.
+TEST(TrustStoreChromeTestNoFixture,
+     LoadCompiledTrustAnchorsWithNoTrustAnchorID) {
+  std::unique_ptr<TrustStoreChrome> trust_store_chrome =
+      TrustStoreChrome::CreateTrustStoreForTesting(
+          base::span<const ChromeRootCertInfo>(kChromeRootCertList),
+          base::span(kEutlRootCertList),
+          /*version=*/1);
+
+  const std::string kAdditionalCertTrustAnchorWithNoTAIHash =
+      "19400be5b7a31fb733917700789d2f0a2471c0c9d506c0e504c06c16d7cb17c0";
+
+  CertificateList additional_certs = CreateCertificateListFromFile(
+      GetTestNetDataDirectory().AppendASCII("ssl/chrome_root_store"),
+      "test_additional.certs", X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
+
+  std::shared_ptr<const bssl::ParsedCertificate> parsed_cert =
+      FindParsedCertificateInCertificateList(
+          kAdditionalCertTrustAnchorWithNoTAIHash, additional_certs);
+  ASSERT_TRUE(parsed_cert);
+  bssl::CertificateTrust trust =
+      trust_store_chrome->GetTrust(parsed_cert.get());
+  EXPECT_TRUE(trust.IsTrustAnchor());
+  EXPECT_TRUE(trust.enforce_anchor_expiry);
+  EXPECT_TRUE(trust.enforce_anchor_constraints);
+}
+
 TEST(TrustStoreChromeTestNoFixture, OverrideConstraints) {
   // Root1: has no constraints and no override constraints
   // Root2: has constraints and no override constraints
diff --git a/net/cert/root_store.proto b/net/cert/root_store.proto
index 1b46fa3..49bd361 100644
--- a/net/cert/root_store.proto
+++ b/net/cert/root_store.proto
@@ -81,10 +81,18 @@
   // TrustAnchor using the constraints expressed in the corresponding
   // certificate.
   optional bool enforce_anchor_constraints = 9;
+
+  // If true, indicates that this certificate is a trust anchor for TLS
+  // connections.
+  optional bool tls_trust_anchor = 10;
 }
 
 // Message storing a complete Chrome Root Store.
 message RootStore {
+  // Certificates in this list are expected to have |tls_trust_anchor| unset,
+  // because all |trust_anchors| are TLS trust anchors. This field exists as a
+  // separate, TLS-trust-anchor-only list from |additional_certs| just for
+  // historical reasons.
   repeated TrustAnchor trust_anchors = 1;
 
   // Major version # of the Chrome Root Store. It is assumed that if
diff --git a/net/data/ssl/chrome_root_store/test_additional.certs b/net/data/ssl/chrome_root_store/test_additional.certs
index a448747..6ff8f0f 100644
--- a/net/data/ssl/chrome_root_store/test_additional.certs
+++ b/net/data/ssl/chrome_root_store/test_additional.certs
@@ -39,3 +39,178 @@
 E0NKnqshwv10EWG5IKFRsq0LYWjogihvzFlAmXftt3G12gXFAwndw2Hed8HXBfUj
 8WjjEBCliiD/N9P40C9JEZovvAkkL07h
 -----END CERTIFICATE-----
+
+SHA-256 hash: 72a34ac2b424aed3f6b0b04755b88cc027dccc806fddb22b4cd7c47773973ec0
+Subject: C=GB, ST=Greater Manchester, L=Salford, O=Sectigo Limited, CN=Sectigo RSA Organization Validation Secure Server CA
+Issuer: C=US, ST=New Jersey, L=Jersey City, O=The USERTRUST Network, CN=USERTrust RSA Certification Authority
+-----BEGIN CERTIFICATE-----
+MIIGGTCCBAGgAwIBAgIQE31TnKp8MamkM3AZaIR6jTANBgkqhkiG9w0BAQwFADCB
+iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
+cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
+BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx
+MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBlTELMAkGA1UEBhMCR0IxGzAZBgNV
+BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE
+ChMPU2VjdGlnbyBMaW1pdGVkMT0wOwYDVQQDEzRTZWN0aWdvIFJTQSBPcmdhbml6
+YXRpb24gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAnJMCRkVKUkiS/FeN+S3qU76zLNXYqKXsW2kDwB0Q
+9lkz3v4HSKjojHpnSvH1jcM3ZtAykffEnQRgxLVK4oOLp64m1F06XvjRFnG7ir1x
+on3IzqJgJLBSoDpFUd54k2xiYPHkVpy3O/c8Vdjf1XoxfDV/ElFw4Sy+BKzL+k/h
+fGVqwECn2XylY4QZ4ffK76q06Fha2ZnjJt+OErK43DOyNtoUHZZYQkBuCyKFHFEi
+rsTIBkVtkuZntxkj5Ng2a4XQf8dS48+wdQHgibSov4o2TqPgbOuEQc6lL0giE5dQ
+YkUeCaXMn2xXcEAG2yDoG9bzk4unMp63RBUJ16/9fAEc2wIDAQABo4IBbjCCAWow
+HwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFBfZ1iUn
+Z/kxwklD2TA2RIxsqU/rMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/
+AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYG
+BFUdIAAwCAYGZ4EMAQICMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNl
+cnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNy
+bDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRy
+dXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZ
+aHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAThNA
+lsnD5m5bwOO69Bfhrgkfyb/LDCUW8nNTs3Yat6tIBtbNAHwgRUNFbBZaGxNh10m6
+pAKkrOjOzi3JKnSj3N6uq9BoNviRrzwB93fVC8+Xq+uH5xWo+jBaYXEgscBDxLmP
+bYox6xU2JPti1Qucj+lmveZhUZeTth2HvbC1bP6mESkGYTQxMD0gJ3NR0N6Fg9N3
+OSBGltqnxloWJ4Wyz04PToxcvr44APhL+XJ71PJ616IphdAEutNCLFGIUi7RPSRn
+R+xVzBv0yjTqJsHe3cQhifa6ezIejpZehEU4z4CqN2mLYBd0FUiRnG3wTqN3yhsc
+SPr5z0noX0+FCuKPkBurcEya67emP7SsXaRfz+bYipaQ908mgWB2XQ8kd5GzKjGf
+FlqyXYwcKapInI5v03hAcNt37N3j0VcFcC3mSZiIBYRiBXBWdoY5TtMibx3+bfEO
+s2LEPMvAhblhHrrhFYBZlAyuBbuMf1a+HNJav5fyakywxnB2sJCNwQs2uRHY1ihc
+6k/+JLcYCpsM0MF8XPtpvcyiTcaQvKZN8rG61ppnW5YCUtCC+cQKXA0o4D/I+pWV
+idWkvklsQLI+qGu41SWyxP7x09fn1txDAXYw+zuLXfdKiXyaNb78yvBXAfCNP6CH
+MntHWpdLgtJmwsQt6j8k9Kf5qLnjatkYYaA7jBU=
+-----END CERTIFICATE-----
+
+SHA-256 hash: e6fe22bf45e4f0d3b85c59e02c0f495418e1eb8d3210f788d48cd5e1cb547cd4
+Subject: C=US, O=Google Trust Services, CN=WR2
+Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R1
+-----BEGIN CERTIFICATE-----
+MIIFCzCCAvOgAwIBAgIQf/AFoHxM3tEArZ1mpRB7mDANBgkqhkiG9w0BAQsFADBH
+MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
+QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjMxMjEzMDkwMDAwWhcNMjkwMjIw
+MTQwMDAwWjA7MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNl
+cnZpY2VzMQwwCgYDVQQDEwNXUjIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCp/5x/RR5wqFOfytnlDd5GV1d9vI+aWqxG8YSau5HbyfsvAfuSCQAWXqAc
++MGr+XgvSszYhaLYWTwO0xj7sfUkDSbutltkdnwUxy96zqhMt/TZCPzfhyM1IKji
+aeKMTj+xWfpgoh6zySBTGYLKNlNtYE3pAJH8do1cCA8Kwtzxc2vFE24KT3rC8gIc
+LrRjg9ox9i11MLL7q8Ju26nADrn5Z9TDJVd06wW06Y613ijNzHoU5HEDy01hLmFX
+xRmpC5iEGuh5KdmyjS//V2pm4M6rlagplmNwEmceOuHbsCFx13ye/aoXbv4r+zgX
+FNFmp6+atXDMyGOBOozAKql2N87jAgMBAAGjgf4wgfswDgYDVR0PAQH/BAQDAgGG
+MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/
+AgEAMB0GA1UdDgQWBBTeGx7teRXUPjckwyG77DQ5bUKyMDAfBgNVHSMEGDAWgBTk
+rysmcRorSCeFL1JmLO/wiRNxPjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAKG
+GGh0dHA6Ly9pLnBraS5nb29nL3IxLmNydDArBgNVHR8EJDAiMCCgHqAchhpodHRw
+Oi8vYy5wa2kuZ29vZy9yL3IxLmNybDATBgNVHSAEDDAKMAgGBmeBDAECATANBgkq
+hkiG9w0BAQsFAAOCAgEARXWL5R87RBOWGqtY8TXJbz3S0DNKhjO6V1FP7sQ02hYS
+TL8Tnw3UVOlIecAwPJQl8hr0ujKUtjNyC4XuCRElNJThb0Lbgpt7fyqaqf9/qdLe
+SiDLs/sDA7j4BwXaWZIvGEaYzq9yviQmsR4ATb0IrZNBRAq7x9UBhb+TV+PfdBJT
+DhEl05vc3ssnbrPCuTNiOcLgNeFbpwkuGcuRKnZc8d/KI4RApW//mkHgte8y0YWu
+ryUJ8GLFbsLIbjL9uNrizkqRSvOFVU6xddZIMy9vhNkSXJ/UcZhjJY1pXAprffJB
+vei7j+Qi151lRehMCofa6WBmiA4fx+FOVsV2/7R6V2nyAiIJJkEd2nSi5SnzxJrl
+Xdaqev3htytmOPvoKWa676ATL/hzfvDaQBEcXd2Ppvy+275W+DKcH0FBbX62xevG
+iza3F4ydzxl6NJ8hk8R+dDXSqv1MbRT1ybB5W0k8878XSOjvmiYTDIfyc9acxVJr
+Y/cykHipa+te1pOhv7wYPYtZ9orGBV5SGOJm4NrB3K1aJar0RfzxC3ikr7Dyc6Qw
+qDTBU39CluVIQeuQRgwG3MuSxl7zRERDRilGoKb8uY45JzmxWuKxrfwT/478JuHU
+/oTxUFqOl2stKnn7QGTq8z29W+GgBLCXSBxC9epaHM0myFH/FJlniXJfHeytWt0=
+-----END CERTIFICATE-----
+
+SHA-256 hash: 973a41276ffd01e027a2aad49e34c37846d3e976ff6a620b6712e33832041aa6
+Subject: C=US, ST=Arizona, L=Scottsdale/O=GoDaddy.com, Inc., OU=http://certs.godaddy.com/repository/, CN=Go Daddy Secure Certificate Authority - G2
+Issuer: C=US, ST=Arizona, L=Scottsdale, O="GoDaddy.com, Inc.", CN=Go Daddy Root Certificate Authority - G2
+-----BEGIN CERTIFICATE-----
+MIIE0DCCA7igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT
+EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp
+ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAwMFoXDTMxMDUwMzA3
+MDAwMFowgbQxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH
+EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjEtMCsGA1UE
+CxMkaHR0cDovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMTMwMQYDVQQD
+EypHbyBEYWRkeSBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC54MsQ1K92vdSTYuswZLiBCGzD
+BNliF44v/z5lz4/OYuY8UhzaFkVLVat4a2ODYpDOD2lsmcgaFItMzEUz6ojcnqOv
+K/6AYZ15V8TPLvQ/MDxdR/yaFrzDN5ZBUY4RS1T4KL7QjL7wMDge87Am+GZHY23e
+cSZHjzhHU9FGHbTj3ADqRay9vHHZqm8A29vNMDp5T19MR/gd71vCxJ1gO7GyQ5HY
+pDNO6rPWJ0+tJYqlxvTV0KaudAVkV4i1RFXULSo6Pvi4vekyCgKUZMQWOlDxSq7n
+eTOvDCAHf+jfBDnCaQJsY1L6d8EbyHSHyLmTGFBUNUtpTrw700kuH9zB0lL7AgMB
+AAGjggEaMIIBFjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV
+HQ4EFgQUQMK9J47MNIMwojPX+2yz8LQsgM4wHwYDVR0jBBgwFoAUOpqFBxBnKLbv
+9r0FQW4gwZTaD94wNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8v
+b2NzcC5nb2RhZGR5LmNvbS8wNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL2NybC5n
+b2RhZGR5LmNvbS9nZHJvb3QtZzIuY3JsMEYGA1UdIAQ/MD0wOwYEVR0gADAzMDEG
+CCsGAQUFBwIBFiVodHRwczovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkv
+MA0GCSqGSIb3DQEBCwUAA4IBAQAIfmyTEMg4uJapkEv/oV9PBO9sPpyIBslQj6Zz
+91cxG7685C/b+LrTW+C05+Z5Yg4MotdqY3MxtfWoSKQ7CC2iXZDXtHwlTxFWMMS2
+RJ17LJ3lXubvDGGqv+QqG+6EnriDfcFDzkSnE3ANkR/0yBOtg2DZ2HKocyQetawi
+DsoXiWJYRBuriSUBAA/NxBti21G00w9RKpv0vHP8ds42pM3Z2Czqrpv1KrKQ0U11
+GIo/ikGQI31bS/6kA1ibRrLDYGCD+H1QQc7CoZDDu+8CL9IVVO5EFdkKrqeKM+2x
+LXY2JtwE65/3YR8V3Idv7kaWKK2hJn0KCacuBKONvPi8BDAB
+-----END CERTIFICATE-----
+
+SHA-256 hash: 7e0e16c0056f41a9f4c61f571503c3bcf079e2bddb228bf2219ac31200496b5c
+Subject: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO RSA Extended Validation Secure Server CA
+Issuer: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO RSA Certification Authority
+-----BEGIN CERTIFICATE-----
+MIIGDjCCA/agAwIBAgIQBqdDgNTr/tQ1taP34Wq92DANBgkqhkiG9w0BAQwFADCB
+hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
+BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTIwMjEy
+MDAwMDAwWhcNMjcwMjExMjM1OTU5WjCBkjELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
+EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
+Q09NT0RPIENBIExpbWl0ZWQxODA2BgNVBAMTL0NPTU9ETyBSU0EgRXh0ZW5kZWQg
+VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAlVbeVLTf1QJJe9FbXKKyHo+cK2JMK40SKPMalaPGEP0p3uGf
+CzhAk9HvbpUQ/OGQF3cs7nU+e2PsYZJuTzurgElr3wDqAwB/L3XVKC/sVmePgIOj
+vdwDmZOLlJFWW6G4ajo/Br0OksxgnP214J9mMF/b5pTwlWqvyIqvgNnmiDkBfBzA
+xSr3e5Wg8narbZtyOTDr0VdVAZ1YEZ18bYSPSeidCfw8/QpKdhQhXBZzQCMZdMO6
+WAqmli7eNuWf0MLw4eDBYuPCGEUZUaoXHugjddTI0JYT/8ck0YwLJ66eetw6YWNg
+iJctXQUL5Tvrrs46R3N2qPos3cCHF+msMJn4HwIDAQABo4IBaTCCAWUwHwYDVR0j
+BBgwFoAUu69+Aj36pvE8hI6t7jiY7NkyMtQwHQYDVR0OBBYEFDna/8ooFIqodBMI
+ueQOqdL6fp1pMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMD4G
+A1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5j
+b21vZG8uY29tL0NQUzBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9k
+b2NhLmNvbS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggr
+BgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29t
+L0NPTU9ET1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz
+cC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAERCnUFRK0iIXZebeV4R
+AUpSGXtBLMeJPNBy3IX6WK/VJeQT+FhlZ58N/1eLqYVeyqZLsKeyLeCMIs37/3mk
+jCuN/gI9JN6pXV/kD0fQ22YlPodHDK4ixVAihNftSlka9pOlk7DgG4HyVsTIEFPk
+1Hax0VtpS3ey4E/EhOfUoFDuPPpE/NBXueEoU/1Tzdy5H3pAvTA/2GzS8+cHnx8i
+teoiccsq8FZ8/qyo0QYPFBRSTP5kKwxpKrgNUG4+BAe/eiCL+O5lCeHHSQgyPQ0o
+fkkdt0rvAucNgBfIXOBhYsvss2B5JdoaZXOcOBCgJjqwyBZ9kzEi7nQLiMBciUEA
+KKlHMd99SUWa9eanRRrSjhMQ34Ovmw2tfn6dNVA0BM7pINae253UqNpktNEvWS5e
+ojZh1CSggjMziqHRbO9haKPl0latxf1eYusVqHQSTC8xjOnB3xBLAer2VBvNfzu9
+XJ/B288ByvK6YBIhMe2pZLiySVgXbVrXzYxtvp5/4gJYp9vDLVj2dAZqmvZh+fYA
+tmnYOosxWd2R5nwnI4fdAw+PKowegwFOAWEMUnNt/AiiuSpm5HZNMaBWm9lTjaK2
+jwLI5jqmBNFI+8NKAnb9L9K8E7bobTQk+p0pisehKxTxlgBzuRPpwLk6R1YCcYAn
+pLwltum95OmYdBbxN4SBB7SC
+-----END CERTIFICATE-----
+
+SHA-256 hash: 19400be5b7a31fb733917700789d2f0a2471c0c9d506c0e504c06c16d7cb17c0
+Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert SHA2 High Assurance Server CA
+Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA
+-----BEGIN CERTIFICATE-----
+MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
+ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL
+MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
+LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy
+YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2
+4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC
+Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1
+itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn
+4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X
+sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft
+bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA
+MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
+NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
+dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t
+L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG
+BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ
+UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D
+aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd
+aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH
+E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly
+/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu
+xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF
+0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae
+cPUeybQ=
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/net/data/ssl/chrome_root_store/test_store.textproto b/net/data/ssl/chrome_root_store/test_store.textproto
index 056f1d32..4eee69b 100644
--- a/net/data/ssl/chrome_root_store/test_store.textproto
+++ b/net/data/ssl/chrome_root_store/test_store.textproto
@@ -58,10 +58,54 @@
   sha256_hex: "687fa451382278fff0c8b11f8d43d576671c6eb2bceab413fb83d965d06d2ff2"
   enforce_anchor_expiry: true
   enforce_anchor_constraints: true
+  trust_anchor_id: "1.1.1.1"
 }
 
 # "CN=Qualified e-Szigno TLS CA 2018,O=Microsec Ltd.,L=Budapest,C=HU,2.5.4.97=#130e56415448552d3233353834343937"
 additional_certs {
   sha256_hex: "f7c7e28fb5e79f314aaac6bbba932f15e1a72069f435d4c9e707f93ca1482ee3"
   eutl: true
-}
\ No newline at end of file
+}
+
+# Sectigo RSA Organization Validation Secure Server CA
+additional_certs {
+  sha256_hex: "72a34ac2b424aed3f6b0b04755b88cc027dccc806fddb22b4cd7c47773973ec0"
+  enforce_anchor_expiry: true
+  trust_anchor_id: "1.2.3.4"
+  tls_trust_anchor: true
+}
+
+# WR2 (Google Trust Services)
+additional_certs {
+  sha256_hex: "e6fe22bf45e4f0d3b85c59e02c0f495418e1eb8d3210f788d48cd5e1cb547cd4"
+  enforce_anchor_constraints: true
+  trust_anchor_id: "3.3.3.3"
+  tls_trust_anchor: true
+}
+
+# Go Daddy Secure Certificate Authority - G2
+additional_certs {
+  sha256_hex: "973a41276ffd01e027a2aad49e34c37846d3e976ff6a620b6712e33832041aa6"
+  enforce_anchor_expiry: true
+  enforce_anchor_constraints: true
+  trust_anchor_id: "2.2.2.2"
+  tls_trust_anchor: true
+}
+
+# Anchor for testing that a certificate which is not EUTL and not a TLS trust anchor is discarded.
+
+# COMODO RSA Extended Validation Secure Server CA
+additional_certs {
+  sha256_hex: "7e0e16c0056f41a9f4c61f571503c3bcf079e2bddb228bf2219ac31200496b5c"
+  trust_anchor_id: "1.2.3.3"
+}
+
+# Anchor for testing that a tls_trust_anchor cert is trusted even if it doesn't have an associated Trust Anchor ID.
+
+# DigiCert SHA2 High Assurance Server CA
+additional_certs {
+  sha256_hex: "19400be5b7a31fb733917700789d2f0a2471c0c9d506c0e504c06c16d7cb17c0"
+  enforce_anchor_expiry: true
+  enforce_anchor_constraints: true
+  tls_trust_anchor: true
+}
diff --git a/net/device_bound_sessions/cookie_craving.cc b/net/device_bound_sessions/cookie_craving.cc
index 210d0e6..5344f63c 100644
--- a/net/device_bound_sessions/cookie_craving.cc
+++ b/net/device_bound_sessions/cookie_craving.cc
@@ -225,7 +225,7 @@
 bool CookieCraving::IsSatisfiedBy(
     const CanonicalCookie& canonical_cookie) const {
   CHECK(IsValid());
-  CHECK(canonical_cookie.IsCanonical());
+  CHECK(canonical_cookie.IsCanonicalForFromStorage());
 
   // Note: Creation time is not required to match. DBSC configs may be set at
   // different times from the cookies they reference. DBSC also does not require
diff --git a/net/extras/sqlite/sqlite_persistent_shared_dictionary_store.cc b/net/extras/sqlite/sqlite_persistent_shared_dictionary_store.cc
index 6b780df..19604d8 100644
--- a/net/extras/sqlite/sqlite_persistent_shared_dictionary_store.cc
+++ b/net/extras/sqlite/sqlite_persistent_shared_dictionary_store.cc
@@ -12,6 +12,7 @@
 #include "base/containers/span.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/files/file_path.h"
+#include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/pickle.h"
 #include "base/strings/strcat.h"
diff --git a/net/http/http_stream_pool_attempt_manager.cc b/net/http/http_stream_pool_attempt_manager.cc
index fa56d8d..be24439 100644
--- a/net/http/http_stream_pool_attempt_manager.cc
+++ b/net/http/http_stream_pool_attempt_manager.cc
@@ -475,14 +475,15 @@
   }
 
   // Try to assign an idle stream to a job.
-  if (jobs_.size() > 0 && group_->IdleStreamSocketCount() > 0) {
+  if (jobs_.size() > 0) {
     std::unique_ptr<StreamSocket> stream_socket = group_->GetIdleStreamSocket();
-    CHECK(stream_socket);
-    const StreamSocketHandle::SocketReuseType reuse_type =
-        GetReuseTypeFromIdleStreamSocket(*stream_socket);
-    CreateTextBasedStreamAndNotify(std::move(stream_socket), reuse_type,
-                                   LoadTimingInfo::ConnectTiming());
-    return;
+    if (stream_socket) {
+      const StreamSocketHandle::SocketReuseType reuse_type =
+          GetReuseTypeFromIdleStreamSocket(*stream_socket);
+      CreateTextBasedStreamAndNotify(std::move(stream_socket), reuse_type,
+                                     LoadTimingInfo::ConnectTiming());
+      return;
+    }
   }
 
   const size_t pending_job_count = PendingJobCount();
diff --git a/net/http/http_stream_pool_attempt_manager_unittest.cc b/net/http/http_stream_pool_attempt_manager_unittest.cc
index bbab823..21fdc80 100644
--- a/net/http/http_stream_pool_attempt_manager_unittest.cc
+++ b/net/http/http_stream_pool_attempt_manager_unittest.cc
@@ -1887,6 +1887,53 @@
   EXPECT_THAT(requester.result(), Optional(IsOk()));
 }
 
+// Regression test for crbug.com/414604656. An idle stream could become
+// non-usable after a request is blocked by the stream count limits. In such
+// case, the request should get a fresh stream.
+TEST_F(HttpStreamPoolAttemptManagerTest, IdleStreamNotUsable) {
+  constexpr size_t kMaxPerGroup = 1;
+  pool().set_max_stream_sockets_per_group_for_testing(kMaxPerGroup);
+
+  const HttpStreamKey stream_key = StreamKeyBuilder("http://a.test").Build();
+  Group& group = pool().GetOrCreateGroupForTesting(stream_key);
+
+  // Create an active text-based stream.
+  auto stream_socket = std::make_unique<FakeStreamSocket>();
+  FakeStreamSocket* stream_socket_ptr = stream_socket.get();
+  std::unique_ptr<HttpStream> stream = group.CreateTextBasedStream(
+      std::move(stream_socket),
+      StreamSocketHandle::SocketReuseType::kReusedIdle,
+      LoadTimingInfo::ConnectTiming());
+  ASSERT_EQ(group.ActiveStreamSocketCount(), 1u);
+  ASSERT_EQ(group.IdleStreamSocketCount(), 0u);
+
+  resolver()
+      ->AddFakeRequest()
+      ->add_endpoint(ServiceEndpointBuilder().add_v4("192.0.2.1").endpoint())
+      .CompleteStartSynchronously(OK);
+
+  SequencedSocketData data;
+  data.set_connect_data(MockConnect(ASYNC, OK));
+  socket_factory()->AddSocketDataProvider(&data);
+
+  // Request another stream. The request should be blocked as the group reached
+  // the group limit.
+  StreamRequester requester(stream_key);
+  requester.RequestStream(pool());
+  ASSERT_FALSE(requester.result().has_value());
+
+  // Release the first stream that will be kept as an idle stream but will be
+  // disconnected later. IsConnected() is called twice to put the stream in the
+  // idle stream pool.
+  stream_socket_ptr->DisconnectAfterIsConnectedCall(/*count=*/2);
+  stream.reset();
+
+  // The request should complete with a fresh stream.
+  requester.WaitForResult();
+  EXPECT_THAT(requester.result(), Optional(IsOk()));
+  ASSERT_FALSE(requester.stream()->IsConnectionReused());
+}
+
 TEST_F(HttpStreamPoolAttemptManagerTest, FeatureParamStreamLimits) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeatureWithParameters(
diff --git a/net/http/http_stream_pool_test_util.cc b/net/http/http_stream_pool_test_util.cc
index 879d00eb..245eaa2 100644
--- a/net/http/http_stream_pool_test_util.cc
+++ b/net/http/http_stream_pool_test_util.cc
@@ -224,8 +224,11 @@
   if (is_connected_override_.has_value()) {
     return *is_connected_override_;
   }
-  if (disconnect_after_is_connected_call_) {
-    is_connected_override_ = false;
+  if (disconnect_after_is_connected_call_count_ > 0) {
+    --disconnect_after_is_connected_call_count_;
+    if (disconnect_after_is_connected_call_count_ == 0) {
+      is_connected_override_ = false;
+    }
   }
   return connected_;
 }
@@ -247,10 +250,10 @@
   return false;
 }
 
-void FakeStreamSocket::DisconnectAfterIsConnectedCall() {
+void FakeStreamSocket::DisconnectAfterIsConnectedCall(int count) {
   connected_ = true;
   is_connected_override_ = std::nullopt;
-  disconnect_after_is_connected_call_ = true;
+  disconnect_after_is_connected_call_count_ = count;
 }
 
 StreamKeyBuilder& StreamKeyBuilder::from_key(const HttpStreamKey& key) {
diff --git a/net/http/http_stream_pool_test_util.h b/net/http/http_stream_pool_test_util.h
index 46d0a74b..280cd8af 100644
--- a/net/http/http_stream_pool_test_util.h
+++ b/net/http/http_stream_pool_test_util.h
@@ -210,14 +210,18 @@
   bool WasEverUsed() const override;
   bool GetSSLInfo(SSLInfo* ssl_info) override;
 
-  // Simulate a situation where a connected socket immediately disconnects after
-  // checking IsConnected(). This could happen in the real world.
-  void DisconnectAfterIsConnectedCall();
+  // Simulates a situation where a connected socket disconnects after
+  // IsConnected() is called `count` times. Such situation could happen in the
+  // real world.
+  void DisconnectAfterIsConnectedCall(int count = 1);
 
  private:
   bool is_idle_ = true;
   bool was_ever_used_ = false;
-  bool disconnect_after_is_connected_call_ = false;
+  // When set to a positive value, every IsConnected() call decrements this
+  // counter. After this counter reached zero, IsConnected() uses
+  // `is_connected_override_`.
+  mutable int disconnect_after_is_connected_call_count_ = -1;
   mutable std::optional<bool> is_connected_override_;
   std::optional<SSLInfo> ssl_info_;
 };
diff --git a/net/tools/root_store_tool/root_store_tool.cc b/net/tools/root_store_tool/root_store_tool.cc
index 5f48909..589c8da 100644
--- a/net/tools/root_store_tool/root_store_tool.cc
+++ b/net/tools/root_store_tool/root_store_tool.cc
@@ -262,6 +262,23 @@
   }
 }
 
+// Appends |trust_anchor|'s Trust Anchor ID (or empty string, if not present) to
+// |*string_to_write|, with a preceding comma. Returns false if the Trust Anchor
+// ID is malformed.
+bool WriteTrustAnchorID(const TrustAnchor& anchor,
+                        std::string* string_to_write) {
+  if (anchor.has_trust_anchor_id()) {
+    if (anchor.trust_anchor_id().find_first_not_of("0123456789.") !=
+        std::string::npos) {
+      return false;
+    }
+    base::StringAppendF(string_to_write, ", \"%s\"", anchor.trust_anchor_id());
+  } else {
+    *string_to_write += ", \"\"";
+  }
+  return true;
+}
+
 // Returns true if file was correctly written, false otherwise.
 bool WriteRootCppFile(const RootStore& root_store,
                       const base::FilePath cpp_path) {
@@ -275,21 +292,56 @@
   WriteTrustAnchors(root_store.additional_certs(), "Additional",
                     &string_to_write);
 
-  // Assemble list of trust anchors
+  // Assemble list of trust anchors.
   string_to_write += "constexpr ChromeRootCertInfo kChromeRootCertList[] = {\n";
   for (int i = 0; i < root_store.trust_anchors_size(); i++) {
     const auto& anchor = root_store.trust_anchors(i);
+    if (anchor.has_tls_trust_anchor()) {
+      // Anchors in |trust_anchors| are not supposed to have |tls_trust_anchor|
+      // set, because they are definitionally TLS trust anchors.
+      return false;
+    }
     base::StringAppendF(&string_to_write, "    {kChromeRootCert%d, ", i);
     if (anchor.constraints_size() > 0) {
       base::StringAppendF(&string_to_write, "kChromeRootConstraints%d", i);
     } else {
       string_to_write += "{}";
     }
+
     base::StringAppendF(
         &string_to_write,
-        ", /*enforce_anchor_expiry=*/%s, /*enforce_anchor_constraints=*/%s},\n",
+        ", /*enforce_anchor_expiry=*/%s, /*enforce_anchor_constraints=*/%s",
         anchor.enforce_anchor_expiry() ? "true" : "false",
         anchor.enforce_anchor_constraints() ? "true" : "false");
+
+    if (!WriteTrustAnchorID(anchor, &string_to_write)) {
+      return false;
+    }
+    string_to_write += "},\n";
+  }
+  // Append additional_certs as TLS trust anchors, if they are marked as such.
+  for (int i = 0; i < root_store.additional_certs_size(); i++) {
+    const auto& anchor = root_store.additional_certs(i);
+    if (!anchor.tls_trust_anchor()) {
+      continue;
+    }
+    base::StringAppendF(&string_to_write, "    {kAdditionalCert%d, ", i);
+    if (anchor.constraints_size() > 0) {
+      base::StringAppendF(&string_to_write, "kAdditionalConstraints%d", i);
+    } else {
+      string_to_write += "{}";
+    }
+
+    base::StringAppendF(
+        &string_to_write,
+        ", /*enforce_anchor_expiry=*/%s, /*enforce_anchor_constraints=*/%s",
+        anchor.enforce_anchor_expiry() ? "true" : "false",
+        anchor.enforce_anchor_constraints() ? "true" : "false");
+
+    if (!WriteTrustAnchorID(anchor, &string_to_write)) {
+      return false;
+    }
+    string_to_write += "},\n";
   }
   string_to_write += "};\n\n";
 
diff --git a/remoting/protocol/mouse_input_filter_unittest.cc b/remoting/protocol/mouse_input_filter_unittest.cc
index 887078b3..19b04e6 100644
--- a/remoting/protocol/mouse_input_filter_unittest.cc
+++ b/remoting/protocol/mouse_input_filter_unittest.cc
@@ -2,13 +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 "remoting/protocol/mouse_input_filter.h"
 
+#include <array>
+#include <utility>
+
+#include "base/containers/span.h"
 #include "remoting/proto/event.pb.h"
 #include "remoting/protocol/protocol_mock_objects.h"
 #include "remoting/protocol/test_event_matchers.h"
@@ -23,6 +22,10 @@
 
 using test::EqualsMouseMoveEvent;
 
+namespace {
+
+using Point = std::pair</* x */ int, /* y */ int>;
+
 static MouseEvent MouseMoveEvent(int x, int y) {
   MouseEvent event;
   event.set_x(x);
@@ -30,14 +33,11 @@
   return event;
 }
 
-struct Point {
-  int x;
-  int y;
-};
+}  // namespace
 
 class MouseInputFilterTest : public testing::Test {
  public:
-  MouseInputFilterTest() : mouse_filter_(&mock_stub_) {}
+  MouseInputFilterTest() = default;
 
   // Set the size of the client viewing rectangle.
   void SetClientSize(int width, int height) {
@@ -56,69 +56,55 @@
     mouse_filter_.set_output_size(width, height);
   }
 
-  void InjectMouse(const Point& point, bool swap = false) {
-    mouse_filter_.InjectMouseEvent(MouseMoveEvent(point.x, point.y));
-    if (swap) {
-      mouse_filter_.InjectMouseEvent(MouseMoveEvent(point.y, point.x));
-    }
-  }
-
-  void ExpectNoMouse() {
-    EXPECT_CALL(mock_stub_, InjectMouseEvent(_)).Times(0);
-  }
-
-  void ExpectMouse(const Point& point, bool swap = false) {
-    EXPECT_CALL(mock_stub_,
-                InjectMouseEvent(EqualsMouseMoveEvent(point.x, point.y)))
-        .Times(1);
-    if (swap) {
-      EXPECT_CALL(mock_stub_,
-                  InjectMouseEvent(EqualsMouseMoveEvent(point.y, point.x)))
-          .Times(1);
-    }
-  }
-
-  void RunMouseTests(unsigned int len,
-                     const Point* injected,
-                     const Point* expected,
+  void RunMouseTests(base::span<const Point> injected,
+                     base::span<const Point> expected,
                      bool swap = false) {
+    ASSERT_EQ(injected.size(), expected.size());
     {
-      InSequence s;
-      for (unsigned int i = 0; i < len; ++i) {
-        ExpectMouse(expected[i], swap);
+      InSequence seq;
+      for (const auto& [x, y] : expected) {
+        EXPECT_CALL(mock_stub_, InjectMouseEvent(EqualsMouseMoveEvent(x, y)))
+            .Times(1);
+        if (swap) {
+          EXPECT_CALL(mock_stub_, InjectMouseEvent(EqualsMouseMoveEvent(y, x)))
+              .Times(1);
+        }
       }
     }
 
-    for (unsigned int i = 0; i < len; ++i) {
-      InjectMouse(injected[i], swap);
+    for (const auto& [x, y] : injected) {
+      mouse_filter_.InjectMouseEvent(MouseMoveEvent(x, y));
+      if (swap) {
+        mouse_filter_.InjectMouseEvent(MouseMoveEvent(y, x));
+      }
     }
   }
 
  protected:
   MockInputStub mock_stub_;
-  MouseInputFilter mouse_filter_;
+  MouseInputFilter mouse_filter_{&mock_stub_};
 };
 
 // Verify that no events get through if we don't set either dimensions.
 TEST_F(MouseInputFilterTest, NoDimensionsSet) {
-  ExpectNoMouse();
-  InjectMouse({10, 10});
+  EXPECT_CALL(mock_stub_, InjectMouseEvent(_)).Times(0);
+  mouse_filter_.InjectMouseEvent(MouseMoveEvent(10, 10));
 }
 
 // Verify that no events get through if there's no input size.
 TEST_F(MouseInputFilterTest, InputDimensionsZero) {
   SetHostDesktop(50, 50);
 
-  ExpectNoMouse();
-  InjectMouse({10, 10});
+  EXPECT_CALL(mock_stub_, InjectMouseEvent(_)).Times(0);
+  mouse_filter_.InjectMouseEvent(MouseMoveEvent(10, 10));
 }
 
 // Verify that no events get through if there's no output size.
 TEST_F(MouseInputFilterTest, OutputDimensionsZero) {
   SetClientSize(40, 40);
 
-  ExpectNoMouse();
-  InjectMouse({10, 10});
+  EXPECT_CALL(mock_stub_, InjectMouseEvent(_)).Times(0);
+  mouse_filter_.InjectMouseEvent(MouseMoveEvent(10, 10));
 }
 
 // Verify that no events get through when input and output are both set to zero.
@@ -126,8 +112,8 @@
   SetClientSize(0, 0);
   SetHostDesktop(0, 0);
 
-  ExpectNoMouse();
-  InjectMouse({10, 10});
+  EXPECT_CALL(mock_stub_, InjectMouseEvent(_)).Times(0);
+  mouse_filter_.InjectMouseEvent(MouseMoveEvent(10, 10));
 }
 
 // Verify that no events get through if the input and output are both set to
@@ -137,8 +123,8 @@
   SetClientSize(1, 1);
   SetHostDesktop(1, 1);
 
-  ExpectNoMouse();
-  InjectMouse({10, 10});
+  EXPECT_CALL(mock_stub_, InjectMouseEvent(_)).Times(0);
+  mouse_filter_.InjectMouseEvent(MouseMoveEvent(10, 10));
 }
 
 // Verify that a min-size desktop (2x2) is handled. This is an edge case test,
@@ -147,9 +133,9 @@
   SetClientSize(2, 2);
   SetHostDesktop(2, 2);
 
-  const Point injected[] = {{1, 1}};
-  const Point expected[] = {{1, 1}};
-  RunMouseTests(std::size(expected), injected, expected, true);
+  constexpr auto injected = std::to_array<Point>({{1, 1}});
+  constexpr auto expected = std::to_array<Point>({{1, 1}});
+  RunMouseTests(injected, expected, true);
 }
 
 // Verify that no events get through if negative dimensions are provided.
@@ -157,8 +143,8 @@
   SetClientSize(-42, -42);
   SetHostDesktop(-84, -84);
 
-  ExpectNoMouse();
-  InjectMouse({10, 10});
+  EXPECT_CALL(mock_stub_, InjectMouseEvent(_)).Times(0);
+  mouse_filter_.InjectMouseEvent(MouseMoveEvent(10, 10));
 }
 
 // Verify that all events get through, clamped to the output.
@@ -166,12 +152,12 @@
   SetClientSize(40, 40);
   SetHostDesktop(40, 40);
 
-  const Point injected[] = {{-5, 10}, {0, 10},  {-1, 10}, {15, 40},
-                            {15, 45}, {15, 39}, {15, 25}};
-  const Point expected[] = {{0, 10},  {0, 10},  {0, 10}, {15, 39},
-                            {15, 39}, {15, 39}, {15, 25}};
+  constexpr auto injected = std::to_array<Point>(
+      {{-5, 10}, {0, 10}, {-1, 10}, {15, 40}, {15, 45}, {15, 39}, {15, 25}});
+  constexpr auto expected = std::to_array<Point>(
+      {{0, 10}, {0, 10}, {0, 10}, {15, 39}, {15, 39}, {15, 39}, {15, 25}});
 
-  RunMouseTests(std::size(expected), injected, expected, true);
+  RunMouseTests(injected, expected, true);
 }
 
 // Verify that we can up-scale with clamping.
@@ -179,12 +165,12 @@
   SetClientSize(40, 40);
   SetHostDesktop(80, 80);
 
-  const Point injected[] = {{-5, 10}, {0, 10},  {-1, 10}, {15, 40},
-                            {15, 45}, {15, 39}, {15, 25}};
-  const Point expected[] = {{0, 20},  {0, 20},  {0, 20}, {30, 79},
-                            {30, 79}, {30, 79}, {30, 51}};
+  constexpr auto injected = std::to_array<Point>(
+      {{-5, 10}, {0, 10}, {-1, 10}, {15, 40}, {15, 45}, {15, 39}, {15, 25}});
+  constexpr auto expected = std::to_array<Point>(
+      {{0, 20}, {0, 20}, {0, 20}, {30, 79}, {30, 79}, {30, 79}, {30, 51}});
 
-  RunMouseTests(std::size(expected), injected, expected, true);
+  RunMouseTests(injected, expected, true);
 }
 
 // Verify that we can down-scale with clamping.
@@ -192,12 +178,12 @@
   SetClientSize(40, 40);
   SetHostDesktop(30, 30);
 
-  const Point injected[] = {{-5, 10}, {0, 10},  {-1, 10}, {15, 40},
-                            {15, 45}, {15, 39}, {15, 25}};
-  const Point expected[] = {{0, 7},   {0, 7},   {0, 7},  {11, 29},
-                            {11, 29}, {11, 29}, {11, 19}};
+  constexpr auto injected = std::to_array<Point>(
+      {{-5, 10}, {0, 10}, {-1, 10}, {15, 40}, {15, 45}, {15, 39}, {15, 25}});
+  constexpr auto expected = std::to_array<Point>(
+      {{0, 7}, {0, 7}, {0, 7}, {11, 29}, {11, 29}, {11, 29}, {11, 19}});
 
-  RunMouseTests(std::size(expected), injected, expected, true);
+  RunMouseTests(injected, expected, true);
 }
 
 // Multimon tests
@@ -215,32 +201,30 @@
   SetClientSize(5120, 1728);
   SetHostMultimonSingleDisplay(0, 0, 6400, 2160);
 
-  const Point injected[] = {
-      {9, 10}, {1559, 372}, {3053, 1662}, {4167, 99}, {5093, 889}};
-  const Point expected[] = {
-      {11, 13}, {1949, 465}, {3816, 2078}, {5209, 124}, {6366, 1111}};
+  constexpr auto injected = std::to_array<Point>(
+      {{9, 10}, {1559, 372}, {3053, 1662}, {4167, 99}, {5093, 889}});
+  constexpr auto expected = std::to_array<Point>(
+      {{11, 13}, {1949, 465}, {3816, 2078}, {5209, 124}, {6366, 1111}});
 
-  RunMouseTests(std::size(expected), injected, expected);
+  RunMouseTests(injected, expected);
 }
 
 TEST_F(MouseInputFilterTest, MultimonLeftDefault_ShowLeftDisplay) {
   SetClientSize(2048, 1152);
   SetHostMultimonSingleDisplay(0, 0, 2560, 1440);
 
-  const Point injected[] = {{12, 25}, {2011, 1099}};
-  const Point expected[] = {{15, 31}, {2514, 1374}};
-
-  RunMouseTests(std::size(expected), injected, expected);
+  constexpr auto injected = std::to_array<Point>({{12, 25}, {2011, 1099}});
+  constexpr auto expected = std::to_array<Point>({{15, 31}, {2514, 1374}});
+  RunMouseTests(injected, expected);
 }
 
 TEST_F(MouseInputFilterTest, MultimonLeftDefault_ShowRightDisplay) {
   SetClientSize(3072, 1728);
   SetHostMultimonSingleDisplay(2560, 0, 3840, 2160);
 
-  const Point injected[] = {{175, 165}, {2948, 1532}};
-  const Point expected[] = {{2779, 206}, {6245, 1915}};
-
-  RunMouseTests(std::size(expected), injected, expected);
+  constexpr auto injected = std::to_array<Point>({{175, 165}, {2948, 1532}});
+  constexpr auto expected = std::to_array<Point>({{2779, 206}, {6245, 1915}});
+  RunMouseTests(injected, expected);
 }
 
 // Default display = Right (A)
@@ -256,20 +240,18 @@
   SetClientSize(3072, 1728);
   SetHostMultimonSingleDisplay(0, 0, 3840, 2160);
 
-  const Point injected[] = {{64, 61}, {3029, 1649}};
-  const Point expected[] = {{80, 76}, {3786, 2061}};
-
-  RunMouseTests(std::size(expected), injected, expected);
+  constexpr auto injected = std::to_array<Point>({{64, 61}, {3029, 1649}});
+  constexpr auto expected = std::to_array<Point>({{80, 76}, {3786, 2061}});
+  RunMouseTests(injected, expected);
 }
 
 TEST_F(MouseInputFilterTest, MultimonRightDefault_ShowRightDisplay) {
   SetClientSize(2048, 1152);
   SetHostMultimonSingleDisplay(3840, 0, 2560, 1440);
 
-  const Point injected[] = {{19, 20}, {2014, 1095}};
-  const Point expected[] = {{3864, 25}, {6358, 1369}};
-
-  RunMouseTests(std::size(expected), injected, expected);
+  constexpr auto injected = std::to_array<Point>({{19, 20}, {2014, 1095}});
+  constexpr auto expected = std::to_array<Point>({{3864, 25}, {6358, 1369}});
+  RunMouseTests(injected, expected);
 }
 
 }  // namespace remoting::protocol
diff --git a/services/data_decoder/public/cpp/data_decoder.cc b/services/data_decoder/public/cpp/data_decoder.cc
index 44884fc4..512b48a 100644
--- a/services/data_decoder/public/cpp/data_decoder.cc
+++ b/services/data_decoder/public/cpp/data_decoder.cc
@@ -8,7 +8,6 @@
 #include <string>
 #include <utility>
 
-#include "base/features.h"
 #include "base/functional/callback.h"
 #include "base/json/json_reader.h"
 #include "base/memory/ref_counted.h"
@@ -28,11 +27,6 @@
 #include "services/data_decoder/public/mojom/structured_headers_parser.mojom.h"
 #include "services/data_decoder/public/mojom/xml_parser.mojom.h"
 
-#if BUILDFLAG(IS_ANDROID)
-#include "base/types/expected_macros.h"
-#include "services/data_decoder/public/cpp/json_sanitizer.h"
-#endif
-
 #if !BUILDFLAG(USE_BLINK)
 #include "services/data_decoder/data_decoder_service.h"  // nogncheck
 #endif
@@ -204,62 +198,11 @@
       },
       base::ElapsedTimer(), std::move(callback));
 
-  if (base::JSONReader::UsingRust()) {
-    if (base::features::kUseRustJsonParserInCurrentSequence.Get()) {
-      base::JSONReader::Result result =
-          base::JSONReader::ReadAndReturnValueWithError(json,
-                                                        base::JSON_PARSE_RFC);
-      base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-          FROM_HERE, base::BindOnce(&ParsingComplete, cancel_requests_,
-                                    std::move(callback), std::move(result)));
-    } else {
-      base::ThreadPool::PostTaskAndReplyWithResult(
-          FROM_HERE, {base::TaskPriority::USER_VISIBLE},
-          base::BindOnce(
-              [](const std::string& json) {
-                return base::JSONReader::ReadAndReturnValueWithError(
-                    json, base::JSON_PARSE_RFC);
-              },
-              json),
-          base::BindOnce(&ParsingComplete, cancel_requests_,
-                         std::move(callback)));
-    }
-    return;
-  }
-
-#if BUILDFLAG(IS_ANDROID)
-  // For Android, if the full Rust parser is not available, we use the
-  // in-process sanitizer and then parse in-process.
-  JsonSanitizer::Sanitize(
-      json, base::BindOnce(
-                [](ValueParseCallback callback,
-                   scoped_refptr<CancellationFlag> is_cancelled,
-                   JsonSanitizer::Result result) {
-                  if (is_cancelled->data) {
-                    return;
-                  }
-
-                  RETURN_IF_ERROR(result, [&](std::string error) {
-                    std::move(callback).Run(base::unexpected(std::move(error)));
-                  });
-
-                  ParsingComplete(is_cancelled, std::move(callback),
-                                  base::JSONReader::ReadAndReturnValueWithError(
-                                      result.value(), base::JSON_PARSE_RFC));
-                },
-                std::move(callback), cancel_requests_));
-#else   // BUILDFLAG(IS_ANDROID)
-  // Parse JSON out-of-process.
-  auto request =
-      base::MakeRefCounted<ValueParseRequest<mojom::JsonParser, base::Value>>(
-          std::move(callback), cancel_requests_);
-  GetService()->BindJsonParser(request->BindRemote());
-  request->remote()->Parse(
-      json, base::JSON_PARSE_RFC,
-      base::BindOnce(&ValueParseRequest<mojom::JsonParser,
-                                        base::Value>::OnServiceValueOrError,
-                     request));
-#endif  // BUILDFLAG(IS_ANDROID)
+  base::JSONReader::Result result =
+      base::JSONReader::ReadAndReturnValueWithError(json, base::JSON_PARSE_RFC);
+  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
+      FROM_HERE, base::BindOnce(&ParsingComplete, cancel_requests_,
+                                std::move(callback), std::move(result)));
 }
 
 // static
diff --git a/services/data_decoder/public/cpp/data_decoder_unittest.cc b/services/data_decoder/public/cpp/data_decoder_unittest.cc
index 2eb9bf9..0e8cf67 100644
--- a/services/data_decoder/public/cpp/data_decoder_unittest.cc
+++ b/services/data_decoder/public/cpp/data_decoder_unittest.cc
@@ -6,13 +6,11 @@
 
 #include <memory>
 
-#include "base/features.h"
 #include "base/functional/bind.h"
 #include "base/run_loop.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/types/expected.h"
 #include "base/values.h"
@@ -208,63 +206,33 @@
 
 class DataDecoderMultiThreadTest : public testing::Test {
  protected:
-  void TestJSONDecode() {
-    base::RunLoop run_loop;
-    DataDecoder decoder;
-    DataDecoder::ValueOrError result;
-    decoder.ParseJson(
-        // The magic 122.416294033786585 number comes from
-        // https://github.com/serde-rs/json/issues/707
-        "[ 122.416294033786585 ]",
-        base::BindLambdaForTesting(
-            [&run_loop, &result](DataDecoder::ValueOrError value_or_error) {
-              result = std::move(value_or_error);
-              run_loop.Quit();
-            }));
-    run_loop.Run();
-    histogram_tester_.ExpectTotalCount("Security.DataDecoder.Json.DecodingTime",
-                                       1);
-    ASSERT_TRUE(result.has_value());
-    ASSERT_TRUE(result->is_list());
-    base::Value::List& list = result->GetList();
-    ASSERT_EQ(1u, list.size());
-    EXPECT_TRUE(list[0].is_double());
-    EXPECT_EQ(122.416294033786585, list[0].GetDouble());
-  }
-
   base::test::TaskEnvironment task_environment_;
   base::HistogramTester histogram_tester_;
 };
 
-// Test basic JSON decoding without using Rust. We test only on Android,
-// because otherwise this would result in spawning a process.
-#if BUILDFLAG(IS_ANDROID)
-#define MAYBE_JSONDecodeNonRust JSONDecodeNonRust
-#else  // BUILDFLAG(IS_ANDROID)
-#define MAYBE_JSONDecodeNonRust DISABLED_JSONDecodeNonRust
-#endif  // BUILDFLAG(IS_ANDROID)
-TEST_F(DataDecoderMultiThreadTest, MAYBE_JSONDecodeNonRust) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndDisableFeature(base::features::kUseRustJsonParser);
-  TestJSONDecode();
-}
-
 // Test basic JSON decoding using Rust, in a threadpool.
-TEST_F(DataDecoderMultiThreadTest, JSONDecodeRustThreadpool) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeatureWithParameters(
-      base::features::kUseRustJsonParser,
-      {{"UseRustJsonParserInCurrentSequence", "false"}});
-  TestJSONDecode();
-}
-
-// Test basic JSON decoding using Rust, in the main thread.
-TEST_F(DataDecoderMultiThreadTest, JSONDecodeRustCurrentSequence) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeatureWithParameters(
-      base::features::kUseRustJsonParser,
-      {{"UseRustJsonParserInCurrentSequence", "true"}});
-  TestJSONDecode();
+TEST_F(DataDecoderMultiThreadTest, JSONDecode) {
+  base::RunLoop run_loop;
+  DataDecoder decoder;
+  DataDecoder::ValueOrError result;
+  decoder.ParseJson(
+      // The magic 122.416294033786585 number comes from
+      // https://github.com/serde-rs/json/issues/707
+      "[ 122.416294033786585 ]",
+      base::BindLambdaForTesting(
+          [&run_loop, &result](DataDecoder::ValueOrError value_or_error) {
+            result = std::move(value_or_error);
+            run_loop.Quit();
+          }));
+  run_loop.Run();
+  histogram_tester_.ExpectTotalCount("Security.DataDecoder.Json.DecodingTime",
+                                     1);
+  ASSERT_TRUE(result.has_value());
+  ASSERT_TRUE(result->is_list());
+  base::Value::List& list = result->GetList();
+  ASSERT_EQ(1u, list.size());
+  EXPECT_TRUE(list[0].is_double());
+  EXPECT_EQ(122.416294033786585, list[0].GetDouble());
 }
 
 }  // namespace data_decoder
diff --git a/services/data_decoder/public/cpp/test_support/in_process_data_decoder.cc b/services/data_decoder/public/cpp/test_support/in_process_data_decoder.cc
index 4ce31f3..9ddde27 100644
--- a/services/data_decoder/public/cpp/test_support/in_process_data_decoder.cc
+++ b/services/data_decoder/public/cpp/test_support/in_process_data_decoder.cc
@@ -6,7 +6,6 @@
 
 #include <utility>
 
-#include "base/features.h"
 #include "base/task/sequenced_task_runner.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 
@@ -27,12 +26,6 @@
   return nullptr;
 }
 
-void InProcessDataDecoder::SimulateJsonParserCrash(bool drop) {
-  CHECK(!base::FeatureList::IsEnabled(base::features::kUseRustJsonParser))
-      << "Rust JSON parser is in-process and cannot crash.";
-  drop_json_parsers_ = drop;
-}
-
 void InProcessDataDecoder::BindDataDecoderService(
     mojo::PendingReceiver<mojom::DataDecoderService> receiver) {
   if (!task_runner_->RunsTasksInCurrentSequence()) {
@@ -68,9 +61,7 @@
 
 void InProcessDataDecoder::BindJsonParser(
     mojo::PendingReceiver<mojom::JsonParser> receiver) {
-  if (!drop_json_parsers_) {
-    GetForwardingInterface()->BindJsonParser(std::move(receiver));
-  }
+  GetForwardingInterface()->BindJsonParser(std::move(receiver));
 }
 
 void InProcessDataDecoder::BindWebBundleParserFactory(
diff --git a/services/data_decoder/public/cpp/test_support/in_process_data_decoder.h b/services/data_decoder/public/cpp/test_support/in_process_data_decoder.h
index 87ebf4a6..7169bad 100644
--- a/services/data_decoder/public/cpp/test_support/in_process_data_decoder.h
+++ b/services/data_decoder/public/cpp/test_support/in_process_data_decoder.h
@@ -44,9 +44,6 @@
   // them. Useful for tests simulating service failures.
   void SimulateImageDecoderCrash(bool drop) { drop_image_decoders_ = drop; }
 
-  // Same as above but for JsonParser receivers.
-  void SimulateJsonParserCrash(bool drop);
-
   // Configures the service to use |binder| to bind
   // WebBundleParserFactory in subsequent
   // BindWebBundleParserFactory() calls.
@@ -82,7 +79,6 @@
   ::data_decoder::DataDecoderService service_;
   mojo::ReceiverSet<mojom::DataDecoderService> receivers_;
   bool drop_image_decoders_ = false;
-  bool drop_json_parsers_ = false;
   base::RepeatingCallback<void(
       mojo::PendingReceiver<web_package::mojom::WebBundleParserFactory>)>
       web_bundle_parser_factory_binder_;
diff --git a/services/on_device_model/public/cpp/model_assets.cc b/services/on_device_model/public/cpp/model_assets.cc
index e1f1f53..5f25f7d 100644
--- a/services/on_device_model/public/cpp/model_assets.cc
+++ b/services/on_device_model/public/cpp/model_assets.cc
@@ -7,6 +7,7 @@
 #include <cstdint>
 #include <string_view>
 
+#include "base/feature_list.h"
 #include "base/files/file.h"
 #include "base/files/file_util.h"
 #include "base/task/thread_pool.h"
@@ -15,6 +16,19 @@
 namespace on_device_model {
 namespace {
 
+// Whether the on-device model should be loaded from a file path rather than a
+// file descriptor. This may require disabling this service's sandbox.
+//
+// This flag is only for testing purposes and should NOT be enabled by default.
+//
+// Ideally this would be a FeatureParam of
+// `optimization_guide::features::kOptimizationGuideOnDeviceModel` but including
+// that header here results in a circular dependency which isn't worth
+// unraveling for a flag which will never be used outside of local testing.
+BASE_FEATURE(kForceLoadOnDeviceModelFromFilePathForTesting,
+             "ForceLoadOnDeviceModelFromFilePathForTesting",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // NOTE: Weights ultimately need to be mapped copy-on-write, but Fuchsia
 // (due to an apparent bug?) doesn't seem to support copy-on-write mapping of
 // file objects which are not writable. So we open as writable on Fuchsia even
@@ -78,7 +92,12 @@
 
   ModelAssets assets;
   if (!paths.weights.empty()) {
-    assets.weights = base::File(paths.weights, kWeightsFlags);
+    if (base::FeatureList::IsEnabled(
+            kForceLoadOnDeviceModelFromFilePathForTesting)) {
+      assets.weights_path = paths.weights;
+    } else {
+      assets.weights = base::File(paths.weights, kWeightsFlags);
+    }
   }
   return assets;
 }
diff --git a/services/screen_ai/public/cpp/metrics.cc b/services/screen_ai/public/cpp/metrics.cc
index 6ca7e39..a3211380 100644
--- a/services/screen_ai/public/cpp/metrics.cc
+++ b/services/screen_ai/public/cpp/metrics.cc
@@ -47,9 +47,9 @@
   }
 
   // Convert to a Chrome language code synonym. Then pass it to
-  // `base::HashMetricName()` that maps this code to a `LocaleCodeISO639` enum
+  // `base::HashMetricName()` that maps this code to a `LocaleCodeBCP47` enum
   // value expected by this histogram. See tools/metrics/histograms/enums.xml
-  // enum LocaleCodeISO639. The enum there doesn't always have locales where
+  // enum LocaleCodeBCP47. The enum there doesn't always have locales where
   // the base lang and the locale are the same (e.g. they don't have id-id, but
   // do have id). So if the base lang and the locale are the same, just use the
   // base lang.
diff --git a/services/webnn/tflite/graph_builder_tflite.cc b/services/webnn/tflite/graph_builder_tflite.cc
index 638bbfab..2d233335 100644
--- a/services/webnn/tflite/graph_builder_tflite.cc
+++ b/services/webnn/tflite/graph_builder_tflite.cc
@@ -18,6 +18,7 @@
 #include "base/command_line.h"
 #include "base/containers/fixed_flat_set.h"
 #include "base/containers/span.h"
+#include "base/feature_list.h"
 #include "base/numerics/checked_math.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/stringprintf.h"
@@ -42,6 +43,12 @@
 
 namespace {
 
+// This feature flag allows us to compare performance between fused vs unfused
+// quantized graphs.
+BASE_FEATURE(kApplyQDQFusion,
+             "ApplyQDQFusion",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 // The version number of the Schema. Ideally all changes will be backward
 // compatible. If that ever changes, we must ensure that version is the first
 // entry in the new tflite root so that we can see that version is not 1.
@@ -998,7 +1005,8 @@
       // is needed for a subsequent operation. During `SerializeInputTensorInfo`
       // for subsequent operations, it will check whether it needs to inject
       // a dequantize operation.
-      if (TrySerializeQuantizedInput(operation, operation_index)) {
+      if (base::FeatureList::IsEnabled(kApplyQDQFusion) &&
+          TrySerializeQuantizedInput(operation, operation_index)) {
         return base::ok();
       }
       ASSIGN_OR_RETURN(operator_offset, SerializeDequantizeLinear(operation));
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index d6a9586d..5c525bf 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -84,6 +84,54 @@
     ]
   },
   "android-builder-perf-pgo": {},
+  "android-byra-perf": {
+    "isolated_scripts": [
+      {
+        "args": [
+          "-v",
+          "-v",
+          "--browser=android-trichrome-chrome-google-64-32-bundle",
+          "--upload-results",
+          "--test-shard-map-filename=android-byra-perf_map.json",
+          "--ignore-benchmark-exit-code"
+        ],
+        "merge": {
+          "script": "//tools/perf/process_perf_results.py"
+        },
+        "name": "performance_test_suite_android_trichrome_chrome_google_64_32_bundle",
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimensions": {
+            "dut_state": "ready",
+            "label-board": "byra",
+            "label-pool": "chrome.tests.perf",
+            "os": "Android",
+            "pool": "chrome"
+          },
+          "expiration": 7200,
+          "hard_timeout": 14400,
+          "io_timeout": 21600,
+          "realm": "chromeos:chrome",
+          "server": "https://chromeos-swarming.appspot.com",
+          "service_account": "chromeos-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 7
+        },
+        "test": "performance_test_suite_android_trichrome_chrome_google_64_32_bundle",
+        "trigger_script": {
+          "args": [
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "requires_simultaneous_shard_dispatch": true,
+          "script": "//testing/trigger_scripts/perf_device_trigger.py"
+        }
+      }
+    ]
+  },
+  "android-desktop-x64-builder-perf": {},
   "android-go-processor-perf": {},
   "android-go-wembley-perf": {
     "isolated_scripts": [
diff --git a/testing/buildbot/chromium.perf.pinpoint.json b/testing/buildbot/chromium.perf.pinpoint.json
index e33ee65..306f3368 100644
--- a/testing/buildbot/chromium.perf.pinpoint.json
+++ b/testing/buildbot/chromium.perf.pinpoint.json
@@ -3,6 +3,53 @@
   "AAAAA2 See //tools/perf/generate_perf_data to make changes": {},
   "android-builder-perf": {},
   "android-builder-perf-pgo": {},
+  "android-byra-perf": {
+    "isolated_scripts": [
+      {
+        "args": [
+          "-v",
+          "-v",
+          "--browser=android-trichrome-chrome-google-64-32-bundle",
+          "--upload-results",
+          "--test-shard-map-filename=android-byra-perf_map.json",
+          "--ignore-benchmark-exit-code"
+        ],
+        "merge": {
+          "script": "//tools/perf/process_perf_results.py"
+        },
+        "name": "performance_test_suite_android_trichrome_chrome_google_64_32_bundle",
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimensions": {
+            "dut_state": "ready",
+            "label-board": "byra",
+            "label-pool": "chrome.tests.perf",
+            "os": "Android",
+            "pool": "chrome"
+          },
+          "expiration": 7200,
+          "hard_timeout": 14400,
+          "io_timeout": 21600,
+          "realm": "chromeos:chrome",
+          "server": "https://chromeos-swarming.appspot.com",
+          "service_account": "chromeos-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 7
+        },
+        "test": "performance_test_suite_android_trichrome_chrome_google_64_32_bundle",
+        "trigger_script": {
+          "args": [
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "requires_simultaneous_shard_dispatch": true,
+          "script": "//testing/trigger_scripts/perf_device_trigger.py"
+        }
+      }
+    ]
+  },
   "android-go-processor-perf": {},
   "android-go-wembley-perf": {
     "isolated_scripts": [
diff --git a/testing/buildbot/filters/android.emulator_11.viz_unittests.filter b/testing/buildbot/filters/android.emulator_11.viz_unittests.filter
index 34a9e18f..e901cf45 100644
--- a/testing/buildbot/filters/android.emulator_11.viz_unittests.filter
+++ b/testing/buildbot/filters/android.emulator_11.viz_unittests.filter
@@ -2,3 +2,4 @@
 -SkiaOutputSurfaceImplTest.CopyOutputBitmapSupportedColorSpace
 -SkiaOutputSurfaceImplTest.CopyOutputBitmapUnsupportedColorSpace
 -SkiaOutputSurfaceImplTest.EndPaint
+-SkiaOutputSurfaceImplTest.EndPaintReleaseFence
diff --git a/testing/buildbot/filters/fuchsia.debug.viz_unittests.filter b/testing/buildbot/filters/fuchsia.debug.viz_unittests.filter
index 427b447..c129ddc 100644
--- a/testing/buildbot/filters/fuchsia.debug.viz_unittests.filter
+++ b/testing/buildbot/filters/fuchsia.debug.viz_unittests.filter
@@ -62,4 +62,5 @@
 -SkiaOutputSurfaceImplTest.CopyOutputBitmapSupportedColorSpace
 -SkiaOutputSurfaceImplTest.CopyOutputBitmapUnsupportedColorSpace
 -SkiaOutputSurfaceImplTest.EndPaint
+-SkiaOutputSurfaceImplTest.EndPaintReleaseFence
 -YUVReadbackTest.YUVReadbackOptTest
diff --git a/testing/buildbot/filters/ios.viz_unittests.filter b/testing/buildbot/filters/ios.viz_unittests.filter
index caf9e20f..4376c7a 100644
--- a/testing/buildbot/filters/ios.viz_unittests.filter
+++ b/testing/buildbot/filters/ios.viz_unittests.filter
@@ -31,8 +31,10 @@
 -VideoRendererPixelHiLoTest.SimpleYUVRect/1
 
 # These tests fail with perceptible pixel differences
--FromColorSpace/ColorTransformPixelTest.Basic/118
--FromColorSpace/ColorTransformPixelTest.Basic/119
+-FromColorSpace/ColorTransformPixelTest.Basic/SkiaGraphiteMetal_Hdr10_XyzD50Linear_premul
+-FromColorSpace/ColorTransformPixelTest.Basic/SkiaGraphiteMetal_Hdr10_XyzD50Linear_unpremul
+-FromColorSpace/ColorTransformPixelTest.Basic/SkiaGraphiteMetal_Hdr10_XyzD50SrgbHdr_premul
+-FromColorSpace/ColorTransformPixelTest.Basic/SkiaGraphiteMetal_Hdr10_XyzD50SrgbHdr_unpremul
 
 # Spot checking seems to show that the following fail with errors similar to:
 # dawn_context_provider.cc(448) First instance (1) must be zero.
@@ -77,26 +79,15 @@
 -IntersectingMultiplanarVideoQuadPixelTest.YUVVideoQuads/SkiaGL
 
 # TODO(crbug.com/337673256): These tests has been failing with happening in a
-# "suitable for blending" color space since https://crrev.com/c/5494389.
--ToColorSpace/ColorTransformPixelTest.Basic/78
--ToColorSpace/ColorTransformPixelTest.Basic/79
--ToColorSpace/ColorTransformPixelTest.Basic/94
--ToColorSpace/ColorTransformPixelTest.Basic/95
-
-# TODO(crbug.com/337673256): These tests has been failing with happening in a
 # "suitable for blending" color space since https://crrev.com/c/5478271.
--HdrVideoCases/ColorTransformPixelTest.Basic/52
--HdrVideoCases/ColorTransformPixelTest.Basic/54
--HdrVideoCases/ColorTransformPixelTest.Basic/56
--HdrVideoCases/ColorTransformPixelTest.Basic/57
--HdrVideoCases/ColorTransformPixelTest.Basic/58
--HdrVideoCases/ColorTransformPixelTest.Basic/59
--HdrVideoCases/ColorTransformPixelTest.Basic/60
--HdrVideoCases/ColorTransformPixelTest.Basic/61
--HdrVideoCases/ColorTransformPixelTest.Basic/62
--HdrVideoCases/ColorTransformPixelTest.Basic/63
--HdrVideoCases/ColorTransformPixelTest.Basic/68
--HdrVideoCases/ColorTransformPixelTest.Basic/70
+-HdrVideoCases/ColorTransformPixelTest.Basic/SkiaGraphiteMetal_Hdr10_ScrgbLinear80Nits_premul
+-HdrVideoCases/ColorTransformPixelTest.Basic/SkiaGraphiteMetal_Hdr10_ScrgbLinear80Nits_premul_ColorConversionInRenderer
+-HdrVideoCases/ColorTransformPixelTest.Basic/SkiaGraphiteMetal_Hdr10_ScrgbLinear80Nits_unpremul
+-HdrVideoCases/ColorTransformPixelTest.Basic/SkiaGraphiteMetal_Hdr10_ScrgbLinear80Nits_unpremul_ColorConversionInRenderer
+-HdrVideoCases/ColorTransformPixelTest.Basic/SkiaGraphiteMetal_Hdr10_Bt709SrgbHdr_premul
+-HdrVideoCases/ColorTransformPixelTest.Basic/SkiaGraphiteMetal_Hdr10_Bt709SrgbHdr_premul_ColorConversionInRenderer
+-HdrVideoCases/ColorTransformPixelTest.Basic/SkiaGraphiteMetal_Hdr10_Bt709SrgbHdr_unpremul
+-HdrVideoCases/ColorTransformPixelTest.Basic/SkiaGraphiteMetal_Hdr10_Bt709SrgbHdr_unpremul_ColorConversionInRenderer
 
 # TODO(crbug.com/358957649): These tests have been failing since
 # https://crrev.com/c/5683265.
diff --git a/testing/scripts/run_performance_tests.py b/testing/scripts/run_performance_tests.py
index 7cc7e2b3..06081cc 100755
--- a/testing/scripts/run_performance_tests.py
+++ b/testing/scripts/run_performance_tests.py
@@ -741,6 +741,7 @@
     self.options = options
     self.isolated_out_dir = isolated_out_dir
     self.network = self._get_network_arg(options.passthrough_args)
+    self.probe = self._get_probe_arg(options.passthrough_args)
     if self.options.luci_chromium:
       # In luci.chromium the Chrome and driver are in the user path.
       self.browser = '--browser=%s' % get_abs_user_path('chrome')
@@ -751,7 +752,7 @@
       browser_arg = _get_browser_arg(options.passthrough_args)
       self.is_android = _is_android(browser_arg)
       self._find_browser(browser_arg)
-      self.driver_path_arg = self._find_chromedriver(browser_arg)
+      self.driver_path_arg = self._find_chromedriver()
 
   def _get_network_arg(self, args):
     if _arg := _get_arg(args, '--network='):
@@ -772,6 +773,14 @@
       return self._create_fileserver_network(arg)
     return []
 
+  def _get_probe_arg(self, args):
+    if _arg := _get_arg(args, '--probe='):
+      return [_arg]
+    if self.options.benchmarks.startswith('motionmark'):
+      # Take a screenshot because of crbug.com/414806161.
+      return ['--probe=screenshot']
+    return []
+
   def _create_fileserver_network(self, arg):
     if '=' in arg:
       fileserver_path = arg.split('=', 1)[1]
@@ -828,15 +837,8 @@
       assert hasattr(possible_browser, 'local_executable')
       self.browser = self.CHROME_BROWSER % possible_browser.local_executable
 
-  def _find_chromedriver(self, browser_arg):
-    browser_arg = browser_arg.lower()
-    if browser_arg == 'release_x64':
-      path = '../Release_x64'
-    elif self.is_android:
-      path = 'clang_x64'
-    else:
-      path = '.'
-
+  def _find_chromedriver(self):
+    path = 'clang_x64' if self.is_android else '.'
     abspath = pathlib.Path(path).absolute()
     if ((driver_path := (abspath / 'chromedriver')).exists()
         or (driver_path := (abspath / 'chromedriver.exe')).exists()):
@@ -861,7 +863,7 @@
     return (['vpython3', '-Xutf8'] + [self.options.executable] + [benchmark] +
             ['--env-validation=throw'] + [self.OUTDIR % working_dir] +
             [self.browser] + benchmark_args + self.driver_path_arg +
-            self.network + self._get_default_args())
+            self.network + self.probe + self._get_default_args())
 
   def execute_benchmark(self,
                         benchmark,
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 5ed572b..34f157f 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -17237,30 +17237,6 @@
             ]
         }
     ],
-    "PreloadTopChromeWebUI": [
-        {
-            "platforms": [
-                "linux",
-                "mac",
-                "windows",
-                "chromeos"
-            ],
-            "experiments": [
-                {
-                    "name": "preload-on-warmup-delay",
-                    "params": {
-                        "delay-preload": "true",
-                        "exclude-origins": "chrome://bookmarks-side-panel.top-chrome",
-                        "preload-mode": "preload-on-warmup",
-                        "smart-preload": "true"
-                    },
-                    "enable_features": [
-                        "PreloadTopChromeWebUI"
-                    ]
-                }
-            ]
-        }
-    ],
     "PreloadingDeterministicViewportBasedPredictorAndroid": [
         {
             "platforms": [
@@ -22852,10 +22828,13 @@
             ],
             "experiments": [
                 {
-                    "name": "Enabled_20250423",
+                    "name": "Enabled_20250430",
                     "params": {
-                        "consecutive_computation_delay_sec": "5",
-                        "create_suggestions_promotion_ui": "false"
+                        "consecutive_computation_delay_sec": "0",
+                        "create_suggestions_promotion_ui": "false",
+                        "group_suggestion_enable_similar_source": "true",
+                        "group_suggestion_enable_switch_between": "true",
+                        "group_suggestion_trigger_calculation_on_page_load": "false"
                     },
                     "enable_features": [
                         "GroupSuggestionService"
diff --git a/third_party/angle b/third_party/angle
index e93c143..432d1d1 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit e93c143a91fc0fd9eb83baad4af26d39ab418b6a
+Subproject commit 432d1d1efdbd0e8d5788529fe193e0eb1e8456bf
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index b815108..1e8221a 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -11380,6 +11380,28 @@
       AttributionReportingEventLevelResult eventLevel
       AttributionReportingAggregatableResult aggregatable
 
+  experimental type AttributionReportingReportResult extends string
+    enum
+      # A network request was attempted for the report.
+      sent
+      # No request was attempted because of browser policy.
+      prohibited
+      # No request was attempted because of an error in report assembly,
+      # e.g. the aggregation service was unavailable.
+      failedToAssemble
+      # No request was attempted because the report's expiry passed.
+      expired
+
+  experimental event attributionReportingReportSent
+    parameters
+      string url
+      object body
+      AttributionReportingReportResult result
+      # If result is `sent`, populated with net/HTTP status.
+      optional integer netError
+      optional string netErrorName
+      optional integer httpStatusCode
+
   # A single Related Website Set object.
   experimental type RelatedWebsiteSet extends object
     properties
@@ -13385,6 +13407,12 @@
       subscribe-to-notifications
       unsubscribe-from-notifications
 
+  # Indicates the various types of descriptor operation.
+  type DescriptorOperationType extends string
+    enum
+      read
+      write
+
   # Stores the manufacturer data
   type ManufacturerData extends object
     properties
@@ -13481,6 +13509,18 @@
       integer code
       optional binary data
 
+  # Simulates the response from the descriptor with |descriptorId| for a
+  # descriptor operation of |type|. The |code| value follows the Error
+  # Codes from Bluetooth Core Specification Vol 3 Part F 3.4.1.1 Error Response.
+  # The |data| is expected to exist when simulating a successful read operation
+  # response.
+  command simulateDescriptorOperationResponse
+    parameters
+      string descriptorId
+      DescriptorOperationType type
+      integer code
+      optional binary data
+
   # Adds a service with |serviceUuid| to the peripheral with |address|.
   command addService
     parameters
@@ -13543,3 +13583,12 @@
       CharacteristicOperationType type
       optional binary data
       optional CharacteristicWriteType writeType
+
+  # Event for when a descriptor operation of |type| to the descriptor
+  # respresented by |descriptorId| happened. |data| is expected to exist when
+  # |type| is write.
+  event descriptorOperationReceived
+    parameters
+      string descriptorId
+      CharacteristicOperationType type
+      optional binary data
diff --git a/third_party/blink/public/platform/media/video_capture.h b/third_party/blink/public/platform/media/video_capture.h
index adfbb866..f4a2033 100644
--- a/third_party/blink/public/platform/media/video_capture.h
+++ b/third_party/blink/public/platform/media/video_capture.h
@@ -73,6 +73,22 @@
 using VideoCaptureStateUpdateCB =
     base::RepeatingCallback<void(VideoCaptureState)>;
 
+// VideoCaptureCallbacks is a struct that holds all the callbacks
+// needed for video capturer to deliver frames to the MediaStreamVideoTrack
+// for screen content capture, e.g. getDisplayMedia.
+// `deliver_frame_cb` is called when a new video frame is available.
+// `frame_dropped_cb` is called when a video frame is dropped.
+// `sub_capture_target_version_cb` is called when the sub-capture target
+// version is updated.
+// `state_update_cb` is called when the video capturer state is updated.
+// If capturing fails to start or stopped due to an external event then
+struct VideoCaptureCallbacks {
+  VideoCaptureDeliverFrameCB deliver_frame_cb;
+  VideoCaptureNotifyFrameDroppedCB frame_dropped_cb;
+  VideoCaptureSubCaptureTargetVersionCB sub_capture_target_version_cb;
+  VideoCaptureStateUpdateCB state_update_cb;
+};
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MEDIA_VIDEO_CAPTURE_H_
diff --git a/third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h b/third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h
index 90c20b34..9054127a 100644
--- a/third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h
+++ b/third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h
@@ -58,37 +58,35 @@
 
   // Start receiving video frames for the given session ID.
   //
-  // |state_update_cb| will be called on the IO thread when capturing
-  // state changes.
+  // |video_capture_callbacks.state_update_cb| will be called on the main thread
+  // when capturing state changes although the caller is on IO thread.
   // States will be one of the following four:
   // * VIDEO_CAPTURE_STATE_STARTED
   // * VIDEO_CAPTURE_STATE_STOPPED
   // * VIDEO_CAPTURE_STATE_PAUSED
   // * VIDEO_CAPTURE_STATE_ERROR
   //
-  // |deliver_frame_cb| will be called on the IO thread when a video
-  // frame is ready.
+  // |video_capture_callbacks.deliver_frame_cb| will be called on the IO thread
+  // when a video frame is ready.
   //
-  // |sub_capture_target_version_cb| will be called on the IO thread when a new
-  // crop version is successfully applied, and it is guaranteed that all
-  // subsequent frames delivered to |deliver_frame_cb|, will have this
+  // |video_capture_callbacks.sub_capture_target_version_cb| will be called on
+  // the IO thread when a new crop version is successfully applied, and it is
+  // guaranteed that all subsequent frames delivered to
+  // |video_capture_callbacks.deliver_frame_cb|, will have this
   // sub-capture-target version or later.
   //
-  // |frame_dropped_cb| will be called when a frame was dropped prior to
-  // delivery (i.e. |deliver_frame_cb| was not called for this frame).
-  //
+  // |video_capture_callbacks.frame_dropped_cb| will be called on the IO thread
+  // when a frame was dropped prior to delivery
+  // (i.e. |video_capture_callbacks,deliver_frame_cb| was not called for this
+  // frame).
+
   // Returns a callback that is used to stop capturing. Note that stopping
   // video capture is not synchronous. Client should handle the case where
   // callbacks are called after capturing is instructed to stop, typically
   // by binding the passed callbacks on a WeakPtr.
-  base::OnceClosure StartCapture(
-      const media::VideoCaptureSessionId& id,
-      const media::VideoCaptureParams& params,
-      const VideoCaptureStateUpdateCB& state_update_cb,
-      const VideoCaptureDeliverFrameCB& deliver_frame_cb,
-      const VideoCaptureSubCaptureTargetVersionCB&
-          sub_capture_target_version_cb,
-      const VideoCaptureNotifyFrameDroppedCB& frame_dropped_cb);
+  base::OnceClosure StartCapture(const media::VideoCaptureSessionId& id,
+                                 const media::VideoCaptureParams& params,
+                                 VideoCaptureCallbacks video_capture_callbacks);
 
   // Requests that the video capturer send a frame "soon" (e.g., to resolve
   // picture loss or quality issues).
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.cc b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
index 9e89b819..3d790b3 100644
--- a/third_party/blink/renderer/core/frame/frame_test_helpers.cc
+++ b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
@@ -1012,9 +1012,9 @@
   FlushInputHandlerTasks();
 }
 
-void TestWebFrameWidget::RequestDecode(
-    const cc::DrawImage&,
-    base::OnceCallback<void(bool)> callback) {
+void TestWebFrameWidget::RequestDecode(const cc::DrawImage&,
+                                       base::OnceCallback<void(bool)> callback,
+                                       bool speculative) {
   // TODO(paint-dev): probably this should `std::move(callback).Run(true)`, but
   // that could cause deep recursion into
   // ResourceFetcher::MaybeStartSpeculativeImageDecode(). Currently, nothing
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.h b/third_party/blink/renderer/core/frame/frame_test_helpers.h
index 1c491ce..4dc19ba 100644
--- a/third_party/blink/renderer/core/frame/frame_test_helpers.h
+++ b/third_party/blink/renderer/core/frame/frame_test_helpers.h
@@ -281,7 +281,8 @@
   }
 
   void RequestDecode(const cc::DrawImage&,
-                     base::OnceCallback<void(bool)>) override;
+                     base::OnceCallback<void(bool)>,
+                     bool speculative) override;
 
   using WebFrameWidgetImpl::GetOriginalScreenInfo;
 
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
index eb8ea71..4fdaa70 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -1598,11 +1598,11 @@
   return frame_widget_host_.get();
 }
 
-void WebFrameWidgetImpl::RequestDecode(
-    const cc::DrawImage& image,
-    base::OnceCallback<void(bool)> callback) {
+void WebFrameWidgetImpl::RequestDecode(const cc::DrawImage& image,
+                                       base::OnceCallback<void(bool)> callback,
+                                       bool speculative) {
   if (auto* layer_tree_host = widget_base_->LayerTreeHost()) {
-    layer_tree_host->QueueImageDecode(image, std::move(callback));
+    layer_tree_host->QueueImageDecode(image, std::move(callback), speculative);
   } else {
     std::move(callback).Run(false);
   }
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
index 994d30a..32633051 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
@@ -235,7 +235,8 @@
   void RequestAnimationAfterDelay(const base::TimeDelta&, bool urgent) final;
   void SetRootLayer(scoped_refptr<cc::Layer>) override;
   void RequestDecode(const cc::DrawImage&,
-                     base::OnceCallback<void(bool)>) override;
+                     base::OnceCallback<void(bool)>,
+                     bool speculative) override;
   void RequestBeginMainFrameNotExpected(bool request) final;
   int GetLayerTreeId() final;
   const cc::LayerTreeSettings* GetLayerTreeSettings() final;
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_test.cc b/third_party/blink/renderer/core/frame/web_frame_widget_test.cc
index cf97f21..0976cac7 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_test.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_test.cc
@@ -273,8 +273,10 @@
                     const cc::OverscrollBehavior& overscroll_behavior,
                     bool event_processed));
 
-  MOCK_METHOD2(RequestDecode,
-               void(const cc::DrawImage&, base::OnceCallback<void(bool)>));
+  MOCK_METHOD3(RequestDecode,
+               void(const cc::DrawImage&,
+                    base::OnceCallback<void(bool)>,
+                    bool));
 };
 
 class WebFrameWidgetImplSimTest : public SimTest {
@@ -568,7 +570,7 @@
   WebView().MainFrameViewWidget()->Resize(gfx::Size(800, 600));
   SimRequest doc_request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
-  EXPECT_CALL(*MockMainFrameWidget(), RequestDecode(_, _)).Times(1);
+  EXPECT_CALL(*MockMainFrameWidget(), RequestDecode(_, _, _)).Times(1);
   doc_request.Complete(
       R"HTML(
 <!DOCTYPE html>
@@ -590,7 +592,7 @@
   WebView().MainFrameViewWidget()->Resize(gfx::Size(800, 600));
   SimRequest doc_request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
-  EXPECT_CALL(*MockMainFrameWidget(), RequestDecode(_, _)).Times(0);
+  EXPECT_CALL(*MockMainFrameWidget(), RequestDecode(_, _, _)).Times(0);
   doc_request.Complete(
       R"HTML(
 <!DOCTYPE html>
@@ -614,7 +616,7 @@
   WebView().MainFrameViewWidget()->Resize(gfx::Size(800, 600));
   SimRequest doc_request("https://example.com/test.html", "text/html");
   LoadURL("https://example.com/test.html");
-  EXPECT_CALL(*MockMainFrameWidget(), RequestDecode(_, _)).Times(0);
+  EXPECT_CALL(*MockMainFrameWidget(), RequestDecode(_, _, _)).Times(0);
   doc_request.Complete(
       R"HTML(
 <!DOCTYPE html>
@@ -643,7 +645,7 @@
   LoadURL("https://example.com/test.html");
 
   {
-    EXPECT_CALL(*MockMainFrameWidget(), RequestDecode(_, _)).Times(0);
+    EXPECT_CALL(*MockMainFrameWidget(), RequestDecode(_, _, _)).Times(0);
     doc_request.Complete(
         R"HTML(<!DOCTYPE html>
         <img id="i1" src="image.png">
@@ -656,7 +658,7 @@
   }
 
   {
-    EXPECT_CALL(*MockMainFrameWidget(), RequestDecode(_, _)).Times(1);
+    EXPECT_CALL(*MockMainFrameWidget(), RequestDecode(_, _, _)).Times(1);
     widget->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
   }
 }
@@ -677,7 +679,7 @@
   LoadURL("https://example.com/test.html");
 
   {
-    EXPECT_CALL(*MockMainFrameWidget(), RequestDecode(_, _)).Times(1);
+    EXPECT_CALL(*MockMainFrameWidget(), RequestDecode(_, _, _)).Times(1);
     doc_request.Complete(
         R"HTML(<!DOCTYPE html>
         <img style="width: 100px" src="image.png">
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
index 2a3846e..c367c4d 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
@@ -137,9 +137,6 @@
     return canvas_rendering_type_ == CanvasRenderingAPI::kWebgl ||
            canvas_rendering_type_ == CanvasRenderingAPI::kWebgl2;
   }
-  bool IsWebGL2() const {
-    return canvas_rendering_type_ == CanvasRenderingAPI::kWebgl2;
-  }
   bool IsWebGPU() const {
     return canvas_rendering_type_ == CanvasRenderingAPI::kWebgpu;
   }
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index a9dba6f6..422b608 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -924,10 +924,23 @@
         static_cast<cc::PaintFlags::FilterQuality>(
             image_resource->GetContent()->MaxInterpolationQuality()),
         matrix, PaintImage::kDefaultFrameIndex);
+    auto paint_image_id = image->paint_image_id();
+    TRACE_EVENT_INSTANT2(
+        TRACE_DISABLED_BY_DEFAULT("loading"), "SpeculativeImageDecodeStarted",
+        TRACE_EVENT_SCOPE_THREAD, "url", resource->Url().GetString().Utf8(),
+        "image_id", paint_image_id);
     document_->GetFrame()->GetChromeClient().RequestDecode(
         document_->GetFrame(), draw_image,
-        WTF::BindOnce([](base::OnceClosure cb, bool) { std::move(cb).Run(); },
-                      std::move(callback)));
+        WTF::BindOnce(
+            [](base::OnceClosure cb, PaintImage::Id paint_image_id, bool) {
+              TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("loading"),
+                                   "SpeculativeImageDecodeFinished",
+                                   TRACE_EVENT_SCOPE_THREAD, "image_id",
+                                   paint_image_id);
+              std::move(cb).Run();
+            },
+            std::move(callback), paint_image_id),
+        /*speculative*/ true);
     return true;
   }
   return false;
diff --git a/third_party/blink/renderer/core/loader/image_loader.cc b/third_party/blink/renderer/core/loader/image_loader.cc
index 1d383a6..a6b7199 100644
--- a/third_party/blink/renderer/core/loader/image_loader.cc
+++ b/third_party/blink/renderer/core/loader/image_loader.cc
@@ -217,7 +217,8 @@
                      frame, draw_image,
                      WTF::BindOnce(&ImageLoader::DecodeRequestFinished,
                                    MakeUnwrappingCrossThreadHandle(this),
-                                   request->request_id()));
+                                   request->request_id()),
+                     /*speculative*/ false);
                  request->NotifyDecodeDispatched();
                  return false;
                }));
diff --git a/third_party/blink/renderer/core/page/chrome_client.h b/third_party/blink/renderer/core/page/chrome_client.h
index 0de68d03..87c96c7 100644
--- a/third_party/blink/renderer/core/page/chrome_client.h
+++ b/third_party/blink/renderer/core/page/chrome_client.h
@@ -563,7 +563,8 @@
 
   virtual void RequestDecode(LocalFrame*,
                              const cc::DrawImage& image,
-                             base::OnceCallback<void(bool)> callback) {
+                             base::OnceCallback<void(bool)> callback,
+                             bool speculative) {
     std::move(callback).Run(false);
   }
 
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.cc b/third_party/blink/renderer/core/page/chrome_client_impl.cc
index e3888bb3..44b0ad16 100644
--- a/third_party/blink/renderer/core/page/chrome_client_impl.cc
+++ b/third_party/blink/renderer/core/page/chrome_client_impl.cc
@@ -1073,9 +1073,10 @@
 
 void ChromeClientImpl::RequestDecode(LocalFrame* frame,
                                      const cc::DrawImage& image,
-                                     base::OnceCallback<void(bool)> callback) {
+                                     base::OnceCallback<void(bool)> callback,
+                                     bool speculative) {
   FrameWidget* widget = frame->GetWidgetForLocalRoot();
-  widget->RequestDecode(image, std::move(callback));
+  widget->RequestDecode(image, std::move(callback), speculative);
 }
 
 void ChromeClientImpl::NotifyPresentationTime(LocalFrame& frame,
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.h b/third_party/blink/renderer/core/page/chrome_client_impl.h
index 0eda15c..abf20cdce 100644
--- a/third_party/blink/renderer/core/page/chrome_client_impl.h
+++ b/third_party/blink/renderer/core/page/chrome_client_impl.h
@@ -297,7 +297,8 @@
 
   void RequestDecode(LocalFrame*,
                      const cc::DrawImage&,
-                     base::OnceCallback<void(bool)>) override;
+                     base::OnceCallback<void(bool)>,
+                     bool speculative) override;
 
   void NotifyPresentationTime(LocalFrame& frame,
                               ReportTimeCallback callback) override;
diff --git a/third_party/blink/renderer/core/web_test/web_test_web_frame_widget_impl.cc b/third_party/blink/renderer/core/web_test/web_test_web_frame_widget_impl.cc
index 4d64ea18..caffb504 100644
--- a/third_party/blink/renderer/core/web_test/web_test_web_frame_widget_impl.cc
+++ b/third_party/blink/renderer/core/web_test/web_test_web_frame_widget_impl.cc
@@ -346,8 +346,9 @@
 
 void WebTestWebFrameWidgetImpl::RequestDecode(
     const cc::DrawImage& image,
-    base::OnceCallback<void(bool)> callback) {
-  WebFrameWidgetImpl::RequestDecode(image, std::move(callback));
+    base::OnceCallback<void(bool)> callback,
+    bool speculative) {
+  WebFrameWidgetImpl::RequestDecode(image, std::move(callback), speculative);
 
   // In web tests the request does not actually cause a commit, because the
   // compositor is scheduled by the test runner to avoid flakiness. So for this
diff --git a/third_party/blink/renderer/core/web_test/web_test_web_frame_widget_impl.h b/third_party/blink/renderer/core/web_test/web_test_web_frame_widget_impl.h
index 02535e52..49b61dc 100644
--- a/third_party/blink/renderer/core/web_test/web_test_web_frame_widget_impl.h
+++ b/third_party/blink/renderer/core/web_test/web_test_web_frame_widget_impl.h
@@ -60,7 +60,8 @@
 
   // FrameWidget overrides.
   void RequestDecode(const cc::DrawImage&,
-                     base::OnceCallback<void(bool)>) override;
+                     base::OnceCallback<void(bool)>,
+                     bool speculative) override;
 
  private:
   // WebFrameWidgetImpl overrides.
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc
index 659864c0..e0c25ab 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc
@@ -62,16 +62,15 @@
     return formats;
   }
   void StartCapture(const media::VideoCaptureParams& params,
-                    const blink::VideoCaptureDeliverFrameCB& frame_callback,
-                    const VideoCaptureSubCaptureTargetVersionCB&
-                        sub_capture_target_version_callback,
-                    // Canvas capture does not report frame drops.
-                    const VideoCaptureNotifyFrameDroppedCB&,
-                    const RunningCallback& running_callback) override {
+                    VideoCaptureCallbacks video_capture_callbacks,
+                    VideoCapturerSource::VideoCaptureRunningCallbackCB
+                        running_callback) override {
     DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
+
     if (canvas_handler_.get()) {
-      canvas_handler_->StartVideoCapture(params, frame_callback,
-                                         running_callback);
+      canvas_handler_->StartVideoCapture(
+          params, std::move(video_capture_callbacks.deliver_frame_cb),
+          std::move(running_callback));
     }
   }
   void RequestRefreshFrame() override {
@@ -215,18 +214,18 @@
 
 void CanvasCaptureHandler::StartVideoCapture(
     const media::VideoCaptureParams& params,
-    const VideoCaptureDeliverFrameCB& new_frame_callback,
-    const VideoCapturerSource::RunningCallback& running_callback) {
+    VideoCaptureDeliverFrameCB new_frame_callback,
+    VideoCapturerSource::VideoCaptureRunningCallbackCB running_callback) {
   DVLOG(3) << __func__ << " requested "
            << media::VideoCaptureFormat::ToString(params.requested_format);
   DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
   DCHECK(params.requested_format.IsValid());
   capture_format_ = params.requested_format;
-  delegate_ =
-      std::make_unique<CanvasCaptureHandlerDelegate>(new_frame_callback);
+  delegate_ = std::make_unique<CanvasCaptureHandlerDelegate>(
+      std::move(new_frame_callback));
   DCHECK(delegate_);
   ask_for_new_frame_ = true;
-  running_callback.Run(RunState::kRunning);
+  running_callback.Run(VideoCaptureRunState::kRunning);
 }
 
 void CanvasCaptureHandler::RequestRefreshFrame() {
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.h b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.h
index 1f526f5..10c0df1 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.h
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.h
@@ -74,8 +74,8 @@
   // Functions called by VideoCapturerSource implementation.
   void StartVideoCapture(
       const media::VideoCaptureParams& params,
-      const VideoCaptureDeliverFrameCB& new_frame_callback,
-      const VideoCapturerSource::RunningCallback& running_callback);
+      VideoCaptureDeliverFrameCB new_frame_callback,
+      VideoCapturerSource::VideoCaptureRunningCallbackCB running_callback);
   void RequestRefreshFrame();
   void StopVideoCapture();
   void SetCanDiscardAlpha(bool can_discard_alpha) {
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler_unittest.cc b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler_unittest.cc
index 200aab8..79fff34a 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler_unittest.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler_unittest.cc
@@ -90,8 +90,9 @@
   }
 
   MOCK_METHOD1(DoOnRunning, void(bool));
-  void OnRunning(blink::RunState run_state) {
-    bool state = (run_state == blink::RunState::kRunning) ? true : false;
+  void OnRunning(blink::VideoCaptureRunState run_state) {
+    bool state =
+        (run_state == blink::VideoCaptureRunState::kRunning) ? true : false;
     DoOnRunning(state);
   }
 
@@ -213,14 +214,15 @@
   EXPECT_CALL(*this, DoOnDeliverFrame(_, _))
       .Times(1)
       .WillOnce(RunOnceClosure(std::move(quit_closure)));
-  source->StartCapture(
-      params,
-      base::BindRepeating(&CanvasCaptureHandlerTest::OnDeliverFrame,
-                          base::Unretained(this)),
-      /*sub_capture_target_version_callback=*/base::DoNothing(),
-      /*frame_dropped_callback=*/base::DoNothing(),
-      base::BindRepeating(&CanvasCaptureHandlerTest::OnRunning,
-                          base::Unretained(this)));
+
+  VideoCaptureCallbacks video_capture_callbacks;
+  video_capture_callbacks.deliver_frame_cb = base::BindRepeating(
+      &CanvasCaptureHandlerTest::OnDeliverFrame, base::Unretained(this));
+  video_capture_callbacks.frame_dropped_cb = base::DoNothing();
+  video_capture_callbacks.sub_capture_target_version_cb = base::DoNothing();
+  source->StartCapture(params, std::move(video_capture_callbacks),
+                       base::BindRepeating(&CanvasCaptureHandlerTest::OnRunning,
+                                           base::Unretained(this)));
   copier_->Convert(GenerateTestImage(testing::get<0>(GetParam()),
                                      testing::get<1>(GetParam()),
                                      testing::get<2>(GetParam())),
@@ -246,14 +248,15 @@
   base::RunLoop run_loop;
   EXPECT_CALL(*this, DoOnRunning(true)).Times(1);
   media::VideoCaptureParams params;
-  source->StartCapture(
-      params,
+  VideoCaptureCallbacks video_capture_callbacks;
+  video_capture_callbacks.deliver_frame_cb =
       base::BindRepeating(&CanvasCaptureHandlerTest::OnVerifyDeliveredFrame,
-                          base::Unretained(this), opaque_frame, width, height),
-      /*sub_capture_target_version_callback=*/base::DoNothing(),
-      /*frame_dropped_callback=*/base::DoNothing(),
-      base::BindRepeating(&CanvasCaptureHandlerTest::OnRunning,
-                          base::Unretained(this)));
+                          base::Unretained(this), opaque_frame, width, height);
+  video_capture_callbacks.frame_dropped_cb = base::DoNothing();
+  video_capture_callbacks.sub_capture_target_version_cb = base::DoNothing();
+  source->StartCapture(params, std::move(video_capture_callbacks),
+                       base::BindRepeating(&CanvasCaptureHandlerTest::OnRunning,
+                                           base::Unretained(this)));
   copier_->Convert(GenerateTestImage(opaque_frame, width, height),
                    canvas_capture_handler_->CanDiscardAlpha(),
                    /*context_provider=*/nullptr,
@@ -275,15 +278,15 @@
   EXPECT_CALL(*this, DoOnRunning(true)).Times(1);
   media::VideoCaptureParams params;
   source->SetCanDiscardAlpha(true);
-  source->StartCapture(
-      params,
-      base::BindRepeating(&CanvasCaptureHandlerTest::OnVerifyDeliveredFrame,
-                          base::Unretained(this), /*opaque_frame=*/true, width,
-                          height),
-      /*sub_capture_target_version_callback=*/base::DoNothing(),
-      /*frame_dropped_callback=*/base::DoNothing(),
-      base::BindRepeating(&CanvasCaptureHandlerTest::OnRunning,
-                          base::Unretained(this)));
+  VideoCaptureCallbacks video_capture_callbacks;
+  video_capture_callbacks.deliver_frame_cb = base::BindRepeating(
+      &CanvasCaptureHandlerTest::OnVerifyDeliveredFrame, base::Unretained(this),
+      /*opaque_frame=*/true, width, height);
+  video_capture_callbacks.frame_dropped_cb = base::DoNothing();
+  video_capture_callbacks.sub_capture_target_version_cb = base::DoNothing();
+  source->StartCapture(params, std::move(video_capture_callbacks),
+                       base::BindRepeating(&CanvasCaptureHandlerTest::OnRunning,
+                                           base::Unretained(this)));
   copier_->Convert(GenerateTestImage(/*opaque=*/false, width, height),
                    canvas_capture_handler_->CanDiscardAlpha(),
                    /*context_provider=*/nullptr,
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
index 0fa818b..18ed0d6 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
@@ -82,31 +82,28 @@
 
 void HtmlVideoElementCapturerSource::StartCapture(
     const media::VideoCaptureParams& params,
-    const VideoCaptureDeliverFrameCB& new_frame_callback,
-    const VideoCaptureSubCaptureTargetVersionCB&
-        sub_capture_target_version_callback,
-    // The HTML element does not report frame drops.
-    const VideoCaptureNotifyFrameDroppedCB&,
-    const RunningCallback& running_callback) {
+    VideoCaptureCallbacks video_capture_callbacks,
+    VideoCaptureRunningCallbackCB running_callback) {
   DVLOG(2) << __func__ << " requested "
            << media::VideoCaptureFormat::ToString(params.requested_format);
   DCHECK(params.requested_format.IsValid());
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  running_callback_ = running_callback;
+  running_callback_ = std::move(running_callback);
   if (!web_media_player_ || !web_media_player_->HasVideo()) {
-    running_callback_.Run(RunState::kStopped);
+    running_callback_.Run(VideoCaptureRunState::kStopped);
     return;
   }
 
-  new_frame_callback_ = new_frame_callback;
+  new_frame_callback_ = std::move(video_capture_callbacks.deliver_frame_cb);
+
   // Force |capture_frame_rate_| to be in between k{Min,Max}FramesPerSecond.
   capture_frame_rate_ =
       std::max(kMinFramesPerSecond,
                std::min(static_cast<float>(media::limits::kMaxFramesPerSecond),
                         params.requested_format.frame_rate));
 
-  running_callback_.Run(RunState::kRunning);
+  running_callback_.Run(VideoCaptureRunState::kRunning);
   task_runner_->PostTask(
       FROM_HERE, WTF::BindOnce(&HtmlVideoElementCapturerSource::sendNewFrame,
                                weak_factory_.GetWeakPtr()));
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.h b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.h
index 2d69ad8..526b34e 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.h
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.h
@@ -47,13 +47,9 @@
 
   // VideoCapturerSource Implementation.
   media::VideoCaptureFormats GetPreferredFormats() override;
-  void StartCapture(
-      const media::VideoCaptureParams& params,
-      const VideoCaptureDeliverFrameCB& new_frame_callback,
-      const VideoCaptureSubCaptureTargetVersionCB&
-          sub_capture_target_version_callback,
-      const VideoCaptureNotifyFrameDroppedCB& frame_dropped_callback,
-      const RunningCallback& running_callback) override;
+  void StartCapture(const media::VideoCaptureParams& params,
+                    VideoCaptureCallbacks video_capture_callbacks,
+                    VideoCaptureRunningCallbackCB running_callback) override;
   void StopCapture() override;
 
  private:
@@ -70,7 +66,7 @@
   const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
   // These three configuration items are passed on StartCapture();
-  RunningCallback running_callback_;
+  VideoCaptureRunningCallbackCB running_callback_;
   VideoCaptureDeliverFrameCB new_frame_callback_;
   double capture_frame_rate_;
 
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
index f9060bf..c776e717 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
@@ -22,6 +22,7 @@
 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/blink/public/platform/web_media_player.h"
 #include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.h"
 #include "third_party/blink/renderer/platform/testing/task_environment.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
@@ -149,8 +150,9 @@
   }
 
   MOCK_METHOD1(DoOnRunning, void(bool));
-  void OnRunning(blink::RunState run_state) {
-    bool state = (run_state == blink::RunState::kRunning) ? true : false;
+  void OnRunning(blink::VideoCaptureRunState run_state) {
+    bool state =
+        (run_state == blink::VideoCaptureRunState::kRunning) ? true : false;
     DoOnRunning(state);
   }
 
@@ -176,13 +178,16 @@
   web_media_player_.reset();
   EXPECT_CALL(*this, DoOnRunning(false)).Times(1);
 
-  html_video_capturer_->StartCapture(
-      media::VideoCaptureParams(),
+  VideoCaptureCallbacks video_capture_callbacks;
+  video_capture_callbacks.deliver_frame_cb =
       WTF::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnDeliverFrame,
-                         base::Unretained(this)),
-      base::DoNothing(), base::DoNothing(),
-      WTF::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnRunning,
-                         base::Unretained(this)));
+                         base::Unretained(this));
+  video_capture_callbacks.frame_dropped_cb = base::DoNothing();
+  video_capture_callbacks.sub_capture_target_version_cb = base::DoNothing();
+  html_video_capturer_->StartCapture(
+      media::VideoCaptureParams(), std::move(video_capture_callbacks),
+      base::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnRunning,
+                          base::Unretained(this)));
 }
 
 // Checks that the usual sequence of GetPreferredFormats() ->
@@ -213,13 +218,15 @@
       .WillOnce(DoAll(SaveArg<0>(&second_frame),
                       RunOnceClosure(std::move(quit_closure))));
 
-  html_video_capturer_->StartCapture(
-      params,
+  VideoCaptureCallbacks video_capture_callbacks;
+  video_capture_callbacks.deliver_frame_cb =
       WTF::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnDeliverFrame,
-                         base::Unretained(this)),
-      base::DoNothing(), base::DoNothing(),
-      WTF::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnRunning,
-                         base::Unretained(this)));
+                         base::Unretained(this));
+  video_capture_callbacks.frame_dropped_cb = base::DoNothing();
+  html_video_capturer_->StartCapture(
+      media::VideoCaptureParams(), std::move(video_capture_callbacks),
+      base::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnRunning,
+                          base::Unretained(this)));
 
   run_loop.Run();
 
@@ -255,13 +262,16 @@
   EXPECT_CALL(*this, DoOnRunning(true));
   EXPECT_CALL(*this, DoOnDeliverFrame(_, _)).Times(0);
 
-  html_video_capturer_->StartCapture(
-      params,
+  VideoCaptureCallbacks video_capture_callbacks;
+  video_capture_callbacks.deliver_frame_cb =
       WTF::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnDeliverFrame,
-                         base::Unretained(this)),
-      base::DoNothing(), base::DoNothing(),
-      WTF::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnRunning,
-                         base::Unretained(this)));
+                         base::Unretained(this));
+  video_capture_callbacks.frame_dropped_cb = base::DoNothing();
+  video_capture_callbacks.sub_capture_target_version_cb = base::DoNothing();
+  html_video_capturer_->StartCapture(
+      media::VideoCaptureParams(), std::move(video_capture_callbacks),
+      base::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnRunning,
+                          base::Unretained(this)));
   html_video_capturer_->StopCapture();
   base::RunLoop().RunUntilIdle();
 
@@ -287,13 +297,16 @@
     EXPECT_CALL(*this, DoOnDeliverFrame(_, _))
         .WillOnce(
             DoAll(SaveArg<0>(&frame), RunOnceClosure(std::move(quit_closure))));
-    html_video_capturer_->StartCapture(
-        params,
+    VideoCaptureCallbacks video_capture_callbacks;
+    video_capture_callbacks.deliver_frame_cb =
         WTF::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnDeliverFrame,
-                           base::Unretained(this)),
-        base::DoNothing(), base::DoNothing(),
-        WTF::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnRunning,
-                           base::Unretained(this)));
+                           base::Unretained(this));
+    video_capture_callbacks.frame_dropped_cb = base::DoNothing();
+    video_capture_callbacks.sub_capture_target_version_cb = base::DoNothing();
+    html_video_capturer_->StartCapture(
+        media::VideoCaptureParams(), std::move(video_capture_callbacks),
+        base::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnRunning,
+                            base::Unretained(this)));
     run_loop.Run();
 
     EXPECT_EQ(media::PIXEL_FORMAT_I420A, frame->format());
@@ -349,13 +362,17 @@
     EXPECT_CALL(*this, DoOnDeliverFrame(_, _))
         .WillOnce(
             DoAll(SaveArg<0>(&frame), RunOnceClosure(std::move(quit_closure))));
-    html_video_capturer_->StartCapture(
-        params,
+
+    VideoCaptureCallbacks video_capture_callbacks;
+    video_capture_callbacks.deliver_frame_cb =
         WTF::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnDeliverFrame,
-                           base::Unretained(this)),
-        base::DoNothing(), base::DoNothing(),
-        WTF::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnRunning,
-                           base::Unretained(this)));
+                           base::Unretained(this));
+    video_capture_callbacks.frame_dropped_cb = base::DoNothing();
+    video_capture_callbacks.sub_capture_target_version_cb = base::DoNothing();
+    html_video_capturer_->StartCapture(
+        media::VideoCaptureParams(), std::move(video_capture_callbacks),
+        base::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnRunning,
+                            base::Unretained(this)));
     run_loop.Run();
   }
   {
@@ -392,13 +409,16 @@
 
   // No frames should be delivered.
   EXPECT_CALL(*this, DoOnDeliverFrame(_, _)).Times(0);
-  html_video_capturer_->StartCapture(
-      params,
+  VideoCaptureCallbacks video_capture_callbacks;
+  video_capture_callbacks.deliver_frame_cb =
       WTF::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnDeliverFrame,
-                         base::Unretained(this)),
-      base::DoNothing(), base::DoNothing(),
-      WTF::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnRunning,
-                         base::Unretained(this)));
+                         base::Unretained(this));
+  video_capture_callbacks.frame_dropped_cb = base::DoNothing();
+  video_capture_callbacks.sub_capture_target_version_cb = base::DoNothing();
+  html_video_capturer_->StartCapture(
+      media::VideoCaptureParams(), std::move(video_capture_callbacks),
+      base::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnRunning,
+                          base::Unretained(this)));
 
   // Wait for frames to be potentially sent in a follow-up task.
   base::RunLoop().RunUntilIdle();
diff --git a/third_party/blink/renderer/modules/mediastream/local_video_capturer_source.cc b/third_party/blink/renderer/modules/mediastream/local_video_capturer_source.cc
index 46dee3a..623afc7e 100644
--- a/third_party/blink/renderer/modules/mediastream/local_video_capturer_source.cc
+++ b/third_party/blink/renderer/modules/mediastream/local_video_capturer_source.cc
@@ -15,6 +15,7 @@
 #include "third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_copier_base.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
@@ -44,23 +45,26 @@
 
 void LocalVideoCapturerSource::StartCapture(
     const media::VideoCaptureParams& params,
-    const VideoCaptureDeliverFrameCB& new_frame_callback,
-    const VideoCaptureSubCaptureTargetVersionCB&
-        sub_capture_target_version_callback,
-    const VideoCaptureNotifyFrameDroppedCB& frame_dropped_callback,
-    const RunningCallback& running_callback) {
+    VideoCaptureCallbacks video_capture_callbacks,
+    VideoCaptureRunningCallbackCB running_callback) {
   DCHECK(params.requested_format.IsValid());
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  running_callback_ = running_callback;
+  running_callback_ = std::move(running_callback);
 
+  // Combine all callbacks into MediaStreamVideoSourceCallbacks structure
+  VideoCaptureCallbacks new_video_capture_callbacks;
+  new_video_capture_callbacks.state_update_cb = base::BindPostTask(
+      task_runner_, ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
+                        &LocalVideoCapturerSource::OnStateUpdate,
+                        weak_factory_.GetWeakPtr())));
+  new_video_capture_callbacks.deliver_frame_cb =
+      std::move(video_capture_callbacks.deliver_frame_cb);
+  new_video_capture_callbacks.sub_capture_target_version_cb =
+      std::move(video_capture_callbacks.sub_capture_target_version_cb);
+  new_video_capture_callbacks.frame_dropped_cb =
+      std::move(video_capture_callbacks.frame_dropped_cb);
   stop_capture_cb_ = manager_->StartCapture(
-      session_id_, params,
-      base::BindPostTask(
-          task_runner_, ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
-                            &LocalVideoCapturerSource::OnStateUpdate,
-                            weak_factory_.GetWeakPtr()))),
-      new_frame_callback, sub_capture_target_version_callback,
-      frame_dropped_callback);
+      session_id_, params, std::move(new_video_capture_callbacks));
 }
 
 media::VideoCaptureFeedbackCB LocalVideoCapturerSource::GetFeedbackCallback()
@@ -103,19 +107,19 @@
     OnLog("LocalVideoCapturerSource::OnStateUpdate discarding state update.");
     return;
   }
-  RunState run_state;
+  VideoCaptureRunState run_state;
   switch (state) {
     case VIDEO_CAPTURE_STATE_ERROR_SYSTEM_PERMISSIONS_DENIED:
-      run_state = RunState::kSystemPermissionsError;
+      run_state = VideoCaptureRunState::kSystemPermissionsError;
       break;
     case VIDEO_CAPTURE_STATE_ERROR_CAMERA_BUSY:
-      run_state = RunState::kCameraBusyError;
+      run_state = VideoCaptureRunState::kCameraBusyError;
       break;
     case VIDEO_CAPTURE_STATE_ERROR_START_TIMEOUT:
-      run_state = RunState::kStartTimeoutError;
+      run_state = VideoCaptureRunState::kStartTimeoutError;
       break;
     default:
-      run_state = RunState::kStopped;
+      run_state = VideoCaptureRunState::kStopped;
   }
 
   auto* frame = LocalFrame::FromFrameToken(frame_token_);
@@ -124,7 +128,7 @@
       OnLog(
           "LocalVideoCapturerSource::OnStateUpdate signaling to "
           "consumer that source is now running.");
-      running_callback_.Run(RunState::kRunning);
+      running_callback_.Run(VideoCaptureRunState::kRunning);
       break;
 
     case VIDEO_CAPTURE_STATE_STOPPING:
diff --git a/third_party/blink/renderer/modules/mediastream/local_video_capturer_source.h b/third_party/blink/renderer/modules/mediastream/local_video_capturer_source.h
index 40f7e47..db323323 100644
--- a/third_party/blink/renderer/modules/mediastream/local_video_capturer_source.h
+++ b/third_party/blink/renderer/modules/mediastream/local_video_capturer_source.h
@@ -53,13 +53,9 @@
 
   // VideoCaptureSource Implementation.
   media::VideoCaptureFormats GetPreferredFormats() override;
-  void StartCapture(
-      const media::VideoCaptureParams& params,
-      const VideoCaptureDeliverFrameCB& new_frame_callback,
-      const VideoCaptureSubCaptureTargetVersionCB&
-          sub_capture_target_version_callback,
-      const VideoCaptureNotifyFrameDroppedCB& frame_dropped_callback,
-      const RunningCallback& running_callback) override;
+  void StartCapture(const media::VideoCaptureParams& params,
+                    VideoCaptureCallbacks video_capture_callbacks,
+                    VideoCaptureRunningCallbackCB running_callback) override;
   void RequestRefreshFrame() override;
   void MaybeSuspend() override;
   void Resume() override;
@@ -81,7 +77,7 @@
   // These two are valid between StartCapture() and StopCapture().
   // |running_call_back_| is run when capture is successfully started, and when
   // it is stopped or error happens.
-  RunningCallback running_callback_;
+  VideoCaptureRunningCallbackCB running_callback_;
   base::OnceClosure stop_capture_cb_;
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.cc
index 2e7c62a..dde7c17 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.cc
@@ -108,14 +108,23 @@
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   state_ = kStarting;
+
   frame_callback_ = media_stream_callbacks.deliver_frame_cb;
   sub_capture_target_version_callback_ =
       media_stream_callbacks.sub_capture_target_version_cb;
   frame_dropped_callback_ = media_stream_callbacks.frame_dropped_cb;
 
+  VideoCaptureCallbacks video_capture_callbacks;
+  video_capture_callbacks.deliver_frame_cb =
+      std::move(media_stream_callbacks.deliver_frame_cb);
+  video_capture_callbacks.sub_capture_target_version_cb =
+      std::move(media_stream_callbacks.sub_capture_target_version_cb);
+  video_capture_callbacks.frame_dropped_cb =
+      std::move(media_stream_callbacks.frame_dropped_cb);
+  video_capture_callbacks.state_update_cb =
+      std::move(media_stream_callbacks.state_update_cb);
   source_->StartCapture(
-      capture_params_, frame_callback_, sub_capture_target_version_callback_,
-      frame_dropped_callback_,
+      capture_params_, std::move(video_capture_callbacks),
       WTF::BindRepeating(&MediaStreamVideoCapturerSource::OnRunStateChanged,
                          weak_factory_.GetWeakPtr(), capture_params_));
 }
@@ -142,7 +151,7 @@
   // Force state update for nondevice sources, since they do not
   // automatically update state after StopCapture().
   if (device().type == mojom::blink::MediaStreamType::NO_SERVICE)
-    OnRunStateChanged(capture_params_, RunState::kStopped);
+    OnRunStateChanged(capture_params_, VideoCaptureRunState::kStopped);
 }
 
 void MediaStreamVideoCapturerSource::RestartSourceImpl(
@@ -152,9 +161,14 @@
   new_capture_params.requested_format = new_format;
   state_ = kRestarting;
 
+  VideoCaptureCallbacks video_capture_callbacks;
+  video_capture_callbacks.deliver_frame_cb = frame_callback_;
+  video_capture_callbacks.sub_capture_target_version_cb =
+      sub_capture_target_version_callback_;
+  video_capture_callbacks.frame_dropped_cb = frame_dropped_callback_;
+
   source_->StartCapture(
-      new_capture_params, frame_callback_, sub_capture_target_version_callback_,
-      frame_dropped_callback_,
+      new_capture_params, std::move(video_capture_callbacks),
       WTF::BindRepeating(&MediaStreamVideoCapturerSource::OnRunStateChanged,
                          weak_factory_.GetWeakPtr(), new_capture_params));
 }
@@ -183,9 +197,14 @@
   }
   SetDevice(new_device);
   source_ = device_capturer_factory_callback_.Run(new_device.session_id());
+
+  VideoCaptureCallbacks video_capture_callbacks;
+  video_capture_callbacks.deliver_frame_cb = frame_callback_;
+  video_capture_callbacks.sub_capture_target_version_cb =
+      sub_capture_target_version_callback_;
+  video_capture_callbacks.frame_dropped_cb = frame_dropped_callback_;
   source_->StartCapture(
-      capture_params_, frame_callback_, sub_capture_target_version_callback_,
-      frame_dropped_callback_,
+      capture_params_, std::move(video_capture_callbacks),
       WTF::BindRepeating(&MediaStreamVideoCapturerSource::OnRunStateChanged,
                          weak_factory_.GetWeakPtr(), capture_params_));
 }
@@ -230,9 +249,9 @@
 
 void MediaStreamVideoCapturerSource::OnRunStateChanged(
     const media::VideoCaptureParams& new_capture_params,
-    RunState run_state) {
+    VideoCaptureRunState run_state) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  bool is_running = (run_state == RunState::kRunning);
+  bool is_running = (run_state == VideoCaptureRunState::kRunning);
   switch (state_) {
     case kStarting:
       source_->OnLog("MediaStreamVideoCapturerSource sending OnStartDone");
@@ -244,13 +263,13 @@
         state_ = kStopped;
         MediaStreamRequestResult result;
         switch (run_state) {
-          case RunState::kSystemPermissionsError:
+          case VideoCaptureRunState::kSystemPermissionsError:
             result = MediaStreamRequestResult::SYSTEM_PERMISSION_DENIED;
             break;
-          case RunState::kCameraBusyError:
+          case VideoCaptureRunState::kCameraBusyError:
             result = MediaStreamRequestResult::DEVICE_IN_USE;
             break;
-          case RunState::kStartTimeoutError:
+          case VideoCaptureRunState::kStartTimeoutError:
             result = MediaStreamRequestResult::START_TIMEOUT;
             break;
           default:
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h
index bdb1a9b..0843c72c 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h
@@ -101,9 +101,10 @@
   uint32_t GetSubCaptureTargetVersion() const override;
   base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() override;
 
-  // Method to bind as RunningCallback in VideoCapturerSource::StartCapture().
+  // Method to bind as VideoCaptureRunningCallbackCB in
+  // VideoCapturerSource::StartCapture().
   void OnRunStateChanged(const media::VideoCaptureParams& new_capture_params,
-                         RunState run_state);
+                         VideoCaptureRunState run_state);
 
   mojom::blink::MediaStreamDispatcherHost* GetMediaStreamDispatcherHost();
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source_test.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source_test.cc
index 60da7897..8e15b27 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source_test.cc
@@ -143,7 +143,8 @@
     EXPECT_EQ(String(source.Id()), stream_source_id_);
   }
   void OnStarted(bool result) {
-    RunState run_state = result ? RunState::kRunning : RunState::kStopped;
+    VideoCaptureRunState run_state = result ? VideoCaptureRunState::kRunning
+                                            : VideoCaptureRunState::kStopped;
     video_capturer_source_->OnRunStateChanged(delegate_->capture_params(),
                                               run_state);
   }
@@ -157,7 +158,7 @@
     auto delegate = std::make_unique<MockVideoCapturerSource>();
     delegate_ = delegate.get();
     EXPECT_CALL(*delegate_, MockStartCapture(_, _, _))
-        .WillOnce(Return(RunState::kRunning));
+        .WillOnce(Return(VideoCaptureRunState::kRunning));
     return delegate;
   }
 
@@ -195,7 +196,7 @@
 
   // A bogus notification of running from the delegate when the source has
   // already started should not change the state.
-  delegate_->SetRunning(RunState::kRunning);
+  delegate_->SetRunning(VideoCaptureRunState::kRunning);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(MediaStreamSource::kReadyStateLive,
             stream_source_->GetReadyState());
@@ -204,7 +205,7 @@
 
   // If the delegate stops, the source should stop.
   EXPECT_CALL(mock_delegate(), MockStopCapture());
-  delegate_->SetRunning(RunState::kStopped);
+  delegate_->SetRunning(VideoCaptureRunState::kStopped);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(MediaStreamSource::kReadyStateEnded,
             stream_source_->GetReadyState());
@@ -215,18 +216,18 @@
 
 TEST_F(MediaStreamVideoCapturerSourceTest, CaptureTimeAndMetadataPlumbing) {
   VideoCaptureDeliverFrameCB deliver_frame_cb;
-  VideoCapturerSource::RunningCallback running_cb;
+  VideoCapturerSource::VideoCaptureRunningCallbackCB running_cb;
 
   InSequence s;
   EXPECT_CALL(mock_delegate(), MockStartCapture(_, _, _))
       .WillOnce(testing::DoAll(testing::SaveArg<1>(&deliver_frame_cb),
                                testing::SaveArg<2>(&running_cb),
-                               Return(RunState::kRunning)));
+                               Return(VideoCaptureRunState::kRunning)));
   EXPECT_CALL(mock_delegate(), RequestRefreshFrame());
   EXPECT_CALL(mock_delegate(), MockStopCapture());
   WebMediaStreamTrack track =
       StartSource(VideoTrackAdapterSettings(), std::nullopt, false, 0.0);
-  running_cb.Run(RunState::kRunning);
+  running_cb.Run(VideoCaptureRunState::kRunning);
 
   base::RunLoop run_loop;
   base::TimeTicks reference_capture_time =
@@ -252,7 +253,7 @@
 TEST_F(MediaStreamVideoCapturerSourceTest, Restart) {
   InSequence s;
   EXPECT_CALL(mock_delegate(), MockStartCapture(_, _, _))
-      .WillOnce(Return(RunState::kRunning));
+      .WillOnce(Return(VideoCaptureRunState::kRunning));
   WebMediaStreamTrack track =
       StartSource(VideoTrackAdapterSettings(), std::nullopt, false, 0.0);
   base::RunLoop().RunUntilIdle();
@@ -293,7 +294,7 @@
 
   // Restart the source. With the mock delegate, any video format will do.
   EXPECT_CALL(mock_delegate(), MockStartCapture(_, _, _))
-      .WillOnce(Return(RunState::kRunning));
+      .WillOnce(Return(VideoCaptureRunState::kRunning));
   EXPECT_FALSE(video_capturer_source_->IsRunning());
   video_capturer_source_->Restart(
       media::VideoCaptureFormat(),
@@ -322,7 +323,7 @@
   // An delegate stop should stop the source and change the track state to
   // "ended".
   EXPECT_CALL(mock_delegate(), MockStopCapture());
-  delegate_->SetRunning(RunState::kStopped);
+  delegate_->SetRunning(VideoCaptureRunState::kStopped);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(MediaStreamSource::kReadyStateEnded,
             stream_source_->GetReadyState());
@@ -335,7 +336,7 @@
 TEST_F(MediaStreamVideoCapturerSourceTest, StartStopAndNotify) {
   InSequence s;
   EXPECT_CALL(mock_delegate(), MockStartCapture(_, _, _))
-      .WillOnce(Return(RunState::kRunning));
+      .WillOnce(Return(VideoCaptureRunState::kRunning));
   WebMediaStreamTrack web_track =
       StartSource(VideoTrackAdapterSettings(), std::nullopt, false, 0.0);
   base::RunLoop().RunUntilIdle();
@@ -368,7 +369,7 @@
 TEST_F(MediaStreamVideoCapturerSourceTest, ChangeSource) {
   InSequence s;
   EXPECT_CALL(mock_delegate(), MockStartCapture(_, _, _))
-      .WillOnce(Return(RunState::kRunning));
+      .WillOnce(Return(VideoCaptureRunState::kRunning));
   WebMediaStreamTrack track =
       StartSource(VideoTrackAdapterSettings(), std::nullopt, false, 0.0);
   base::RunLoop().RunUntilIdle();
@@ -379,7 +380,7 @@
 
   // A bogus notification of running from the delegate when the source has
   // already started should not change the state.
-  delegate_->SetRunning(RunState::kRunning);
+  delegate_->SetRunning(VideoCaptureRunState::kRunning);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(MediaStreamSource::kReadyStateLive,
             stream_source_->GetReadyState());
@@ -398,7 +399,7 @@
 
   // If the delegate stops, the source should stop.
   EXPECT_CALL(mock_delegate(), MockStopCapture());
-  delegate_->SetRunning(RunState::kStopped);
+  delegate_->SetRunning(VideoCaptureRunState::kStopped);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(MediaStreamSource::kReadyStateEnded,
             stream_source_->GetReadyState());
@@ -410,7 +411,7 @@
 TEST_F(MediaStreamVideoCapturerSourceTest, FailStartSystemPermission) {
   InSequence s;
   EXPECT_CALL(mock_delegate(), MockStartCapture(_, _, _))
-      .WillOnce(Return(RunState::kSystemPermissionsError));
+      .WillOnce(Return(VideoCaptureRunState::kSystemPermissionsError));
   WebMediaStreamTrack track =
       StartSource(VideoTrackAdapterSettings(), std::nullopt, false, 0.0);
   base::RunLoop().RunUntilIdle();
@@ -421,7 +422,7 @@
 TEST_F(MediaStreamVideoCapturerSourceTest, FailStartCamInUse) {
   InSequence s;
   EXPECT_CALL(mock_delegate(), MockStartCapture(_, _, _))
-      .WillOnce(Return(RunState::kCameraBusyError));
+      .WillOnce(Return(VideoCaptureRunState::kCameraBusyError));
   WebMediaStreamTrack track =
       StartSource(VideoTrackAdapterSettings(), std::nullopt, false, 0.0);
   base::RunLoop().RunUntilIdle();
diff --git a/third_party/blink/renderer/modules/mediastream/mock_video_capturer_source.h b/third_party/blink/renderer/modules/mediastream/mock_video_capturer_source.h
index 61c206eb..bf9c3dec 100644
--- a/third_party/blink/renderer/modules/mediastream/mock_video_capturer_source.h
+++ b/third_party/blink/renderer/modules/mediastream/mock_video_capturer_source.h
@@ -20,27 +20,25 @@
 
   MOCK_METHOD0(RequestRefreshFrame, void());
   MOCK_METHOD0(GetPreferredFormats, media::VideoCaptureFormats());
-  MOCK_METHOD3(MockStartCapture,
-               RunState(const media::VideoCaptureParams& params,
-                        const VideoCaptureDeliverFrameCB& new_frame_callback,
-                        const RunningCallback& running_callback));
+  MOCK_METHOD3(
+      MockStartCapture,
+      VideoCaptureRunState(const media::VideoCaptureParams& params,
+                           VideoCaptureDeliverFrameCB new_frame_callback,
+                           VideoCaptureRunningCallbackCB running_callback));
   MOCK_METHOD0(MockStopCapture, void());
-  void StartCapture(
-      const media::VideoCaptureParams& params,
-      const VideoCaptureDeliverFrameCB& new_frame_callback,
-      const VideoCaptureSubCaptureTargetVersionCB&
-          sub_capture_target_version_callback,
-      const VideoCaptureNotifyFrameDroppedCB& frame_dropped_callback,
-      const RunningCallback& running_callback) override {
-    running_cb_ = running_callback;
+  void StartCapture(const media::VideoCaptureParams& params,
+                    VideoCaptureCallbacks video_capture_callbacks,
+                    VideoCaptureRunningCallbackCB running_callback) override {
+    running_cb_ = std::move(running_callback);
     capture_params_ = params;
 
-    RunState run_state =
-        MockStartCapture(params, new_frame_callback, running_callback);
+    VideoCaptureRunState run_state = MockStartCapture(
+        params, std::move(video_capture_callbacks.deliver_frame_cb),
+        running_cb_);
     SetRunning(run_state);
   }
   void StopCapture() override { MockStopCapture(); }
-  void SetRunning(RunState run_state) {
+  void SetRunning(VideoCaptureRunState run_state) {
     PostCrossThreadTask(*scheduler::GetSingleThreadTaskRunnerForTesting(),
                         FROM_HERE, CrossThreadBindOnce(running_cb_, run_state));
   }
@@ -49,7 +47,7 @@
   }
 
  private:
-  RunningCallback running_cb_;
+  VideoCaptureRunningCallbackCB running_cb_;
   media::VideoCaptureParams capture_params_;
 };
 
diff --git a/third_party/blink/renderer/modules/mediastream/video_track_adapter.h b/third_party/blink/renderer/modules/mediastream/video_track_adapter.h
index 911d5a7..ca06974e 100644
--- a/third_party/blink/renderer/modules/mediastream/video_track_adapter.h
+++ b/third_party/blink/renderer/modules/mediastream/video_track_adapter.h
@@ -151,7 +151,7 @@
       VideoCaptureSubCaptureTargetVersionInternalCallback
           sub_capture_target_version_callback,
       VideoTrackSettingsInternalCallback settings_callback,
-      VideoTrackFormatInternalCallback track_callback,
+      VideoTrackFormatInternalCallback format_callback,
       const VideoTrackAdapterSettings& settings);
 
   void RemoveTrackOnVideoTaskRunner(const MediaStreamVideoTrack* track);
diff --git a/third_party/blink/renderer/modules/webgl/BUILD.gn b/third_party/blink/renderer/modules/webgl/BUILD.gn
index 54d8f85..fcf44281 100644
--- a/third_party/blink/renderer/modules/webgl/BUILD.gn
+++ b/third_party/blink/renderer/modules/webgl/BUILD.gn
@@ -104,6 +104,8 @@
     "webgl_context_attribute_helpers.h",
     "webgl_context_event.cc",
     "webgl_context_event.h",
+    "webgl_context_object_support.cc",
+    "webgl_context_object_support.h",
     "webgl_debug_renderer_info.cc",
     "webgl_debug_renderer_info.h",
     "webgl_debug_shaders.cc",
diff --git a/third_party/blink/renderer/modules/webgl/webgl_buffer.cc b/third_party/blink/renderer/modules/webgl/webgl_buffer.cc
index a567d13..ef889b1 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_buffer.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_buffer.cc
@@ -26,13 +26,13 @@
 #include "third_party/blink/renderer/modules/webgl/webgl_buffer.h"
 
 #include "gpu/command_buffer/client/gles2_interface.h"
-#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_context_object_support.h"
 
 namespace blink {
 
-WebGLBuffer::WebGLBuffer(WebGLRenderingContextBase* ctx)
+WebGLBuffer::WebGLBuffer(WebGLContextObjectSupport* ctx)
     : WebGLObject(ctx), initial_target_(0), size_(0) {
-  if (!ctx->isContextLost()) {
+  if (!ctx->IsLost()) {
     GLuint buffer;
     ctx->ContextGL()->GenBuffers(1, &buffer);
     SetObject(buffer);
diff --git a/third_party/blink/renderer/modules/webgl/webgl_buffer.h b/third_party/blink/renderer/modules/webgl/webgl_buffer.h
index 2f195497..6c2611f 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_buffer.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_buffer.h
@@ -34,7 +34,7 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit WebGLBuffer(WebGLRenderingContextBase*);
+  explicit WebGLBuffer(WebGLContextObjectSupport*);
   ~WebGLBuffer() override;
 
   GLenum GetInitialTarget() const { return initial_target_; }
diff --git a/third_party/blink/renderer/modules/webgl/webgl_context_object_support.cc b/third_party/blink/renderer/modules/webgl/webgl_context_object_support.cc
new file mode 100644
index 0000000..6a3b14163
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgl/webgl_context_object_support.cc
@@ -0,0 +1,42 @@
+// 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 "third_party/blink/renderer/modules/webgl/webgl_context_object_support.h"
+
+namespace blink {
+
+scoped_refptr<base::SingleThreadTaskRunner>
+WebGLContextObjectSupport::GetContextTaskRunner() {
+  return task_runner_;
+}
+
+void WebGLContextObjectSupport::Trace(Visitor* visitor) const {
+  ScriptWrappable::Trace(visitor);
+}
+
+WebGLContextObjectSupport::WebGLContextObjectSupport(
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+    bool is_webgl2)
+    : task_runner_(std::move(task_runner)), is_webgl2_(is_webgl2) {}
+
+void WebGLContextObjectSupport::OnContextLost() {
+  DCHECK(!is_lost_);
+  number_of_context_losses_++;
+  is_lost_ = true;
+  gles2_interface_ = nullptr;
+  extensions_enabled_.reset();
+}
+
+void WebGLContextObjectSupport::OnContextRestored(
+    gpu::gles2::GLES2Interface* gl) {
+  DCHECK(is_lost_);
+  is_lost_ = false;
+  gles2_interface_ = gl;
+}
+
+void WebGLContextObjectSupport::MarkExtensionEnabled(WebGLExtensionName name) {
+  extensions_enabled_.set(name);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgl/webgl_context_object_support.h b/third_party/blink/renderer/modules/webgl/webgl_context_object_support.h
new file mode 100644
index 0000000..907866b
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgl/webgl_context_object_support.h
@@ -0,0 +1,75 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_CONTEXT_OBJECT_SUPPORT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_CONTEXT_OBJECT_SUPPORT_H_
+
+#include <bitset>
+
+#include "base/task/single_thread_task_runner.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_extension_name.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/khronos/GLES2/gl2.h"
+#include "third_party/khronos/GLES2/gl2ext.h"
+#include "third_party/khronos/GLES3/gl31.h"
+
+namespace gpu::gles2 {
+class GLES2Interface;
+}
+
+namespace blink {
+
+// Base classes for WebGL rendering contexts that contains all the information
+// needed by WebGLObject and child classes. This is used to avoid a dependency
+// on WebGLRenderingContextBase and keep logic and effects more local.
+class MODULES_EXPORT WebGLContextObjectSupport : public ScriptWrappable {
+ public:
+  // The GLES2Interface to use for the underlying GL context, it is nullptr when
+  // the context is lost.
+  gpu::gles2::GLES2Interface* ContextGL() const { return gles2_interface_; }
+
+  bool IsWebGL2() const { return is_webgl2_; }
+  bool IsLost() const { return is_lost_; }
+
+  // How many context losses there were, to check whether a WebGLObject was
+  // created since the last context resoration or before that (and hence invalid
+  // to use).
+  uint32_t NumberOfContextLosses() const { return number_of_context_losses_; }
+
+  bool ExtensionEnabled(WebGLExtensionName name) const {
+    return extensions_enabled_.test(name);
+  }
+
+  scoped_refptr<base::SingleThreadTaskRunner> GetContextTaskRunner();
+  void Trace(Visitor*) const override;
+
+ protected:
+  WebGLContextObjectSupport(
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+      bool is_webgl2);
+
+  // Must be called when the WebGL context is lost.
+  void OnContextLost();
+  // Must be called when the WebGL context is created or restored, also sets up
+  // the GLES2Interface that will be used for the duration that this context is
+  // active.
+  void OnContextRestored(gpu::gles2::GLES2Interface*);
+
+  void MarkExtensionEnabled(WebGLExtensionName name);
+
+ private:
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+  std::bitset<kWebGLExtensionNameCount> extensions_enabled_ = {};
+  raw_ptr<gpu::gles2::GLES2Interface> gles2_interface_ = nullptr;
+
+  uint32_t number_of_context_losses_ = 0;
+  bool is_lost_ = true;
+  bool is_webgl2_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_CONTEXT_OBJECT_SUPPORT_H_
diff --git a/third_party/blink/renderer/modules/webgl/webgl_fence_sync.cc b/third_party/blink/renderer/modules/webgl/webgl_fence_sync.cc
index 916e052..7611257 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_fence_sync.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_fence_sync.cc
@@ -5,12 +5,13 @@
 #include "third_party/blink/renderer/modules/webgl/webgl_fence_sync.h"
 
 #include <GLES2/gl2extchromium.h>
+
 #include "gpu/command_buffer/client/gles2_interface.h"
-#include "third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_context_object_support.h"
 
 namespace blink {
 
-WebGLFenceSync::WebGLFenceSync(WebGL2RenderingContextBase* ctx,
+WebGLFenceSync::WebGLFenceSync(WebGLContextObjectSupport* ctx,
                                GLenum condition,
                                GLbitfield flags)
     : WebGLSync(ctx, insertQuery(ctx), GL_SYNC_FENCE) {
@@ -18,7 +19,7 @@
   DCHECK_EQ(flags, 0u);
 }
 
-GLuint WebGLFenceSync::insertQuery(WebGL2RenderingContextBase* ctx) {
+GLuint WebGLFenceSync::insertQuery(WebGLContextObjectSupport* ctx) {
   GLuint query = 0;
   auto* gl = ctx->ContextGL();
   if (!gl) {
diff --git a/third_party/blink/renderer/modules/webgl/webgl_fence_sync.h b/third_party/blink/renderer/modules/webgl/webgl_fence_sync.h
index 63ba678f..5dc2bde 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_fence_sync.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_fence_sync.h
@@ -9,16 +9,14 @@
 
 namespace blink {
 
-class WebGL2RenderingContextBase;
-
 class WebGLFenceSync : public WebGLSync {
  public:
-  WebGLFenceSync(WebGL2RenderingContextBase*,
+  WebGLFenceSync(WebGLContextObjectSupport*,
                  GLenum condition,
                  GLbitfield flags);
 
  private:
-  GLuint insertQuery(WebGL2RenderingContextBase*);
+  GLuint insertQuery(WebGLContextObjectSupport*);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc b/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc
index 9b37698..597e9d20 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc
@@ -26,8 +26,8 @@
 #include "third_party/blink/renderer/modules/webgl/webgl_framebuffer.h"
 
 #include "gpu/command_buffer/client/gles2_interface.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_context_object_support.h"
 #include "third_party/blink/renderer/modules/webgl/webgl_renderbuffer.h"
-#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h"
 #include "third_party/blink/renderer/modules/webgl/webgl_texture.h"
 
 namespace blink {
@@ -196,7 +196,7 @@
 
 WebGLFramebuffer::WebGLAttachment::WebGLAttachment() = default;
 
-WebGLFramebuffer* WebGLFramebuffer::CreateOpaque(WebGLRenderingContextBase* ctx,
+WebGLFramebuffer* WebGLFramebuffer::CreateOpaque(WebGLContextObjectSupport* ctx,
                                                  bool has_depth,
                                                  bool has_stencil) {
   WebGLFramebuffer* const fb =
@@ -206,13 +206,13 @@
   return fb;
 }
 
-WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContextBase* ctx, bool opaque)
+WebGLFramebuffer::WebGLFramebuffer(WebGLContextObjectSupport* ctx, bool opaque)
     : WebGLObject(ctx),
       has_ever_been_bound_(false),
       web_gl1_depth_stencil_consistent_(true),
       opaque_(opaque),
       read_buffer_(GL_COLOR_ATTACHMENT0) {
-  if (!ctx->isContextLost()) {
+  if (!ctx->IsLost()) {
     GLuint fbo;
     ctx->ContextGL()->GenFramebuffers(1, &fbo);
     SetObject(fbo);
@@ -231,7 +231,7 @@
   DCHECK(HasObject());
   DCHECK(IsBound(target));
 
-  if (Context()->isContextLost()) {
+  if (Context()->IsLost()) {
     return;
   }
 
@@ -294,7 +294,7 @@
   DCHECK(HasObject());
   DCHECK(IsBound(target));
 
-  if (Context()->isContextLost()) {
+  if (Context()->IsLost()) {
     return;
   }
 
@@ -466,7 +466,7 @@
 void WebGLFramebuffer::DrawBuffersIfNecessary(bool force) {
   if (Context()->IsWebGL2() ||
       Context()->ExtensionEnabled(kWebGLDrawBuffersName)) {
-    if (Context()->isContextLost()) {
+    if (Context()->IsLost()) {
       return;
     }
 
@@ -541,7 +541,7 @@
 void WebGLFramebuffer::CommitWebGL1DepthStencilIfConsistent(GLenum target) {
   DCHECK(!Context()->IsWebGL2());
 
-  if (Context()->isContextLost()) {
+  if (Context()->IsLost()) {
     return;
   }
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_framebuffer.h b/third_party/blink/renderer/modules/webgl/webgl_framebuffer.h
index b56d82b..207801c 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_framebuffer.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_framebuffer.h
@@ -31,12 +31,6 @@
 #include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
-namespace gpu {
-namespace gles2 {
-class GLES2Interface;
-}
-}
-
 namespace blink {
 
 class WebGLRenderbuffer;
@@ -68,13 +62,13 @@
     WebGLAttachment();
   };
 
-  explicit WebGLFramebuffer(WebGLRenderingContextBase*, bool opaque = false);
+  explicit WebGLFramebuffer(WebGLContextObjectSupport*, bool opaque = false);
   ~WebGLFramebuffer() override;
 
   // An opaque framebuffer is one whose attachments are created and managed by
   // the browser and not inspectable or alterable via Javascript. This is
   // primarily used by the VRWebGLLayer interface.
-  static WebGLFramebuffer* CreateOpaque(WebGLRenderingContextBase*,
+  static WebGLFramebuffer* CreateOpaque(WebGLContextObjectSupport*,
                                         bool has_depth,
                                         bool has_stencil);
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_object.cc b/third_party/blink/renderer/modules/webgl/webgl_object.cc
index 3572ac3..9d984de 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_object.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_object.cc
@@ -27,11 +27,11 @@
 
 #include <limits>
 
-#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_context_object_support.h"
 
 namespace blink {
 
-WebGLObject::WebGLObject(WebGLRenderingContextBase* context)
+WebGLObject::WebGLObject(WebGLContextObjectSupport* context)
     : context_(context),
       cached_number_of_context_losses_(std::numeric_limits<uint32_t>::max()) {
   if (context_) {
@@ -41,7 +41,7 @@
 
 WebGLObject::~WebGLObject() = default;
 
-bool WebGLObject::Validate(const WebGLRenderingContextBase* context) const {
+bool WebGLObject::Validate(const WebGLContextObjectSupport* context) const {
   // The contexts and context groups no longer maintain references to all
   // the objects they ever created, so there's no way to invalidate them
   // eagerly during context loss. The invalidation is discovered lazily.
diff --git a/third_party/blink/renderer/modules/webgl/webgl_object.h b/third_party/blink/renderer/modules/webgl/webgl_object.h
index e2f3f4e0..37f0885 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_object.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_object.h
@@ -31,15 +31,13 @@
 #include "third_party/blink/renderer/platform/heap/prefinalizer.h"
 #include "third_party/khronos/GLES2/gl2.h"
 
-namespace gpu {
-namespace gles2 {
+namespace gpu::gles2 {
 class GLES2Interface;
 }
-}
 
 namespace blink {
 
-class WebGLRenderingContextBase;
+class WebGLContextObjectSupport;
 
 template <typename T>
 GLuint ObjectOrZero(const T* object) {
@@ -74,7 +72,7 @@
   // subclasses via Dispose().
   ~WebGLObject() override;
 
-  WebGLRenderingContextBase* Context() const { return context_.Get(); }
+  WebGLContextObjectSupport* Context() const { return context_.Get(); }
 
   // deleteObject may not always delete the OpenGL resource.  For programs and
   // shaders, deletion is delayed until they are no longer attached.
@@ -89,7 +87,7 @@
   bool MarkedForDeletion() { return marked_for_deletion_; }
 
   // True if this object belongs to the group or context.
-  bool Validate(const WebGLRenderingContextBase*) const;
+  bool Validate(const WebGLContextObjectSupport*) const;
 
   // A reference is returned so it can be made a pointer for glDelete* calls
   const GLuint& Object() const { return object_; }
@@ -101,7 +99,7 @@
   void Trace(Visitor*) const override;
 
  protected:
-  explicit WebGLObject(WebGLRenderingContextBase*);
+  explicit WebGLObject(WebGLContextObjectSupport*);
 
   // Must be called only once to set the GL object this JS wrapper wraps.
   void SetObject(GLuint object);
@@ -121,7 +119,7 @@
   bool DestructionInProgress() const;
 
  private:
-  Member<WebGLRenderingContextBase> context_;
+  Member<WebGLContextObjectSupport> context_;
 
   GLuint object_ = 0;
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_program.cc b/third_party/blink/renderer/modules/webgl/webgl_program.cc
index 0acc2d7..33698c3 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_program.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_program.cc
@@ -26,11 +26,12 @@
 #include "third_party/blink/renderer/modules/webgl/webgl_program.h"
 
 #include "gpu/command_buffer/client/gles2_interface.h"
-#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_context_object_support.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_shader.h"
 
 namespace blink {
 
-WebGLProgram::WebGLProgram(WebGLRenderingContextBase* ctx)
+WebGLProgram::WebGLProgram(WebGLContextObjectSupport* ctx)
     : WebGLObject(ctx),
       link_status_(false),
       link_count_(0),
@@ -38,7 +39,7 @@
       info_valid_(true),
       required_transform_feedback_buffer_count_(0),
       required_transform_feedback_buffer_count_after_next_link_(0) {
-  if (!ctx->isContextLost()) {
+  if (!ctx->IsLost()) {
     SetObject(ctx->ContextGL()->CreateProgram());
   }
 }
@@ -59,12 +60,12 @@
   }
 }
 
-bool WebGLProgram::LinkStatus(WebGLRenderingContextBase* context) {
+bool WebGLProgram::LinkStatus(WebGLContextObjectSupport* context) {
   CacheInfoIfNeeded(context);
   return link_status_;
 }
 
-bool WebGLProgram::CompletionStatus(WebGLRenderingContextBase* context) {
+bool WebGLProgram::CompletionStatus(WebGLContextObjectSupport* context) {
   GLint completed = 0;
   gpu::gles2::GLES2Interface* gl = context->ContextGL();
   // If gl is nullptr, context has been lost.
@@ -137,7 +138,7 @@
   }
 }
 
-void WebGLProgram::CacheInfoIfNeeded(WebGLRenderingContextBase* context) {
+void WebGLProgram::CacheInfoIfNeeded(WebGLContextObjectSupport* context) {
   if (info_valid_)
     return;
   if (!HasObject()) {
diff --git a/third_party/blink/renderer/modules/webgl/webgl_program.h b/third_party/blink/renderer/modules/webgl/webgl_program.h
index f49c5ba..d7926bf 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_program.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_program.h
@@ -27,21 +27,22 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_PROGRAM_H_
 
 #include "third_party/blink/renderer/modules/webgl/webgl_object.h"
-#include "third_party/blink/renderer/modules/webgl/webgl_shader.h"
 
 namespace blink {
 
+class WebGLShader;
+
 class WebGLProgram final : public WebGLObject {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit WebGLProgram(WebGLRenderingContextBase*);
+  explicit WebGLProgram(WebGLContextObjectSupport*);
   ~WebGLProgram() override;
 
-  bool LinkStatus(WebGLRenderingContextBase*);
+  bool LinkStatus(WebGLContextObjectSupport*);
   void setLinkStatus(bool link_status);
 
-  bool CompletionStatus(WebGLRenderingContextBase*);
+  bool CompletionStatus(WebGLContextObjectSupport*);
 
   unsigned LinkCount() const { return link_count_; }
 
@@ -61,7 +62,7 @@
     required_transform_feedback_buffer_count_after_next_link_ = count;
   }
   int GetRequiredTransformFeedbackBufferCount(
-      WebGLRenderingContextBase* context) {
+      WebGLContextObjectSupport* context) {
     CacheInfoIfNeeded(context);
     return required_transform_feedback_buffer_count_;
   }
@@ -76,7 +77,7 @@
   void DeleteObjectImpl(gpu::gles2::GLES2Interface*) override;
 
  private:
-  void CacheInfoIfNeeded(WebGLRenderingContextBase*);
+  void CacheInfoIfNeeded(WebGLContextObjectSupport*);
 
   GLint link_status_;
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_query.cc b/third_party/blink/renderer/modules/webgl/webgl_query.cc
index 161e09bd..6015992d 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_query.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_query.cc
@@ -7,19 +7,20 @@
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_context_object_support.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
 
 namespace blink {
 
-WebGLQuery::WebGLQuery(WebGL2RenderingContextBase* ctx)
+WebGLQuery::WebGLQuery(WebGLContextObjectSupport* ctx)
     : WebGLObject(ctx),
       target_(0),
       can_update_availability_(false),
       query_result_available_(false),
       query_result_(0),
       task_runner_(ctx->GetContextTaskRunner()) {
-  GLuint query;
-  if (!ctx->isContextLost()) {
+  if (!ctx->IsLost()) {
+    GLuint query;
     ctx->ContextGL()->GenQueriesEXT(1, &query);
     SetObject(query);
   }
diff --git a/third_party/blink/renderer/modules/webgl/webgl_query.h b/third_party/blink/renderer/modules/webgl/webgl_query.h
index bf4648e..f2ef7d9 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_query.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_query.h
@@ -9,21 +9,13 @@
 #include "third_party/blink/renderer/modules/webgl/webgl_object.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
 
-namespace gpu {
-namespace gles2 {
-class GLES2Interface;
-}
-}
-
 namespace blink {
 
-class WebGL2RenderingContextBase;
-
 class WebGLQuery : public WebGLObject {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit WebGLQuery(WebGL2RenderingContextBase*);
+  explicit WebGLQuery(WebGLContextObjectSupport*);
   ~WebGLQuery() override;
 
   void SetTarget(GLenum);
diff --git a/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.cc b/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.cc
index efca7fb..64b4273 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.cc
@@ -26,19 +26,19 @@
 #include "third_party/blink/renderer/modules/webgl/webgl_renderbuffer.h"
 
 #include "gpu/command_buffer/client/gles2_interface.h"
-#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_context_object_support.h"
 
 namespace blink {
 
-WebGLRenderbuffer::WebGLRenderbuffer(WebGLRenderingContextBase* ctx)
+WebGLRenderbuffer::WebGLRenderbuffer(WebGLContextObjectSupport* ctx)
     : WebGLObject(ctx),
       internal_format_(GL_RGBA4),
       width_(0),
       height_(0),
       is_multisampled_(false),
       has_ever_been_bound_(false) {
-  GLuint rbo;
-  if (!ctx->isContextLost()) {
+  if (!ctx->IsLost()) {
+    GLuint rbo;
     ctx->ContextGL()->GenRenderbuffers(1, &rbo);
     SetObject(rbo);
   }
diff --git a/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.h b/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.h
index 8f07e376..5b338b4 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.h
@@ -34,7 +34,7 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit WebGLRenderbuffer(WebGLRenderingContextBase*);
+  explicit WebGLRenderbuffer(WebGLContextObjectSupport*);
   ~WebGLRenderbuffer() override;
 
   void SetInternalFormat(GLenum internalformat) {
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index 1ef7fa4..2939586c 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -1258,7 +1258,10 @@
     const Platform::GraphicsInfo& graphics_info,
     const CanvasContextCreationAttributesCore& requested_attributes,
     Platform::ContextType context_type)
-    : CanvasRenderingContext(host,
+    : WebGLContextObjectSupport(
+          task_runner,
+          /* is_webgl2 */ context_type == Platform::kWebGL2ContextType),
+      CanvasRenderingContext(host,
                              requested_attributes,
                              context_type == Platform::kWebGL2ContextType
                                  ? CanvasRenderingAPI::kWebgl2
@@ -1270,7 +1273,6 @@
       restore_timer_(task_runner,
                      this,
                      &WebGLRenderingContextBase::MaybeRestoreContext),
-      task_runner_(task_runner),
       num_gl_errors_to_console_allowed_(kMaxGLErrorsAllowedToConsole),
       context_type_(context_type),
       number_of_user_allocated_multisampled_renderbuffers_(0) {
@@ -1292,6 +1294,7 @@
 
   drawing_buffer_ = std::move(buffer);
   GetDrawingBuffer()->Bind(GL_FRAMEBUFFER);
+  WebGLContextObjectSupport::OnContextRestored(drawing_buffer_->ContextGL());
   SetupFlags();
 
   String disabled_webgl_extensions(GetDrawingBuffer()
@@ -1471,9 +1474,6 @@
   // mistakenly identified as the "least recently used" context.
   ContextGL()->Flush();
 
-  for (int i = 0; i < kWebGLExtensionNameCount; ++i)
-    extension_enabled_[i] = false;
-
   // This limits the count of threads if the extension is yet to be requested.
   if (String(ContextGL()->GetString(GL_EXTENSIONS))
           .Contains("GL_KHR_parallel_shader_compile")) {
@@ -1593,6 +1593,10 @@
 
   extensions_util_.reset();
 
+  // Invalidate all objects associated with this version of the context (new
+  // objects can be created after context restoration).
+  WebGLContextObjectSupport::OnContextLost();
+
   base::RepeatingClosure null_closure;
   base::RepeatingCallback<void(const char*, int32_t)> null_function;
   GetDrawingBuffer()->ContextProvider()->SetLostContextCallback(
@@ -1642,11 +1646,6 @@
   }
 }
 
-scoped_refptr<base::SingleThreadTaskRunner>
-WebGLRenderingContextBase::GetContextTaskRunner() {
-  return task_runner_;
-}
-
 bool WebGLRenderingContextBase::PushFrame() {
   TRACE_EVENT0("blink", "WebGLRenderingContextBase::PushFrame");
   DCHECK(Host());
@@ -3434,25 +3433,25 @@
 
 WebGLExtension* WebGLRenderingContextBase::EnableExtensionIfSupported(
     const String& name) {
-  WebGLExtension* extension = nullptr;
-
-  if (!isContextLost()) {
-    for (ExtensionTracker* tracker : extensions_) {
-      if (tracker->MatchesName(name)) {
-        if (ExtensionSupportedAndAllowed(tracker)) {
-          extension = tracker->GetExtension(this);
-          if (extension) {
-            if (!extension_enabled_[extension->GetName()]) {
-              extension_enabled_[extension->GetName()] = true;
-            }
-          }
-        }
-        break;
-      }
-    }
+  if (isContextLost()) {
+    return nullptr;
   }
 
-  return extension;
+  for (ExtensionTracker* tracker : extensions_) {
+    if (!tracker->MatchesName(name) || !ExtensionSupportedAndAllowed(tracker)) {
+      continue;
+    }
+
+    WebGLExtension* extension = tracker->GetExtension(this);
+    if (!extension) {
+      continue;
+    }
+
+    MarkExtensionEnabled(extension->GetName());
+    return extension;
+  }
+
+  return nullptr;
 }
 
 bool WebGLRenderingContextBase::TimerQueryExtensionsEnabled() {
@@ -7118,17 +7117,6 @@
     return;
   }
 
-  LoseContextImpl(mode, auto_recovery_method);
-}
-
-void WebGLRenderingContextBase::LoseContextImpl(
-    WebGLRenderingContextBase::LostContextMode mode,
-    AutoRecoveryMethod auto_recovery_method) {
-  number_of_context_losses_++;
-
-  if (isContextLost())
-    return;
-
   context_lost_mode_ = mode;
   DCHECK_NE(context_lost_mode_, kNotLostContext);
   auto_recovery_method_ = auto_recovery_method;
@@ -7138,9 +7126,6 @@
     tracker->LoseExtension(false);
   }
 
-  for (wtf_size_t i = 0; i < kWebGLExtensionNameCount; ++i)
-    extension_enabled_[i] = false;
-
   // This resolver is non-null during a makeXRCompatible call, while waiting
   // for a response from the browser and XR process. If the WebGL context is
   // lost before we get a response, the resolver has to be rejected to be
@@ -7163,7 +7148,7 @@
     // the event is done being handled. This causes a crash when an outstanding
     // AutoLock goes out of scope. To avoid this, we create a no-op task to hold
     // a reference to the DrawingBuffer until this function is done executing.
-    task_runner_->PostTask(
+    GetContextTaskRunner()->PostTask(
         FROM_HERE,
         WTF::BindOnce(&WebGLRenderingContextBase::HoldReferenceToDrawingBuffer,
                       WrapWeakPersistent(this),
@@ -7216,10 +7201,6 @@
     restore_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
 }
 
-uint32_t WebGLRenderingContextBase::NumberOfContextLosses() const {
-  return number_of_context_losses_;
-}
-
 cc::Layer* WebGLRenderingContextBase::CcLayer() const {
   return isContextLost() ? nullptr : GetDrawingBuffer()->CcLayer();
 }
@@ -8590,6 +8571,7 @@
 
   drawing_buffer_ = std::move(buffer);
   GetDrawingBuffer()->Bind(GL_FRAMEBUFFER);
+  WebGLContextObjectSupport::OnContextRestored(drawing_buffer_->ContextGL());
   lost_context_errors_.clear();
   context_lost_mode_ = kNotLostContext;
   auto_recovery_method_ = kManual;
@@ -8888,7 +8870,7 @@
   visitor->Trace(make_xr_compatible_resolver_);
   visitor->Trace(program_completion_query_list_);
   visitor->Trace(program_completion_query_map_);
-  ScriptWrappable::Trace(visitor);
+  WebGLContextObjectSupport::Trace(visitor);
   CanvasRenderingContext::Trace(visitor);
 }
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
index 3e74a3b..95d52d6 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
@@ -33,7 +33,6 @@
 #include "base/check_op.h"
 #include "base/memory/raw_ptr_exclusion.h"
 #include "base/numerics/checked_math.h"
-#include "base/task/single_thread_task_runner.h"
 #include "device/vr/public/mojom/vr_service.mojom-blink-forward.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
@@ -46,12 +45,11 @@
 #include "third_party/blink/renderer/core/layout/content_change_type.h"
 #include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
-#include "third_party/blink/renderer/modules/webgl/webgl_extension_name.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_context_object_support.h"
 #include "third_party/blink/renderer/modules/webgl/webgl_texture.h"
 #include "third_party/blink/renderer/modules/webgl/webgl_uniform_location.h"
 #include "third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/extensions_3d_util.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.h"
@@ -60,20 +58,12 @@
 #include "third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h"
 #include "third_party/blink/renderer/platform/timer.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/khronos/GLES2/gl2.h"
-#include "third_party/khronos/GLES3/gl31.h"
 #include "third_party/skia/include/core/SkData.h"
 
 namespace cc {
 class Layer;
 }
 
-namespace gpu {
-namespace gles2 {
-class GLES2Interface;
-}
-}  // namespace gpu
-
 namespace media {
 class PaintCanvasVideoRenderer;
 }
@@ -103,7 +93,6 @@
 class WebGLCompressedTexturePVRTC;
 class WebGLCompressedTextureS3TC;
 class WebGLCompressedTextureS3TCsRGB;
-class WebGLContextObject;
 class WebGLDebugShaders;
 class WebGLDrawBuffers;
 class WebGLExtension;
@@ -111,6 +100,7 @@
 class WebGLObject;
 class WebGLProgram;
 class WebGLRenderbuffer;
+class WebGLRenderingContextBase;
 class WebGLShader;
 class WebGLShaderPrecisionFormat;
 class WebGLVertexArrayObjectBase;
@@ -135,9 +125,10 @@
   const bool requires_emulation_;
 };
 
-class MODULES_EXPORT WebGLRenderingContextBase : public ScriptWrappable,
-                                                 public CanvasRenderingContext,
-                                                 public DrawingBuffer::Client {
+class MODULES_EXPORT WebGLRenderingContextBase
+    : public WebGLContextObjectSupport,
+      public CanvasRenderingContext,
+      public DrawingBuffer::Client {
  public:
   WebGLRenderingContextBase(const WebGLRenderingContextBase&) = delete;
   WebGLRenderingContextBase& operator=(const WebGLRenderingContextBase&) =
@@ -561,8 +552,6 @@
   void LoseContext(LostContextMode) override;
   void ForceLostContext(LostContextMode, AutoRecoveryMethod);
   void ForceRestoreContext();
-  void LoseContextImpl(LostContextMode, AutoRecoveryMethod);
-  uint32_t NumberOfContextLosses() const;
 
   // Utilities to restore GL state to match the rendering context's
   // saved state. Use these after contextGL()-based state changes that
@@ -575,12 +564,6 @@
   void RestoreProgram();
   void RestoreActiveTexture();
 
-  gpu::gles2::GLES2Interface* ContextGL() const {
-    DrawingBuffer* d = GetDrawingBuffer();
-    if (!d)
-      return nullptr;
-    return d->ContextGL();
-  }
   const gpu::Capabilities& ContextGLCapabilities() const {
     // This should only be called in contexts where ContextGL() is guaranteed
     // to exist.
@@ -664,13 +647,6 @@
       ::partition_alloc::internal::MaxDirectMapped();
 
  protected:
-  // WebGL object types.
-  friend class WebGLContextObject;
-  friend class WebGLObject;
-  friend class WebGLQuery;
-  friend class WebGLTimerQueryEXT;
-  friend class WebGLVertexArrayObjectBase;
-
   // Implementation helpers.
   friend class ScopedPixelLocalStorageInterrupt;
   friend class ScopedDrawingBufferBinder;
@@ -786,8 +762,6 @@
 
   void OnErrorMessage(const char*, int32_t id);
 
-  scoped_refptr<base::SingleThreadTaskRunner> GetContextTaskRunner();
-
   // Query if depth_stencil buffer is supported.
   bool IsDepthStencilSupported() { return is_depth_stencil_supported_; }
 
@@ -844,7 +818,6 @@
       dispatch_context_lost_event_timer_;
   bool restore_allowed_ = false;
   HeapTaskRunnerTimer<WebGLRenderingContextBase> restore_timer_;
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
   bool destruction_in_progress_ = false;
   bool marked_canvas_dirty_;
@@ -1074,10 +1047,6 @@
   bool ExtensionSupportedAndAllowed(const ExtensionTracker*);
   WebGLExtension* EnableExtensionIfSupported(const String& name);
 
-  inline bool ExtensionEnabled(WebGLExtensionName name) {
-    return extension_enabled_[name];
-  }
-
   bool TimerQueryExtensionsEnabled();
 
   // ScopedDrawingBufferBinder is used for
diff --git a/third_party/blink/renderer/modules/webgl/webgl_sampler.cc b/third_party/blink/renderer/modules/webgl/webgl_sampler.cc
index 2ed1a52..073992d 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_sampler.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_sampler.cc
@@ -5,13 +5,13 @@
 #include "third_party/blink/renderer/modules/webgl/webgl_sampler.h"
 
 #include "gpu/command_buffer/client/gles2_interface.h"
-#include "third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_context_object_support.h"
 
 namespace blink {
 
-WebGLSampler::WebGLSampler(WebGL2RenderingContextBase* ctx) : WebGLObject(ctx) {
-  GLuint sampler;
-  if (!ctx->isContextLost()) {
+WebGLSampler::WebGLSampler(WebGLContextObjectSupport* ctx) : WebGLObject(ctx) {
+  if (!ctx->IsLost()) {
+    GLuint sampler;
     ctx->ContextGL()->GenSamplers(1, &sampler);
     SetObject(sampler);
   }
diff --git a/third_party/blink/renderer/modules/webgl/webgl_sampler.h b/third_party/blink/renderer/modules/webgl/webgl_sampler.h
index 625a632..30525ac 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_sampler.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_sampler.h
@@ -9,13 +9,11 @@
 
 namespace blink {
 
-class WebGL2RenderingContextBase;
-
 class WebGLSampler : public WebGLObject {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit WebGLSampler(WebGL2RenderingContextBase*);
+  explicit WebGLSampler(WebGLContextObjectSupport*);
   ~WebGLSampler() override;
 
  protected:
diff --git a/third_party/blink/renderer/modules/webgl/webgl_shader.cc b/third_party/blink/renderer/modules/webgl/webgl_shader.cc
index 0f2b17d..feef57d7 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_shader.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_shader.cc
@@ -26,13 +26,13 @@
 #include "third_party/blink/renderer/modules/webgl/webgl_shader.h"
 
 #include "gpu/command_buffer/client/gles2_interface.h"
-#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_context_object_support.h"
 
 namespace blink {
 
-WebGLShader::WebGLShader(WebGLRenderingContextBase* ctx, GLenum type)
+WebGLShader::WebGLShader(WebGLContextObjectSupport* ctx, GLenum type)
     : WebGLObject(ctx), type_(type), source_("") {
-  if (!ctx->isContextLost()) {
+  if (!ctx->IsLost()) {
     SetObject(ctx->ContextGL()->CreateShader(type));
   }
 }
diff --git a/third_party/blink/renderer/modules/webgl/webgl_shader.h b/third_party/blink/renderer/modules/webgl/webgl_shader.h
index 0ef9e0f..6844a69 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_shader.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_shader.h
@@ -37,7 +37,7 @@
  public:
   ~WebGLShader() override;
 
-  WebGLShader(WebGLRenderingContextBase*, GLenum);
+  WebGLShader(WebGLContextObjectSupport*, GLenum);
 
   GLenum GetType() const { return type_; }
   const String& Source() const { return source_; }
diff --git a/third_party/blink/renderer/modules/webgl/webgl_sync.cc b/third_party/blink/renderer/modules/webgl/webgl_sync.cc
index ca4f88b..6f1edfb3 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_sync.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_sync.cc
@@ -7,11 +7,12 @@
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_context_object_support.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
 
 namespace blink {
 
-WebGLSync::WebGLSync(WebGL2RenderingContextBase* ctx,
+WebGLSync::WebGLSync(WebGLContextObjectSupport* ctx,
                      GLuint object,
                      GLenum object_type)
     : WebGLObject(ctx),
diff --git a/third_party/blink/renderer/modules/webgl/webgl_sync.h b/third_party/blink/renderer/modules/webgl/webgl_sync.h
index 5e0f6e8..a46c3a3 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_sync.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_sync.h
@@ -9,16 +9,8 @@
 #include "third_party/blink/renderer/modules/webgl/webgl_object.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
 
-namespace gpu {
-namespace gles2 {
-class GLES2Interface;
-}
-}  // namespace gpu
-
 namespace blink {
 
-class WebGL2RenderingContextBase;
-
 class WebGLSync : public WebGLObject {
   DEFINE_WRAPPERTYPEINFO();
 
@@ -30,7 +22,7 @@
   bool IsSignaled() const;
 
  protected:
-  WebGLSync(WebGL2RenderingContextBase*, GLuint, GLenum object_type);
+  WebGLSync(WebGLContextObjectSupport*, GLuint, GLenum object_type);
 
   void DeleteObjectImpl(gpu::gles2::GLES2Interface*) override;
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_texture.cc b/third_party/blink/renderer/modules/webgl/webgl_texture.cc
index 282bbc2c..028ef81 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_texture.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_texture.cc
@@ -30,16 +30,16 @@
 
 namespace blink {
 
-WebGLTexture::WebGLTexture(WebGLRenderingContextBase* ctx)
+WebGLTexture::WebGLTexture(WebGLContextObjectSupport* ctx)
     : WebGLObject(ctx), target_(0) {
-  if (!ctx->isContextLost()) {
+  if (!ctx->IsLost()) {
     GLuint texture;
     ctx->ContextGL()->GenTextures(1, &texture);
     SetObject(texture);
   }
 }
 
-WebGLTexture::WebGLTexture(WebGLRenderingContextBase* ctx,
+WebGLTexture::WebGLTexture(WebGLContextObjectSupport* ctx,
                            GLuint texture,
                            GLenum target)
     : WebGLObject(ctx), target_(target) {
diff --git a/third_party/blink/renderer/modules/webgl/webgl_texture.h b/third_party/blink/renderer/modules/webgl/webgl_texture.h
index 8f30095..ec5424a 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_texture.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_texture.h
@@ -26,11 +26,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_TEXTURE_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_TEXTURE_H_
 
-#include "base/time/time.h"
-#include "media/base/video_frame.h"
-#include "third_party/blink/public/platform/web_media_player.h"
 #include "third_party/blink/renderer/modules/webgl/webgl_object.h"
-#include "ui/gfx/geometry/rect.h"
 
 namespace blink {
 
@@ -38,7 +34,7 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit WebGLTexture(WebGLRenderingContextBase*);
+  explicit WebGLTexture(WebGLContextObjectSupport*);
 
   ~WebGLTexture() override;
 
@@ -55,7 +51,7 @@
 
  protected:
   // Constructor for WebGLUnownedTexture.
-  explicit WebGLTexture(WebGLRenderingContextBase* ctx,
+  explicit WebGLTexture(WebGLContextObjectSupport* ctx,
                         GLuint texture,
                         GLenum target);
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_timer_query_ext.cc b/third_party/blink/renderer/modules/webgl/webgl_timer_query_ext.cc
index 5586583..efcb90e5 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_timer_query_ext.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_timer_query_ext.cc
@@ -7,18 +7,19 @@
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_context_object_support.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
 
 namespace blink {
 
-WebGLTimerQueryEXT::WebGLTimerQueryEXT(WebGLRenderingContextBase* ctx)
+WebGLTimerQueryEXT::WebGLTimerQueryEXT(WebGLContextObjectSupport* ctx)
     : WebGLObject(ctx),
       target_(0),
       can_update_availability_(false),
       query_result_available_(false),
       query_result_(0),
       task_runner_(ctx->GetContextTaskRunner()) {
-  if (!ctx || ctx->isContextLost()) {
+  if (!ctx || ctx->IsLost()) {
     return;
   }
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_timer_query_ext.h b/third_party/blink/renderer/modules/webgl/webgl_timer_query_ext.h
index 759bc36..240dfeb6 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_timer_query_ext.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_timer_query_ext.h
@@ -9,19 +9,13 @@
 #include "third_party/blink/renderer/modules/webgl/webgl_object.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cancellable_task.h"
 
-namespace gpu {
-namespace gles2 {
-class GLES2Interface;
-}
-}
-
 namespace blink {
 
 class WebGLTimerQueryEXT : public WebGLObject {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  WebGLTimerQueryEXT(WebGLRenderingContextBase*);
+  WebGLTimerQueryEXT(WebGLContextObjectSupport*);
   ~WebGLTimerQueryEXT() override;
 
   void SetTarget(GLenum target) { target_ = target; }
diff --git a/third_party/blink/renderer/modules/webgl/webgl_transform_feedback.cc b/third_party/blink/renderer/modules/webgl/webgl_transform_feedback.cc
index e904eca..7bd67ae6 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_transform_feedback.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_transform_feedback.cc
@@ -5,12 +5,14 @@
 #include "third_party/blink/renderer/modules/webgl/webgl_transform_feedback.h"
 
 #include "gpu/command_buffer/client/gles2_interface.h"
-#include "third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_buffer.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_context_object_support.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_program.h"
 
 namespace blink {
 
 WebGLTransformFeedback::WebGLTransformFeedback(
-    WebGL2RenderingContextBase* ctx,
+    WebGLContextObjectSupport* ctx,
     TFType type,
     GLint max_transform_feedback_separate_attribs)
     : WebGLObject(ctx),
@@ -19,7 +21,7 @@
       program_(nullptr),
       active_(false),
       paused_(false) {
-  if (ctx->isContextLost()) {
+  if (ctx->IsLost()) {
     return;
   }
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_transform_feedback.h b/third_party/blink/renderer/modules/webgl/webgl_transform_feedback.h
index 39af2a1..7ba203cd 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_transform_feedback.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_transform_feedback.h
@@ -6,13 +6,12 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_TRANSFORM_FEEDBACK_H_
 
 #include "third_party/blink/renderer/modules/webgl/webgl_object.h"
-#include "third_party/blink/renderer/modules/webgl/webgl_program.h"
 #include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 
 namespace blink {
 
-class WebGL2RenderingContextBase;
 class WebGLBuffer;
+class WebGLProgram;
 
 class WebGLTransformFeedback : public WebGLObject {
   DEFINE_WRAPPERTYPEINFO();
@@ -24,7 +23,7 @@
   };
 
   explicit WebGLTransformFeedback(
-      WebGL2RenderingContextBase*,
+      WebGLContextObjectSupport*,
       TFType,
       GLint max_transform_feedback_separate_attribs);
   ~WebGLTransformFeedback() override;
diff --git a/third_party/blink/renderer/modules/webgl/webgl_unowned_texture.cc b/third_party/blink/renderer/modules/webgl/webgl_unowned_texture.cc
index 02dca84..3c9ae843 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_unowned_texture.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_unowned_texture.cc
@@ -4,12 +4,9 @@
 
 #include "third_party/blink/renderer/modules/webgl/webgl_unowned_texture.h"
 
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h"
-
 namespace blink {
 
-WebGLUnownedTexture::WebGLUnownedTexture(WebGLRenderingContextBase* ctx,
+WebGLUnownedTexture::WebGLUnownedTexture(WebGLContextObjectSupport* ctx,
                                          GLuint texture,
                                          GLenum target)
     : WebGLTexture(ctx, texture, target) {}
diff --git a/third_party/blink/renderer/modules/webgl/webgl_unowned_texture.h b/third_party/blink/renderer/modules/webgl/webgl_unowned_texture.h
index 53f6c8188..9d21cda 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_unowned_texture.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_unowned_texture.h
@@ -19,9 +19,9 @@
 class WebGLUnownedTexture final : public WebGLTexture {
  public:
   // The provided GLuint must have been created in the same
-  // WebGLRenderingContextBase that is provided. Garbage collection of
+  // WebGLContextObjectSupport that is provided. Garbage collection of
   // this texture will not result in any GL calls being issued.
-  explicit WebGLUnownedTexture(WebGLRenderingContextBase* ctx,
+  explicit WebGLUnownedTexture(WebGLContextObjectSupport* ctx,
                                GLuint texture,
                                GLenum target);
   ~WebGLUnownedTexture() override;
diff --git a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object.cc b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object.cc
index d6ec841..ae02c6e 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object.cc
@@ -4,11 +4,9 @@
 
 #include "third_party/blink/renderer/modules/webgl/webgl_vertex_array_object.h"
 
-#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h"
-
 namespace blink {
 
-WebGLVertexArrayObject::WebGLVertexArrayObject(WebGLRenderingContextBase* ctx,
+WebGLVertexArrayObject::WebGLVertexArrayObject(WebGLContextObjectSupport* ctx,
                                                VaoType type,
                                                GLint max_vertex_attribs)
     : WebGLVertexArrayObjectBase(ctx, type, max_vertex_attribs) {}
diff --git a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object.h b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object.h
index c80059b..5e59b92 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object.h
@@ -13,7 +13,7 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit WebGLVertexArrayObject(WebGLRenderingContextBase*,
+  explicit WebGLVertexArrayObject(WebGLContextObjectSupport*,
                                   VaoType,
                                   GLint max_vertex_attribs);
 };
diff --git a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.cc b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.cc
index 1fddc23..1358a27f 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.cc
@@ -5,19 +5,19 @@
 #include "third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.h"
 
 #include "gpu/command_buffer/client/gles2_interface.h"
-#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h"
+#include "third_party/blink/renderer/modules/webgl/webgl_context_object_support.h"
 
 namespace blink {
 
 WebGLVertexArrayObjectBase::WebGLVertexArrayObjectBase(
-    WebGLRenderingContextBase* ctx,
+    WebGLContextObjectSupport* ctx,
     VaoType type,
     GLint max_vertex_attribs)
     : WebGLObject(ctx),
       type_(type),
       has_ever_been_bound_(false),
       is_all_enabled_attrib_buffer_bound_(true) {
-  if (!ctx || ctx->isContextLost()) {
+  if (!ctx || ctx->IsLost()) {
     return;
   }
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.h b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.h
index 10407f4..d3c114dfb 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.h
@@ -45,7 +45,7 @@
   void Trace(Visitor*) const override;
 
  protected:
-  WebGLVertexArrayObjectBase(WebGLRenderingContextBase*,
+  WebGLVertexArrayObjectBase(WebGLContextObjectSupport*,
                              VaoType,
                              GLint max_vertex_attribs);
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.cc b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.cc
index 458bdec..1e7177e 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.cc
@@ -25,12 +25,10 @@
 
 #include "third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.h"
 
-#include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h"
-
 namespace blink {
 
 WebGLVertexArrayObjectOES::WebGLVertexArrayObjectOES(
-    WebGLRenderingContextBase* ctx,
+    WebGLContextObjectSupport* ctx,
     VaoType type,
     GLint max_vertex_attribs)
     : WebGLVertexArrayObjectBase(ctx, type, max_vertex_attribs) {}
diff --git a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.h b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.h
index eb669a1..182074b 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.h
@@ -34,7 +34,7 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit WebGLVertexArrayObjectOES(WebGLRenderingContextBase*,
+  explicit WebGLVertexArrayObjectOES(WebGLContextObjectSupport*,
                                      VaoType,
                                      GLint max_vertex_attribs);
 };
diff --git a/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager.cc b/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager.cc
index b979997bc..3a62178 100644
--- a/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager.cc
+++ b/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager.cc
@@ -121,10 +121,7 @@
 base::OnceClosure WebVideoCaptureImplManager::StartCapture(
     const media::VideoCaptureSessionId& id,
     const media::VideoCaptureParams& params,
-    const VideoCaptureStateUpdateCB& state_update_cb,
-    const VideoCaptureDeliverFrameCB& deliver_frame_cb,
-    const VideoCaptureSubCaptureTargetVersionCB& sub_capture_target_version_cb,
-    const VideoCaptureNotifyFrameDroppedCB& frame_dropped_cb) {
+    VideoCaptureCallbacks video_capture_callbacks) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
   const auto it = std::ranges::find(devices_, id, &DeviceEntry::session_id);
   if (it == devices_.end())
@@ -136,8 +133,7 @@
   Platform::Current()->GetIOTaskRunner()->PostTask(
       FROM_HERE,
       base::BindOnce(&VideoCaptureImpl::StartCapture, it->impl->GetWeakPtr(),
-                     client_id, params, state_update_cb, deliver_frame_cb,
-                     sub_capture_target_version_cb, frame_dropped_cb));
+                     client_id, params, std::move(video_capture_callbacks)));
   return base::BindOnce(&WebVideoCaptureImplManager::StopCapture,
                         weak_factory_.GetWeakPtr(), client_id, id);
 }
diff --git a/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager_test.cc b/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager_test.cc
index 5c46e98..64777f7 100644
--- a/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager_test.cc
+++ b/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager_test.cc
@@ -230,15 +230,17 @@
 
   base::OnceClosure StartCapture(const media::VideoCaptureSessionId& id,
                                  const media::VideoCaptureParams& params) {
-    return manager_->StartCapture(
-        id, params,
-        ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
-            &VideoCaptureImplManagerTest::OnStateUpdate,
-            CrossThreadUnretained(this), id)),
-        ConvertToBaseRepeatingCallback(
-            CrossThreadBindRepeating(&VideoCaptureImplManagerTest::OnFrameReady,
-                                     CrossThreadUnretained(this))),
-        base::DoNothing(), base::DoNothing());
+    VideoCaptureCallbacks video_capture_callbacks;
+    video_capture_callbacks.state_update_cb = ConvertToBaseRepeatingCallback(
+        CrossThreadBindRepeating(&VideoCaptureImplManagerTest::OnStateUpdate,
+                                 CrossThreadUnretained(this), id));
+    video_capture_callbacks.deliver_frame_cb =
+        base::BindRepeating(&VideoCaptureImplManagerTest::OnFrameReady,
+                            CrossThreadUnretained(this));
+    video_capture_callbacks.frame_dropped_cb = base::DoNothing();
+    video_capture_callbacks.sub_capture_target_version_cb = base::DoNothing();
+    return manager_->StartCapture(id, params,
+                                  std::move(video_capture_callbacks));
   }
 
   base::test::TaskEnvironment task_environment_;
diff --git a/third_party/blink/renderer/platform/fonts/string_truncator.cc b/third_party/blink/renderer/platform/fonts/string_truncator.cc
index 6cb5ef5b..edd4246 100644
--- a/third_party/blink/renderer/platform/fonts/string_truncator.cc
+++ b/third_party/blink/renderer/platform/fonts/string_truncator.cc
@@ -171,7 +171,8 @@
     DCHECK_LT(keep_count, keep_count_for_smallest_known_to_not_fit);
     DCHECK_GT(keep_count, keep_count_for_largest_known_to_fit);
 
-    truncated_string = truncate_to_buffer(string, keep_count, string_buffer);
+    truncated_string = truncate_to_buffer(string, keep_count,
+      base::span(string_buffer));
 
     width = StringWidth(font, truncated_string);
     if (width <= max_width) {
@@ -188,7 +189,8 @@
 
   if (keep_count != keep_count_for_largest_known_to_fit) {
     keep_count = keep_count_for_largest_known_to_fit;
-    truncated_string = truncate_to_buffer(string, keep_count, string_buffer);
+    truncated_string = truncate_to_buffer(string, keep_count,
+      base::span(string_buffer));
   }
 
   return String(truncated_string);
diff --git a/third_party/blink/renderer/platform/graphics/image_frame_generator.cc b/third_party/blink/renderer/platform/graphics/image_frame_generator.cc
index 38a0a63..b029813 100644
--- a/third_party/blink/renderer/platform/graphics/image_frame_generator.cc
+++ b/third_party/blink/renderer/platform/graphics/image_frame_generator.cc
@@ -111,10 +111,11 @@
     wtf_size_t index,
     const SkPixmap& pixmap,
     cc::PaintImage::GeneratorClientId client_id) {
+  if (decode_failed_.load()) {
+    return false;
+  }
   {
     base::AutoLock lock(generator_lock_);
-    if (decode_failed_)
-      return false;
     RecordWhetherMultiDecoded(client_id);
   }
 
@@ -146,8 +147,8 @@
   }
 
   base::AutoLock lock(generator_lock_);
-  decode_failed_ = decode_failed;
-  if (decode_failed_) {
+  decode_failed_.store(decode_failed);
+  if (decode_failed) {
     DCHECK(!current_decode_succeeded);
     return false;
   }
@@ -175,8 +176,9 @@
   // TODO (scroggo): The only interesting thing this uses from the
   // ImageFrameGenerator is |decode_failed_|. Move this into
   // DecodingImageGenerator, which is the only class that calls it.
-  if (decode_failed_ || yuv_decoding_failed_)
+  if (decode_failed_.load() || yuv_decoding_failed_.load()) {
     return false;
+  }
 
   if (!planes.data() || !planes[0] || !planes[1] || !planes[2] ||
       !row_bytes.data() || !row_bytes[0] || !row_bytes[1] || !row_bytes[2]) {
@@ -216,15 +218,14 @@
   // This may not be the case once YUV supports incremental decoding
   // (crbug.com/943519).
   if (decoder->Failed()) {
-    yuv_decoding_failed_ = true;
+    yuv_decoding_failed_.store(true);
   }
 
   return false;
 }
 
 void ImageFrameGenerator::SetHasAlpha(wtf_size_t index, bool has_alpha) {
-  generator_lock_.AssertAcquired();
-
+  base::AutoLock lock(has_alpha_lock_);
   if (index >= has_alpha_.size()) {
     const wtf_size_t old_size = has_alpha_.size();
     has_alpha_.resize(index + 1);
@@ -255,9 +256,8 @@
   }
 }
 
-bool ImageFrameGenerator::HasAlpha(wtf_size_t index) {
-  base::AutoLock lock(generator_lock_);
-
+bool ImageFrameGenerator::HasAlpha(wtf_size_t index) const {
+  base::AutoLock lock(has_alpha_lock_);
   if (index < has_alpha_.size())
     return has_alpha_[index];
   return true;
@@ -272,8 +272,9 @@
 
   base::AutoLock lock(generator_lock_);
 
-  if (yuv_decoding_failed_)
+  if (yuv_decoding_failed_.load()) {
     return false;
+  }
   std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create(
       data, /*data_complete=*/true, ImageDecoder::kAlphaPremultiplied,
       ImageDecoder::kDefaultBitDepth, decoder_color_behavior_, aux_image_,
diff --git a/third_party/blink/renderer/platform/graphics/image_frame_generator.h b/third_party/blink/renderer/platform/graphics/image_frame_generator.h
index ebdf48b..b0a0af2 100644
--- a/third_party/blink/renderer/platform/graphics/image_frame_generator.h
+++ b/third_party/blink/renderer/platform/graphics/image_frame_generator.h
@@ -108,12 +108,9 @@
   SkISize GetSupportedDecodeSize(const SkISize& requested_size) const;
 
   bool IsMultiFrame() const { return is_multi_frame_; }
-  bool DecodeFailed() const {
-    base::AutoLock lock(generator_lock_);
-    return decode_failed_;
-  }
+  bool DecodeFailed() const { return decode_failed_.load(); }
 
-  bool HasAlpha(wtf_size_t index);
+  bool HasAlpha(wtf_size_t index) const;
 
   // TODO(crbug.com/943519): Do not call unless the SkROBuffer has all the data.
   bool GetYUVAInfo(
@@ -170,16 +167,19 @@
   const bool is_multi_frame_;
   const Vector<SkISize> supported_sizes_;
 
-  mutable base::Lock generator_lock_;
-  bool decode_failed_ GUARDED_BY(generator_lock_) = false;
-  bool yuv_decoding_failed_ GUARDED_BY(generator_lock_) = false;
-  Vector<bool> has_alpha_ GUARDED_BY(generator_lock_);
+  std::atomic<bool> decode_failed_{false};
+  std::atomic<bool> yuv_decoding_failed_{false};
+
+  mutable base::Lock has_alpha_lock_;
+  Vector<bool> has_alpha_ GUARDED_BY(has_alpha_lock_);
 
   struct ClientLock {
     int ref_count = 0;
     base::Lock lock;
   };
 
+  mutable base::Lock generator_lock_;
+
   // Note that it is necessary to use HashMap here to ensure that references
   // to entries in the map, stored in ClientAutoLock, remain valid across
   // insertions into the map.
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 6175858..8663620 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -4543,7 +4543,7 @@
     },
     {
       name: "SvgInlineRootPixelSnappingScaleAdjustment",
-      status: "stable",
+      status: "test",
     },
     {
       name: "SvgNoPixelSnappingScaleAdjustment",
@@ -5220,7 +5220,7 @@
     },
     {
       name: "WebCodecsOrientation",
-      status: "experimental",
+      status: "stable",
     },
     {
       name: "WebCodecsVideoEncoderBuffers",
diff --git a/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc b/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
index a0bc559..50ac61d6 100644
--- a/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
+++ b/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
@@ -694,20 +694,21 @@
 void VideoCaptureImpl::StartCapture(
     int client_id,
     const media::VideoCaptureParams& params,
-    const VideoCaptureStateUpdateCB& state_update_cb,
-    const VideoCaptureDeliverFrameCB& deliver_frame_cb,
-    const VideoCaptureSubCaptureTargetVersionCB& sub_capture_target_version_cb,
-    const VideoCaptureNotifyFrameDroppedCB& frame_dropped_cb) {
+    VideoCaptureCallbacks video_capture_callbacks) {
   DVLOG(1) << __func__ << " |device_id_| = " << device_id_;
   DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
   OnLog("VideoCaptureImpl got request to start capture.");
 
   ClientInfo client_info;
   client_info.params = params;
-  client_info.state_update_cb = state_update_cb;
-  client_info.deliver_frame_cb = deliver_frame_cb;
-  client_info.sub_capture_target_version_cb = sub_capture_target_version_cb;
-  client_info.frame_dropped_cb = frame_dropped_cb;
+  client_info.state_update_cb =
+      std::move(video_capture_callbacks.state_update_cb);
+  client_info.deliver_frame_cb =
+      std::move(video_capture_callbacks.deliver_frame_cb);
+  client_info.sub_capture_target_version_cb =
+      std::move(video_capture_callbacks.sub_capture_target_version_cb);
+  client_info.frame_dropped_cb =
+      std::move(video_capture_callbacks.frame_dropped_cb);
 
   switch (state_) {
     case VIDEO_CAPTURE_STATE_STARTING:
@@ -739,20 +740,22 @@
       return;
     case VIDEO_CAPTURE_STATE_ERROR:
       OnLog("VideoCaptureImpl is in error state.");
-      state_update_cb.Run(blink::VIDEO_CAPTURE_STATE_ERROR);
+      client_info.state_update_cb.Run(blink::VIDEO_CAPTURE_STATE_ERROR);
       return;
     case VIDEO_CAPTURE_STATE_ERROR_SYSTEM_PERMISSIONS_DENIED:
       OnLog("VideoCaptureImpl is in system permissions error state.");
-      state_update_cb.Run(
+      client_info.state_update_cb.Run(
           blink::VIDEO_CAPTURE_STATE_ERROR_SYSTEM_PERMISSIONS_DENIED);
       return;
     case VIDEO_CAPTURE_STATE_ERROR_CAMERA_BUSY:
       OnLog("VideoCaptureImpl is in camera busy error state.");
-      state_update_cb.Run(blink::VIDEO_CAPTURE_STATE_ERROR_CAMERA_BUSY);
+      client_info.state_update_cb.Run(
+          blink::VIDEO_CAPTURE_STATE_ERROR_CAMERA_BUSY);
       return;
     case VIDEO_CAPTURE_STATE_ERROR_START_TIMEOUT:
       OnLog("VideoCaptureImpl is in timeout error state.");
-      state_update_cb.Run(blink::VIDEO_CAPTURE_STATE_ERROR_START_TIMEOUT);
+      client_info.state_update_cb.Run(
+          blink::VIDEO_CAPTURE_STATE_ERROR_START_TIMEOUT);
       return;
     case VIDEO_CAPTURE_STATE_PAUSED:
     case VIDEO_CAPTURE_STATE_RESUMED:
diff --git a/third_party/blink/renderer/platform/video_capture/video_capture_impl.h b/third_party/blink/renderer/platform/video_capture/video_capture_impl.h
index febe5ff..b31ecfce 100644
--- a/third_party/blink/renderer/platform/video_capture/video_capture_impl.h
+++ b/third_party/blink/renderer/platform/video_capture/video_capture_impl.h
@@ -72,20 +72,20 @@
   // Start capturing using the provided parameters.
   // |client_id| must be unique to this object in the render process. It is
   // used later to stop receiving video frames.
-  // |state_update_cb| will be called when state changes.
-  // |deliver_frame_cb| will be called when a frame is ready.
-  // |sub_capture_target_version_cb| will be called when it is guaranteed that
-  // all subsequent frames |deliver_frame_cb| is called for, have a crop version
-  // that is equal-to-or-greater-than the given crop version.
-  // |frame_dropped_cb| will be called when a frame was dropped prior to
-  // delivery (i.e. |deliver_frame_cb| was not called for this frame).
+  // |video_capture_callbacks.state_update_cb| will be called when state
+  // changes.
+  // |video_capture_callbacks.deliver_frame_cb| will be called when a
+  // frame is ready.
+  // |video_capture_callbacks.sub_capture_target_version_cb| will be called
+  // when it is guaranteed that all subsequent frames
+  // |video_capture_callbacks.deliver_frame_cb| is called for, have a crop
+  // version that is equal-to-or-greater-than the given crop version.
+  // |video_capture_callbacks.frame_dropped_cb| will be called when a frame was
+  // dropped prior to delivery (i.e. |video_capture_callbacks.deliver_frame_cb|
+  // was not called for this frame).
   void StartCapture(int client_id,
                     const media::VideoCaptureParams& params,
-                    const VideoCaptureStateUpdateCB& state_update_cb,
-                    const VideoCaptureDeliverFrameCB& deliver_frame_cb,
-                    const VideoCaptureSubCaptureTargetVersionCB&
-                        sub_capture_target_version_cb,
-                    const VideoCaptureNotifyFrameDroppedCB& frame_dropped_cb);
+                    VideoCaptureCallbacks video_capture_callbacks);
 
   // Stop capturing. |client_id| is the identifier used to call StartCapture.
   void StopCapture(int client_id);
diff --git a/third_party/blink/renderer/platform/video_capture/video_capture_impl_test.cc b/third_party/blink/renderer/platform/video_capture/video_capture_impl_test.cc
index 328fc15..1ab09cc 100644
--- a/third_party/blink/renderer/platform/video_capture/video_capture_impl_test.cc
+++ b/third_party/blink/renderer/platform/video_capture/video_capture_impl_test.cc
@@ -209,10 +209,14 @@
     const auto frame_dropped_callback = WTF::BindRepeating(
         &VideoCaptureImplTest::OnFrameDropped, base::Unretained(this));
 
-    video_capture_impl_->StartCapture(
-        client_id, params, state_update_callback, frame_ready_callback,
-        /*sub_capture_target_version_cb=*/base::DoNothing(),
-        frame_dropped_callback);
+    VideoCaptureCallbacks video_capture_callbacks;
+    video_capture_callbacks.state_update_cb = state_update_callback;
+    video_capture_callbacks.deliver_frame_cb = frame_ready_callback;
+    video_capture_callbacks.frame_dropped_cb = frame_dropped_callback;
+    video_capture_callbacks.sub_capture_target_version_cb = base::DoNothing();
+
+    video_capture_impl_->StartCapture(client_id, params,
+                                      std::move(video_capture_callbacks));
   }
 
   void StopCapture(int client_id) {
diff --git a/third_party/blink/renderer/platform/video_capture/video_capturer_source.h b/third_party/blink/renderer/platform/video_capture/video_capturer_source.h
index 9ff36f3ee..f1114e655 100644
--- a/third_party/blink/renderer/platform/video_capture/video_capturer_source.h
+++ b/third_party/blink/renderer/platform/video_capture/video_capturer_source.h
@@ -18,7 +18,10 @@
 
 namespace blink {
 
-enum class RunState {
+// The state of the video capture device.
+// The client can use this information to determine if the video capture
+// device is currently running or not.
+enum class VideoCaptureRunState {
   kRunning = 0,
   kStopped,
   kSystemPermissionsError,
@@ -33,14 +36,16 @@
  public:
   virtual ~VideoCapturerSource();
 
-  using RunningCallback = base::RepeatingCallback<void(RunState)>;
+  using VideoCaptureRunningCallbackCB =
+      base::RepeatingCallback<void(VideoCaptureRunState)>;
 
   // Returns formats that are preferred and can currently be used. May be empty
   // if no formats are available or known.
   virtual media::VideoCaptureFormats GetPreferredFormats() = 0;
 
-  // Starts capturing frames using the capture |params|. |new_frame_callback| is
-  // triggered when a new video frame is available.
+  // Starts capturing frames using the capture |params|.
+  // |video_capture_callbacks.deliver_frame_cb| is triggered when a new video
+  // frame is available.
   //
   // If capturing is started successfully then |running_callback| will be
   // called with a parameter of true. Note that some implementations may
@@ -52,20 +57,18 @@
   // |running_callback| will always be called on the same thread as the
   // StartCapture.
   //
-  // |sub_capture_target_version_callback| will be called when it is guaranteed
-  // that all subsequent frames |new_frame_callback| is called for, have a
+  // |video_capture_callbacks.sub_capture_target_version_cb| will be called when
+  // it is guaranteed that all subsequent frames
+  // |video_capture_callbacks.deliver_frame_cb| is called for, have a
   // sub-capture-target version that is equal-to-or-greater-than the given
   // sub-capture-target version.
   //
-  // |frame_dropped_callback| will be called when a frame was dropped prior to
-  // delivery (i.e. |new_frame_callback| was not called for this frame).
-  virtual void StartCapture(
-      const media::VideoCaptureParams& params,
-      const VideoCaptureDeliverFrameCB& new_frame_callback,
-      const VideoCaptureSubCaptureTargetVersionCB&
-          sub_capture_target_version_callback,
-      const VideoCaptureNotifyFrameDroppedCB& frame_dropped_callback,
-      const RunningCallback& running_callback) = 0;
+  // |video_capture_callbacks.frame_dropped_cb| will be called when a frame was
+  // dropped prior to delivery (i.e. |video_capture_callbacks.deliver_frame_cb|
+  // was not called for this frame).
+  virtual void StartCapture(const media::VideoCaptureParams& params,
+                            VideoCaptureCallbacks video_capture_callbacks,
+                            VideoCaptureRunningCallbackCB running_callback) = 0;
 
   // Returns a callback for providing the feedback from the consumer.
   // The callback can be called on any thread.
@@ -79,7 +82,8 @@
   //
   // The default implementation is a no-op and implementations are not required
   // to honor this request. If they decide to and capturing is started
-  // successfully, then |new_frame_callback| should be called with a frame.
+  // successfully, then |video_capture_callbacks.deliver_frame_cb| should be
+  // called with a frame.
   //
   // Note: This should only be called after StartCapture() and before
   // StopCapture(). Otherwise, its behavior is undefined.
@@ -107,7 +111,8 @@
   // Stops capturing frames and clears all callbacks including the
   // SupportedFormatsCallback callback. Note that queued frame callbacks
   // may still occur after this call, so the caller must take care to
-  // use refcounted or weak references in |new_frame_callback|.
+  // use refcounted or weak references in
+  // |video_capture_callbacks.deliver_frame_cb|.
   virtual void StopCapture() = 0;
 
   // Hints to the source that if it has an alpha channel, that alpha channel
diff --git a/third_party/blink/renderer/platform/widget/frame_widget.h b/third_party/blink/renderer/platform/widget/frame_widget.h
index e544f23..c6cf5ea 100644
--- a/third_party/blink/renderer/platform/widget/frame_widget.h
+++ b/third_party/blink/renderer/platform/widget/frame_widget.h
@@ -83,7 +83,8 @@
 
   // Image decode functionality.
   virtual void RequestDecode(const cc::DrawImage&,
-                             base::OnceCallback<void(bool)>) = 0;
+                             base::OnceCallback<void(bool)>,
+                             bool speculative) = 0;
 
   // Forwards to `WebFrameWidget::NotifyPresentationTime()`.
   // `presentation_callback` will be fired when the corresponding renderer frame
diff --git a/third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-abort.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-abort.tentative.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-abort.tentative.https.any.js
rename to third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-abort.tentative.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-availability-available.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-availability-available.tentative.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-availability-available.tentative.https.any.js
rename to third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-availability-available.tentative.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-availability.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-availability.tentative.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-availability.tentative.https.any.js
rename to third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-availability.tentative.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-create-available.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-create-available.tentative.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-create-available.tentative.https.any.js
rename to third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-create-available.tentative.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-create.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-create.tentative.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-create.tentative.https.any.js
rename to third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-create.tentative.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-measureInputUsage.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-measureInputUsage.tentative.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-measureInputUsage.tentative.https.any.js
rename to third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-measureInputUsage.tentative.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-summarize-streaming.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-summarize-streaming.tentative.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-summarize-streaming.tentative.https.any.js
rename to third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-summarize-streaming.tentative.https.window.js
diff --git a/third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-summarize.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-summarize.tentative.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-summarize.tentative.https.any.js
rename to third_party/blink/web_tests/external/wpt/ai/summarizer/summarizer-summarize.tentative.https.window.js
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/send-pending-reports-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/send-pending-reports-expected.txt
index a0da861..3d1a40b 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/send-pending-reports-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/send-pending-reports-expected.txt
@@ -2,4 +2,18 @@
 {
     numSent : 1
 }
+{
+    body : {
+        attribution_destination : http://127.0.0.1
+        randomized_trigger_rate : 0.0000025
+        report_id : <string>
+        scheduled_report_time : <string>
+        source_event_id : 0
+        source_type : event
+        trigger_data : 0
+    }
+    httpStatusCode : 404
+    result : sent
+    url : http://127.0.0.1:8000/.well-known/attribution-reporting/report-event-attribution
+}
 
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/send-pending-reports.js b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/send-pending-reports.js
index 9018af0..83e6320 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/send-pending-reports.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/send-pending-reports.js
@@ -40,7 +40,11 @@
     return;
   }
 
+  const report = dp.Storage.onceAttributionReportingReportSent();
+
   const {result} = await dp.Storage.sendPendingAttributionReports();
   testRunner.log(result);
+
+  testRunner.log((await report).params, '', ['report_id', 'scheduled_report_time']);
   testRunner.completeTest();
 })
diff --git a/third_party/blink/web_tests/inspector-protocol/bluetooth/descriptor-event-expected.txt b/third_party/blink/web_tests/inspector-protocol/bluetooth/descriptor-event-expected.txt
new file mode 100644
index 0000000..edbc910
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/bluetooth/descriptor-event-expected.txt
@@ -0,0 +1,5 @@
+Tests Bluetooth descriptor operation events handling
+Descriptor operation received: descriptorId: 09:09:09:09:09:09_1_1_1, type: read, data: undefined
+Descriptor operation received: descriptorId: 09:09:09:09:09:09_1_1_1, type: write, data: AQ==
+W29iamVjdCBBcnJheUJ1ZmZlcl0=
+
diff --git a/third_party/blink/web_tests/inspector-protocol/bluetooth/descriptor-event.js b/third_party/blink/web_tests/inspector-protocol/bluetooth/descriptor-event.js
new file mode 100644
index 0000000..449485a
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/bluetooth/descriptor-event.js
@@ -0,0 +1,78 @@
+(async function(/** @type {import('test_runner').TestRunner} */ testRunner) {
+  const {session, dp} = await testRunner.startBlank(
+      'Tests Bluetooth descriptor operation events handling');
+  const bp = testRunner.browserP();
+  await dp.Page.enable();
+  await dp.Runtime.enable();
+  const BluetoothHelper =
+      await testRunner.loadScript('resources/bluetooth-helper.js')
+  const helper = new BluetoothHelper(testRunner, dp, session);
+  await helper.setupPreconnectedPeripheral();
+  await helper.requestDevice({
+    acceptAllDevices: true,
+    optionalServices: [BluetoothHelper.HEART_RATE_SERVICE_UUID]
+  });
+  await helper.setupGattOperationHandler();
+  // Prepare descriptor operation handling.
+  bp.BluetoothEmulation.onDescriptorOperationReceived(
+      ({params: {descriptorId, type, data}}) => {
+        testRunner.log(`Descriptor operation received: descriptorId: ${
+            descriptorId}, type: ${type}, data: ${data}`);
+        bp.BluetoothEmulation.simulateDescriptorOperationResponse({
+          descriptorId,
+          type,
+          code: BluetoothHelper.HCI_SUCCESS,
+          ...(type === 'read' && {data: 'W29iamVjdCBBcnJheUJ1ZmZlcl0='}),
+        });
+      });
+
+  // Setup UUIDs.
+  const {result: {serviceId: heartRateServiceId}} =
+      await bp.BluetoothEmulation.addService({
+        address: helper.peripheralAddress(),
+        serviceUuid: BluetoothHelper.HEART_RATE_SERVICE_UUID,
+      });
+  const {result: {characteristicId: measurementIntervalCharacteristicId}} =
+      await bp.BluetoothEmulation.addCharacteristic({
+        serviceId: heartRateServiceId,
+        characteristicUuid:
+            BluetoothHelper.MEASUREMENT_INTERVAL_CHARACTERISTIC_UUID,
+        properties: {
+          read: true,
+          write: true,
+          indicate: true,
+        }
+      });
+  await bp.BluetoothEmulation.addDescriptor({
+    characteristicId: measurementIntervalCharacteristicId,
+    descriptorUuid:
+        BluetoothHelper.CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR_UUID
+  });
+
+  const testDescriptorOperations =
+      async (serviceUuid, characteristicUuid, descriptorUuid) => {
+    const devices = await navigator.bluetooth.getDevices();
+    const server = await devices[0].gatt.connect();
+    let readResult;
+    try {
+      const service = await server.getPrimaryService(serviceUuid);
+      const characteristic =
+          await service.getCharacteristic(characteristicUuid);
+      const descriptor = await characteristic.getDescriptor(descriptorUuid);
+      readResult =
+          btoa(await descriptor.readValue().then(value => value.buffer));
+      await descriptor.writeValue(new Uint8Array([1]));
+    } catch (e) {
+      return e.message;
+    }
+    return readResult;
+  };
+
+  // Start the test.
+  testRunner.log(await session.evaluateAsync(
+      testDescriptorOperations, BluetoothHelper.HEART_RATE_SERVICE_UUID,
+      BluetoothHelper.MEASUREMENT_INTERVAL_CHARACTERISTIC_UUID,
+      BluetoothHelper.CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR_UUID));
+
+  testRunner.completeTest();
+});
diff --git a/third_party/blink/web_tests/inspector-protocol/bluetooth/descriptor-read-invalid-param-expected.txt b/third_party/blink/web_tests/inspector-protocol/bluetooth/descriptor-read-invalid-param-expected.txt
new file mode 100644
index 0000000..0a377ad9
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/bluetooth/descriptor-read-invalid-param-expected.txt
@@ -0,0 +1,16 @@
+Tests Bluetooth descriptor read response simulation invalid paramter
+{
+    error : {
+        code : -32602
+        message : Descriptor operation type read with code 0 expects data
+    }
+    id : <number>
+}
+{
+    error : {
+        code : -32602
+        message : Descriptor operation type read with code 8 does not expect data
+    }
+    id : <number>
+}
+
diff --git a/third_party/blink/web_tests/inspector-protocol/bluetooth/descriptor-read-invalid-param.js b/third_party/blink/web_tests/inspector-protocol/bluetooth/descriptor-read-invalid-param.js
new file mode 100644
index 0000000..247b000
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/bluetooth/descriptor-read-invalid-param.js
@@ -0,0 +1,54 @@
+(async function(/** @type {import('test_runner').TestRunner} */ testRunner) {
+  const {session, dp} = await testRunner.startBlank(
+      'Tests Bluetooth descriptor read response simulation invalid paramter');
+  const bp = testRunner.browserP();
+  await dp.Page.enable();
+  await dp.Runtime.enable();
+  const BluetoothHelper =
+      await testRunner.loadScript('resources/bluetooth-helper.js')
+  const helper = new BluetoothHelper(testRunner, dp, session);
+  await helper.setupPreconnectedPeripheral();
+  // Setup UUIDs.
+  const {result: {serviceId: heartRateServiceId}} =
+      await bp.BluetoothEmulation.addService({
+        address: helper.peripheralAddress(),
+        serviceUuid: BluetoothHelper.HEART_RATE_SERVICE_UUID,
+      });
+  const {result: {characteristicId: measurementIntervalCharacteristicId}} =
+      await bp.BluetoothEmulation.addCharacteristic({
+        serviceId: heartRateServiceId,
+        characteristicUuid:
+            BluetoothHelper.MEASUREMENT_INTERVAL_CHARACTERISTIC_UUID,
+        properties: {
+          read: true,
+          write: true,
+          indicate: true,
+        }
+      });
+  const {result: {descriptorId: userDescriptionDescriptorId}} =
+      await bp.BluetoothEmulation.addDescriptor({
+        characteristicId: measurementIntervalCharacteristicId,
+        descriptorUuid:
+            BluetoothHelper.CHARACTERISTIC_USER_DESCRIPTION_DESCRIPTOR_UUID
+      });
+
+  // Start test.
+  const resultSuccessCodeWithoutData =
+      await bp.BluetoothEmulation.simulateDescriptorOperationResponse({
+        descriptorId: userDescriptionDescriptorId,
+        type: 'read',
+        code: BluetoothHelper.HCI_SUCCESS
+      });
+  testRunner.log(resultSuccessCodeWithoutData);
+
+  const resultTimeoutCodeWithData =
+      await bp.BluetoothEmulation.simulateDescriptorOperationResponse({
+        descriptorId: userDescriptionDescriptorId,
+        type: 'read',
+        code: BluetoothHelper.HCI_CONNECTION_TIMEOUT,
+        data: 'W29iamVjdCBBcnJheUJ1ZmZlcl0='
+      });
+  testRunner.log(resultTimeoutCodeWithData);
+
+  testRunner.completeTest();
+});
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
index ad23eeb..e1084b90 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -2228,7 +2228,9 @@
 [Worker]     getter displayHeight
 [Worker]     getter displayWidth
 [Worker]     getter duration
+[Worker]     getter flip
 [Worker]     getter format
+[Worker]     getter rotation
 [Worker]     getter timestamp
 [Worker]     getter visibleRect
 [Worker]     method allocationSize
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 2fa6c563..62ae0652 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -9658,7 +9658,9 @@
     getter displayHeight
     getter displayWidth
     getter duration
+    getter flip
     getter format
+    getter rotation
     getter timestamp
     getter visibleRect
     method allocationSize
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-abort.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-abort.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/language-model-api-abort.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/language-model-api-abort.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-availability.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-availability.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/language-model-api-availability.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/language-model-api-availability.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-clone.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-clone.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/language-model-api-clone.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/language-model-api-clone.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-count-prompt-tokens.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-count-prompt-tokens.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/language-model-api-count-prompt-tokens.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/language-model-api-count-prompt-tokens.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-create.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-create.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/language-model-api-create.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/language-model-api-create.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-destroy.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-destroy.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/language-model-api-destroy.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/language-model-api-destroy.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-params.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-params.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/language-model-api-params.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/language-model-api-params.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-gc.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-gc.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-gc.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-gc.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-monitor-callback-exception.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-monitor-callback-exception.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-monitor-callback-exception.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-monitor-callback-exception.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-quota-exceeded.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-quota-exceeded.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-quota-exceeded.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-quota-exceeded.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-quota-overflow.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-quota-overflow.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-quota-overflow.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-quota-overflow.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-streaming-gc.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-streaming-gc.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-streaming-gc.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-streaming-gc.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-streaming.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-streaming.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-streaming.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt-streaming.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/language-model-api-prompt.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-quota-exceeded.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-quota-exceeded.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/language-model-api-quota-exceeded.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/language-model-api-quota-exceeded.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/language-model-api-response-json-schema.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/language-model-api-response-json-schema.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/language-model-api-response-json-schema.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/language-model-api-response-json-schema.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/rewriter-api-abort.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/rewriter-api-abort.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/rewriter-api-abort.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/rewriter-api-abort.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/rewriter-api-slow.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/rewriter-api-slow.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/rewriter-api-slow.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/rewriter-api-slow.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/rewriter-api.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/rewriter-api.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/rewriter-api.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/rewriter-api.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/writer-api-abort.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/writer-api-abort.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/writer-api-abort.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/writer-api-abort.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/writer-api-slow.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/writer-api-slow.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/writer-api-slow.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/writer-api-slow.https.window.js
diff --git a/third_party/blink/web_tests/wpt_internal/ai/writer-api.https.any.js b/third_party/blink/web_tests/wpt_internal/ai/writer-api.https.window.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/ai/writer-api.https.any.js
rename to third_party/blink/web_tests/wpt_internal/ai/writer-api.https.window.js
diff --git a/third_party/boringssl/src b/third_party/boringssl/src
index a70ec8d..ab301d0 160000
--- a/third_party/boringssl/src
+++ b/third_party/boringssl/src
@@ -1 +1 @@
-Subproject commit a70ec8dd2cc1816e9deadda2f6e536640380e20c
+Subproject commit ab301d01c2bf15da3716500e518425c085c25503
diff --git a/third_party/catapult b/third_party/catapult
index 083971e..0f4bac5 160000
--- a/third_party/catapult
+++ b/third_party/catapult
@@ -1 +1 @@
-Subproject commit 083971e6b02dd794b3cb84d01033455889be7976
+Subproject commit 0f4bac59a38c6aa5ad9874778f822d76ea737d35
diff --git a/third_party/dawn b/third_party/dawn
index bddeca3..3d21836 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit bddeca3e8f226b857070fb90b6068886fee7a93e
+Subproject commit 3d21836f05819cda0631ba692b9a7dbb536f2ec8
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index 520dadf..6c841fc 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit 520dadff7b7ab40a273f261ca5d5253be7fb3710
+Subproject commit 6c841fc0da4e1eeec9f198fd14167572e1f6656a
diff --git a/third_party/grpc/OWNERS b/third_party/grpc/OWNERS
index 9ebedac..b6f8a891 100644
--- a/third_party/grpc/OWNERS
+++ b/third_party/grpc/OWNERS
@@ -1,6 +1,2 @@
 # Chromecast team members
-file://chromecast/CHROMECAST_OWNERS
-
-# libassistant team members
-yawano@google.com
-xiaohuic@chromium.org
+file://chromecast/CHROMECAST_OWNERS
\ No newline at end of file
diff --git a/third_party/llvm-libc/src b/third_party/llvm-libc/src
index c43b02c..bf95cc5 160000
--- a/third_party/llvm-libc/src
+++ b/third_party/llvm-libc/src
@@ -1 +1 @@
-Subproject commit c43b02cfdbd4a75e9ba233f3b5bfd8322e3bf1d8
+Subproject commit bf95cc5da608540ccddbd22f1866d713eaba3ac8
diff --git a/third_party/pdfium b/third_party/pdfium
index d45defc..f92aa15 160000
--- a/third_party/pdfium
+++ b/third_party/pdfium
@@ -1 +1 @@
-Subproject commit d45defc2d92a7961131319d92b35eba648926707
+Subproject commit f92aa15fa160f203a0064ec9b7e4a853784d0134
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index a8fced6..9ee0ee6 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -27295,17 +27295,23 @@
 
 <action name="MobileToolbarBackInNewBackgroundTab">
   <owner>jhimawan@google.com</owner>
-  <description>TBD(jhimawan)</description>
+  <description>
+    The user navigated back, opening the page in a background tab.
+  </description>
 </action>
 
 <action name="MobileToolbarBackInNewForegroundTab">
   <owner>jhimawan@google.com</owner>
-  <description>TBD(jhimawan)</description>
+  <description>
+    The user navigated back, opening the page in a foreground tab.
+  </description>
 </action>
 
 <action name="MobileToolbarBackInNewForegroundWindow">
   <owner>jhimawan@google.com</owner>
-  <description>TBD(jhimawan)</description>
+  <description>
+    The user navigated back, opening the page in a foreground window.
+  </description>
 </action>
 
 <action name="MobileToolbarCloseAllIncognitoTabsButtonTap">
@@ -27355,6 +27361,27 @@
   <description>Please enter the description of this user action.</description>
 </action>
 
+<action name="MobileToolbarForwardInNewBackgroundTab">
+  <owner>jhimawan@google.com</owner>
+  <description>
+    The user navigated forward, opening the page in a background tab.
+  </description>
+</action>
+
+<action name="MobileToolbarForwardInNewForegroundTab">
+  <owner>jhimawan@google.com</owner>
+  <description>
+    The user navigated forward, opening the page in a foreground tab.
+  </description>
+</action>
+
+<action name="MobileToolbarForwardInNewForegroundWindow">
+  <owner>jhimawan@google.com</owner>
+  <description>
+    The user navigated forward, opening the page in a foreground window.
+  </description>
+</action>
+
 <action name="MobileToolbarIdentityDiscTap">
   <owner>pavely@chromium.org</owner>
   <owner>clank-app-team@google.com</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 44b19e0..e691575 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -2068,7 +2068,8 @@
   <int value="15" label="YouTube"/>
   <int value="16" label="Camera"/>
   <int value="17" label="Pixel Launcher"/>
-  <int value="18" label="Third-party Launcher"/>
+  <int value="18" label="Third-party Launcher (Deprecated)"/>
+  <int value="19" label="Samsung Launcher"/>
 </enum>
 
 <!-- LINT.IfChange(ClientSummarizedResultType) -->
@@ -7425,7 +7426,7 @@
 
 <enum name="LanguageName">
   <summary>
-    Deprecated: Instead use LocaleCodeISO639 since it supports script tags and
+    Deprecated: Instead use LocaleCodeBCP47 since it supports script tags and
     three letter language codes unlike LanguageName.
 
     Hash values for the first two letters of a locale code. This is mapped to
@@ -8403,11 +8404,12 @@
   <int value="11" label="Invalid base model version"/>
 </enum>
 
-<enum name="LocaleCodeISO639">
+<enum name="LocaleCodeBCP47">
   <summary>
-    Hash values for ISO 639 locale codes (including country and script tags e.g
-    &quot;en-US&quot;). Each of these values is computed by casting the output
-    of base::HashMetricName(locale_string_id) to base::HistogramBase::Sample. JS
+    Hash values for BCP47 locale codes (including country and script tags e.g
+    &quot;en-US&quot; (i.e. ISO639) or extended BCP47 tags &quot;zh-Hant&quot;).
+    Each of these values is computed by casting the output of
+    base::HashMetricName(locale_string_id) to base::HistogramBase::Sample. JS
     users should use metricsPrivate.recordSparseValueWithHashMetricName().
   </summary>
   <int value="-2132740958" label="gl"/>
@@ -8524,6 +8526,7 @@
   <int value="-644560085" label="su"/>
   <int value="-598481752" label="et"/>
   <int value="-548175087" label="tt"/>
+  <int value="-545951624" label="ar-Latn"/>
   <int value="-450972170" label="oc"/>
   <int value="-442590807" label="sd"/>
   <int value="-441493751" label="el-Latn"/>
@@ -8569,6 +8572,7 @@
   <int value="264824286" label="ksh"/>
   <int value="350748440" label="und"/>
   <int value="357286655" label="af"/>
+  <int value="389407533" label="zh-Hant"/>
   <int value="443574411" label="dz"/>
   <int value="461111861" label="mt"/>
   <int value="462869158" label="hy"/>
diff --git a/tools/metrics/histograms/metadata/accessibility/histograms.xml b/tools/metrics/histograms/metadata/accessibility/histograms.xml
index c2eb6283..69ffb5d 100644
--- a/tools/metrics/histograms/metadata/accessibility/histograms.xml
+++ b/tools/metrics/histograms/metadata/accessibility/histograms.xml
@@ -931,7 +931,7 @@
   </summary>
 </histogram>
 
-<histogram name="Accessibility.CrosDictation.Language" enum="LocaleCodeISO639"
+<histogram name="Accessibility.CrosDictation.Language" enum="LocaleCodeBCP47"
     expires_after="2026-03-30">
   <owner>katie@chromium.org</owner>
   <owner>dtseng@chromium.org</owner>
@@ -2093,7 +2093,7 @@
 </histogram>
 
 <histogram name="Accessibility.LiveTranslate.Ash.Boca.Babelorca.TargetLanguage"
-    enum="LocaleCodeISO639" expires_after="2025-10-12">
+    enum="LocaleCodeBCP47" expires_after="2025-10-12">
   <owner>caott@google.com</owner>
   <owner>cros-edu-eng@google.com</owner>
   <summary>
@@ -2130,7 +2130,7 @@
 </histogram>
 
 <histogram name="Accessibility.LiveTranslate.SourceLanguage"
-    enum="LocaleCodeISO639" expires_after="2025-10-19">
+    enum="LocaleCodeBCP47" expires_after="2025-10-19">
   <owner>evliu@google.com</owner>
   <owner>chrome-media-ux@google.com</owner>
   <summary>
@@ -2140,7 +2140,7 @@
 </histogram>
 
 <histogram name="Accessibility.LiveTranslate.TargetLanguage"
-    enum="LocaleCodeISO639" expires_after="2025-10-19">
+    enum="LocaleCodeBCP47" expires_after="2025-10-19">
   <owner>evliu@google.com</owner>
   <owner>chrome-media-ux@google.com</owner>
   <summary>
@@ -2329,7 +2329,7 @@
 </histogram>
 
 <histogram name="Accessibility.PdfOcr.UserAcceptLanguage"
-    enum="LocaleCodeISO639" expires_after="2025-10-26">
+    enum="LocaleCodeBCP47" expires_after="2025-10-26">
   <owner>kyungjunlee@google.com</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
@@ -2899,7 +2899,7 @@
   </summary>
 </histogram>
 
-<histogram name="Accessibility.ReadAnything.Language" enum="LocaleCodeISO639"
+<histogram name="Accessibility.ReadAnything.Language" enum="LocaleCodeBCP47"
     expires_after="2026-01-30">
   <owner>abigailbklein@google.com</owner>
   <owner>chrome-a11y-core@google.com</owner>
@@ -2981,7 +2981,7 @@
 </histogram>
 
 <histogram name="Accessibility.ReadAnything.ReadAloud.Language"
-    enum="LocaleCodeISO639" expires_after="2025-09-07">
+    enum="LocaleCodeBCP47" expires_after="2025-09-07">
   <owner>kristislee@google.com</owner>
   <owner>komo-eng@google.com</owner>
   <summary>
@@ -3312,7 +3312,7 @@
 </histogram>
 
 <histogram name="Accessibility.ScreenAI.OCR.MostDetectedLanguage.PDF"
-    enum="LocaleCodeISO639" expires_after="2025-12-01">
+    enum="LocaleCodeBCP47" expires_after="2025-12-01">
   <owner>rhalavati@chromium.org</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/ai/histograms.xml b/tools/metrics/histograms/metadata/ai/histograms.xml
index 0d34f26c..727da8ef 100644
--- a/tools/metrics/histograms/metadata/ai/histograms.xml
+++ b/tools/metrics/histograms/metadata/ai/histograms.xml
@@ -206,7 +206,7 @@
 
 <histogram
     name="AI.{WritingAssistanceType}.APIUsage.{WritingAssistanceFunctionName}.{LanguageMetric}"
-    enum="LocaleCodeISO639" expires_after="2025-10-27">
+    enum="LocaleCodeBCP47" expires_after="2025-10-27">
   <owner>btriebw@chromium.org</owner>
   <owner>ayui@chromium.org</owner>
   <owner>src/chrome/browser/ai/OWNERS</owner>
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml
index 62b8fe8e..cfe19b85 100644
--- a/tools/metrics/histograms/metadata/arc/histograms.xml
+++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -555,7 +555,7 @@
 </histogram>
 
 <histogram name="Arc.AppLanguageSwitch.{SettingsPage}.TargetLanguage"
-    enum="LocaleCodeISO639" expires_after="2025-08-10">
+    enum="LocaleCodeBCP47" expires_after="2025-08-10">
   <owner>nergi@chromium.org</owner>
   <owner>arc-framework@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 32850a3..07de650e 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -1359,6 +1359,15 @@
   </token>
 </histogram>
 
+<histogram name="Ash.Boca.TokenRetrievalIsValidation" enum="Boolean"
+    expires_after="2025-10-28">
+  <owner>zifanzhang@google.com</owner>
+  <owner>cros-edu-eng@google.com</owner>
+  <summary>
+    Records the number of validation and non-validation token Retrievals.
+  </summary>
+</histogram>
+
 <histogram name="Ash.Boca.{Request}.ErrorCode" enum="ApiErrorCode"
     expires_after="2025-10-23">
   <owner>zifanzhang@google.com</owner>
@@ -2440,7 +2449,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.AnimationSmoothness.DeskRemoval" units="%"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>tclaiborne@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2491,8 +2500,8 @@
 </histogram>
 
 <histogram name="Ash.Desks.ConsecutiveDailyVisits" units="days"
-    expires_after="2025-10-01">
-  <owner>dandersson@google.com</owner>
+    expires_after="2025-10-08">
+  <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2508,8 +2517,8 @@
 </histogram>
 
 <histogram name="Ash.Desks.CustomNameCount" units="desks"
-    expires_after="2025-10-30">
-  <owner>dandersson@google.com</owner>
+    expires_after="2025-10-08">
+  <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2519,8 +2528,8 @@
 </histogram>
 
 <histogram name="Ash.Desks.CustomNameCreated" enum="BooleanHit"
-    expires_after="2025-10-30">
-  <owner>dandersson@google.com</owner>
+    expires_after="2025-10-08">
+  <owner>dandersson@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2530,8 +2539,8 @@
 </histogram>
 
 <histogram name="Ash.Desks.CustomNamePercentage" units="%"
-    expires_after="2025-10-30">
-  <owner>dandersson@google.com</owner>
+    expires_after="2025-10-08">
+  <owner>dandersson@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2541,7 +2550,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.DeskButton.DeskBar.Enter.PresentationTime"
-    units="ms" expires_after="2025-10-12">
+    units="ms" expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2553,7 +2562,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.DeskButton.DeskBar.Exit.PresentationTime" units="ms"
-    expires_after="2025-08-10">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2565,7 +2574,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.DeskButton.HiddenByUser" enum="BooleanHit"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2576,7 +2585,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.DeskButton.Presses" enum="BooleanHit"
-    expires_after="2025-06-08">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2637,7 +2646,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.DesksSwitchScreenshotResult" enum="BooleanSuccess"
-    expires_after="2025-10-05">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2646,7 +2655,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.MoveWindowFromActiveDesk"
-    enum="DesksMoveWindowFromActiveDeskSource" expires_after="2025-10-01">
+    enum="DesksMoveWindowFromActiveDeskSource" expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2674,7 +2683,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfDeskTraversals" units="units"
-    expires_after="2025-07-27">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
   <summary>
@@ -2687,7 +2696,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsClosed2" units="units"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2699,7 +2708,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsClosed2.{RemovalSource}"
-    units="windows" expires_after="2025-10-01">
+    units="windows" expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2716,7 +2725,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_1" units="units"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2727,7 +2736,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_10" units="units"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2738,7 +2747,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_11" units="units"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2749,7 +2758,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_12" units="units"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2760,7 +2769,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_13" units="units"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2771,7 +2780,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_14" units="units"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2782,7 +2791,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_15" units="units"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2793,7 +2802,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_16" units="units"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2804,7 +2813,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_2" units="units"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2815,7 +2824,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_3" units="units"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2826,7 +2835,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_4" units="units"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2837,7 +2846,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_5" units="units"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2848,7 +2857,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_6" units="units"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2859,7 +2868,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_7" units="units"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2870,7 +2879,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_8" units="units"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2881,7 +2890,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.NumberOfWindowsOnDesk_9" units="units"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2892,7 +2901,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.PresentationTime.UpdateGesture" units="ms"
-    expires_after="2026-01-29">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>tclaiborne@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2906,7 +2915,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.PresentationTime.UpdateGesture.MaxLatency"
-    units="ms" expires_after="2026-01-29">
+    units="ms" expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>tclaiborne@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2921,7 +2930,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.RemoveDesk" enum="DesksCreationRemovalSource"
-    expires_after="2025-10-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2960,7 +2969,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.{EntryPoint}.BarAction.{BarAction}"
-    enum="BooleanHit" expires_after="2025-10-01">
+    enum="BooleanHit" expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>yongshun@chromium.org</owner>
   <owner>chromeos-wm@google.com</owner>
@@ -2987,7 +2996,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTamplate.LaunchAdminTemplate" enum="BooleanHit"
-    expires_after="2025-08-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>chromeos-wms@google.com</owner>
@@ -2995,8 +3004,8 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.AddOrUpdateTemplateStatus"
-    enum="DeskModelAddOrUpdateEntryStatus" expires_after="2025-08-01">
-  <owner>dandersson@google.com</owner>
+    enum="DeskModelAddOrUpdateEntryStatus" expires_after="2025-10-08">
+  <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
     Emitted when a desk template is added or updated to indicate result of this
@@ -3006,7 +3015,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.AdminTemplateTabCount" units="count"
-    expires_after="2025-08-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3015,7 +3024,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.AdminTemplateWindowCount" units="count"
-    expires_after="2025-08-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3024,7 +3033,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.DeleteSaveAndRecall" enum="BooleanHit"
-    expires_after="2025-08-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3033,8 +3042,8 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.DeleteTemplate" enum="BooleanHit"
-    expires_after="2025-08-01">
-  <owner>dandersson@google.com</owner>
+    expires_after="2025-10-08">
+  <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>Recorded when desk templates are deleted, is never false.</summary>
 </histogram>
@@ -3075,7 +3084,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.LaunchFromTemplate" enum="BooleanHit"
-    expires_after="2025-08-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3084,15 +3093,15 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.LaunchSaveAndRecall" enum="BooleanHit"
-    expires_after="2025-08-10">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>Emitted when a Save and Recall desk is launched.</summary>
 </histogram>
 
 <histogram name="Ash.DeskTemplate.LoadTemplateGrid" enum="BooleanHit"
-    expires_after="2025-08-01">
-  <owner>dandersson@google.com</owner>
+    expires_after="2025-10-08">
+  <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
     Recorded when a user opens the template grid, is never false.
@@ -3100,15 +3109,15 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.NewSaveAndRecall" enum="BooleanHit"
-    expires_after="2025-10-12">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>Recorded when a new Save and Recall desk is created.</summary>
 </histogram>
 
 <histogram name="Ash.DeskTemplate.NewTemplate" enum="BooleanHit"
-    expires_after="2025-08-01">
-  <owner>dandersson@google.com</owner>
+    expires_after="2025-10-08">
+  <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
     Recorded when a user creates a desk template, is never false.
@@ -3116,15 +3125,15 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.ReplaceSaveAndRecall" enum="BooleanHit"
-    expires_after="2025-10-26">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>Recorded when the user replaces a Save and Recall desk.</summary>
 </histogram>
 
 <histogram name="Ash.DeskTemplate.ReplaceTemplate" enum="BooleanHit"
-    expires_after="2025-08-01">
-  <owner>dandersson@google.com</owner>
+    expires_after="2025-10-08">
+  <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
     Recorded when replace dialog opens and user accepted it, is never false.
@@ -3132,7 +3141,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.SaveAndRecallLocalDeskSavedDeskParseError"
-    enum="SavedDeskParseError" expires_after="2025-08-01">
+    enum="SavedDeskParseError" expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <owner>yzd@google.com</owner>
@@ -3140,7 +3149,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.SaveAndRecallTabCount" units="count"
-    expires_after="2025-08-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3149,8 +3158,8 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.SaveAndRecallTemplateSize" units="B"
-    expires_after="2025-06-08">
-  <owner>dandersson@google.com</owner>
+    expires_after="2025-10-08">
+  <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
     Records the save and recall template file size that is saved to local
@@ -3159,8 +3168,8 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.SaveAndRecallUnsupportedAppDialogShow"
-    units="count" expires_after="2025-08-01">
-  <owner>dandersson@google.com</owner>
+    units="count" expires_after="2025-10-08">
+  <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
     Records the number of times the unsupported Apps dialog shows. This event is
@@ -3171,7 +3180,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.SaveAndRecallWindowAndTabCount" units="count"
-    expires_after="2025-08-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3181,7 +3190,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.SaveAndRecallWindowCount" units="count"
-    expires_after="2025-08-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3251,15 +3260,15 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.TabCount" units="count"
-    expires_after="2025-08-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>Records the number of tabs in a template when it is saved.</summary>
 </histogram>
 
 <histogram name="Ash.DeskTemplate.TemplateSize" units="B"
-    expires_after="2025-08-01">
-  <owner>dandersson@google.com</owner>
+    expires_after="2025-10-08">
+  <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
     Records the file size of the desk template that is saved to local storage.
@@ -3267,7 +3276,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.TimeBetweenSaveAndRecall" units="seconds"
-    expires_after="2025-08-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3277,8 +3286,8 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.TimeToLoadTemplate" units="ms"
-    expires_after="2025-08-01">
-  <owner>dandersson@google.com</owner>
+    expires_after="2025-10-08">
+  <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
     Measures the amount of time it takes to launch a template from the time that
@@ -3287,8 +3296,8 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.UnsupportedAppDialogShow" units="count"
-    expires_after="2025-08-01">
-  <owner>dandersson@google.com</owner>
+    expires_after="2025-10-08">
+  <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
     Records the number of times the unsupported Apps dialog shows. This event is
@@ -3299,7 +3308,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.UserSaveAndRecallCount" units="count"
-    expires_after="2025-08-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3309,7 +3318,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.UserTemplateCount" units="count"
-    expires_after="2025-08-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3319,7 +3328,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.WindowAndTabCount" units="count"
-    expires_after="2025-08-01">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3328,7 +3337,7 @@
 </histogram>
 
 <histogram name="Ash.DeskTemplate.WindowCount" units="count"
-    expires_after="2025-10-26">
+    expires_after="2025-10-08">
   <owner>dandersson@chromium.org</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/glic/enums.xml b/tools/metrics/histograms/metadata/glic/enums.xml
index 5355ccf3..5ce8fc4 100644
--- a/tools/metrics/histograms/metadata/glic/enums.xml
+++ b/tools/metrics/histograms/metadata/glic/enums.xml
@@ -47,6 +47,20 @@
 
 <!-- LINT.ThenChange(//chrome/browser/glic/glic_metrics.h:AttachChangeReason) -->
 
+<!-- LINT.IfChange(GlicDetailedWebClientState) -->
+
+<enum name="GlicDetailedWebClientState">
+  <int value="0" label="Bootstrap pending"/>
+  <int value="1" label="Web client not created"/>
+  <int value="2" label="Web client initialize failed"/>
+  <int value="3" label="Web client created but not initialized"/>
+  <int value="4" label="Temporary unresponsive"/>
+  <int value="5" label="Permanent unresponsive"/>
+  <int value="6" label="Responsive"/>
+</enum>
+
+<!-- LINT.ThenChange(//chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts:DetailedWebClientState) -->
+
 <!-- LINT.IfChange(GlicEntryPointImpression) -->
 
 <enum name="GlicEntryPointImpression">
diff --git a/tools/metrics/histograms/metadata/glic/histograms.xml b/tools/metrics/histograms/metadata/glic/histograms.xml
index a8c060c..b89f4469 100644
--- a/tools/metrics/histograms/metadata/glic/histograms.xml
+++ b/tools/metrics/histograms/metadata/glic/histograms.xml
@@ -160,6 +160,20 @@
   </summary>
 </histogram>
 
+<histogram name="Glic.Host.WebClientState.{Event}"
+    enum="GlicDetailedWebClientState" expires_after="2026-01-15">
+  <owner>harringtond@chromium.org</owner>
+  <owner>carlosk@chromium.org</owner>
+  <summary>Records the web client state according to the host. {Event}</summary>
+  <token key="Event">
+    <variant name="AtOneMinute"
+        summary="Recorded one minute after loading the webview."/>
+    <variant name="OnCommit" summary="Recorded before commit on the webview."/>
+    <variant name="OnDestroy"
+        summary="Recorded before the webview is destroyed."/>
+  </token>
+</histogram>
+
 <histogram name="Glic.Metrics.Error" enum="GlicMetricsError"
     expires_after="2026-01-15">
   <owner>dewittj@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/gpu/histograms.xml b/tools/metrics/histograms/metadata/gpu/histograms.xml
index 21a7557..09fd10c 100644
--- a/tools/metrics/histograms/metadata/gpu/histograms.xml
+++ b/tools/metrics/histograms/metadata/gpu/histograms.xml
@@ -553,11 +553,12 @@
 </histogram>
 
 <histogram name="GPU.Dawn.InfoCollectionTimeMS" units="ms"
-    expires_after="2024-06-25">
+    expires_after="2026-04-28">
   <owner>enga@chromium.org</owner>
   <owner>mdb.webgpu-dev-team@google.com</owner>
   <summary>
     Measures the time to collect Dawn information during GPU info collection.
+    NOTE: metric expired from 2024-06-25 to 2025-05-01.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/image/histograms.xml b/tools/metrics/histograms/metadata/image/histograms.xml
index 0150630..928954e 100644
--- a/tools/metrics/histograms/metadata/image/histograms.xml
+++ b/tools/metrics/histograms/metadata/image/histograms.xml
@@ -53,9 +53,10 @@
       summary="Showing cache patterns only for AssistantDetails."/>
   <variant name=".AutofillCardArt"
       summary="Show customized card-art image for credit card suggestions on
-               Android."/>
+               Android (Used up to M137, will log as 'AutofillImageFetcher'
+               from M138)."/>
   <variant name=".AutofillImageFetcher"
-      summary="Show customized card art image for credit card."/>
+      summary="Downloads various Autofill related images."/>
   <variant name=".AutofillPasswordFavicon"
       summary="Requesting favicons associated with credentials directly from
                websites."/>
diff --git a/tools/metrics/histograms/metadata/language/histograms.xml b/tools/metrics/histograms/metadata/language/histograms.xml
index 7202e59..9d0ff8dd 100644
--- a/tools/metrics/histograms/metadata/language/histograms.xml
+++ b/tools/metrics/histograms/metadata/language/histograms.xml
@@ -50,7 +50,7 @@
 
 <histogram
     name="LanguageDetection.TFLiteModel.ClassifyText.HighestConfidenceLanguage"
-    enum="LocaleCodeISO639" expires_after="2025-09-28">
+    enum="LocaleCodeBCP47" expires_after="2025-09-28">
   <owner>fergal@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -237,7 +237,7 @@
 </histogram>
 
 <histogram name="LanguageSettings.AppLanguagePrompt.Language"
-    enum="LocaleCodeISO639" expires_after="2025-12-10">
+    enum="LocaleCodeBCP47" expires_after="2025-12-10">
   <owner>perrier@chromium.org</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -454,7 +454,7 @@
 </histogram>
 
 <histogram name="LanguageUsage.UI.Android.OverrideLanguage"
-    enum="LocaleCodeISO639" expires_after="2025-09-28">
+    enum="LocaleCodeBCP47" expires_after="2025-09-28">
   <owner>perrier@chromium.org</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -538,7 +538,7 @@
 </histogram>
 
 <histogram name="LanguageUsage.ULP.Initiation.NeverLanguagesMissingFromULP"
-    enum="LocaleCodeISO639" expires_after="2025-12-10">
+    enum="LocaleCodeBCP47" expires_after="2025-12-10">
   <owner>perrier@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -562,7 +562,7 @@
 </histogram>
 
 <histogram name="LanguageUsage.ULP.Initiation.PageLanguagesMissingFromULP"
-    enum="LocaleCodeISO639" expires_after="2025-12-10">
+    enum="LocaleCodeBCP47" expires_after="2025-12-10">
   <owner>perrier@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/lens/enums.xml b/tools/metrics/histograms/metadata/lens/enums.xml
index c89d3ae35..bee07f9 100644
--- a/tools/metrics/histograms/metadata/lens/enums.xml
+++ b/tools/metrics/histograms/metadata/lens/enums.xml
@@ -236,9 +236,10 @@
   <int value="1" label="Result shown"/>
   <int value="2" label="Error page shown (offline)"/>
   <int value="3" label="Error page shown (start query response error)"/>
+  <int value="4" label="Error page shown (protected)"/>
 </enum>
 
-<!-- LINT.ThenChange(//components/lens/lens_overlay_side_panel_result.h:LensOverlaySidePanelResultStatus) -->
+<!-- LINT.ThenChange(//components/lens/lens_overlay_side_panel_result.h:LensOverlaySidePanelResultStatus,//chrome/browser/lens/core/mojom/lens_side_panel.mojom:SidePanelResultStatus) -->
 
 </enums>
 
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index 69fbce35..d30b9c2 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -4864,7 +4864,7 @@
 </histogram>
 
 <histogram name="Media.Notification.Cast.Count" units="count"
-    expires_after="2025-06-08">
+    expires_after="2026-05-01">
   <owner>muyaoxu@google.com</owner>
   <owner>openscreen-eng@google.com</owner>
   <owner>media-dev-uma@chromium.org</owner>
@@ -4875,7 +4875,7 @@
 </histogram>
 
 <histogram name="Media.Notification.Cast.UserAction" enum="MediaSessionAction"
-    expires_after="2025-06-08">
+    expires_after="2026-05-01">
   <owner>muyaoxu@google.com</owner>
   <owner>openscreen-eng@google.com</owner>
   <owner>media-dev-uma@chromium.org</owner>
@@ -7602,7 +7602,7 @@
 </histogram>
 
 <histogram name="MediaRouter.Cast.LaunchSessionResponse.AppType"
-    enum="MediaRouterResponseReceiverAppType" expires_after="2025-05-11">
+    enum="MediaRouterResponseReceiverAppType" expires_after="2026-05-01">
   <owner>muyaoxu@google.com</owner>
   <owner>openscreen-eng@google.com</owner>
   <summary>
@@ -7836,7 +7836,7 @@
 </histogram>
 
 <histogram name="MediaRouter.Icon.Click.Location"
-    enum="MediaRouterDialogActivationLocation" expires_after="2025-05-04">
+    enum="MediaRouterDialogActivationLocation" expires_after="2026-05-01">
   <owner>muyaoxu@google.com</owner>
   <owner>openscreen-eng@google.com</owner>
   <summary>Location the user clicked to open the Media Router dialog.</summary>
@@ -7866,7 +7866,7 @@
 </histogram>
 
 <histogram name="MediaRouter.MirroringService.SessionError"
-    enum="MirroringServiceErrorType" expires_after="2025-05-18">
+    enum="MirroringServiceErrorType" expires_after="2026-05-01">
   <owner>muyaoxu@google.com</owner>
   <owner>openscreen-eng@google.com</owner>
   <summary>
@@ -8024,7 +8024,7 @@
 </histogram>
 
 <histogram name="MediaRouter.Ui.Device.Count" units="units"
-    expires_after="2025-06-08">
+    expires_after="2026-05-01">
   <owner>muyaoxu@google.com</owner>
   <owner>openscreen-eng@google.com</owner>
   <summary>
@@ -8047,7 +8047,7 @@
 </histogram>
 
 <histogram name="MediaRouter.Ui.Dialog.IconStateAtOpen"
-    enum="MediaRouterIconState" expires_after="2025-05-04">
+    enum="MediaRouterIconState" expires_after="2026-05-01">
   <owner>muyaoxu@google.com</owner>
   <owner>openscreen-eng@google.com</owner>
   <summary>
@@ -8082,7 +8082,7 @@
 </histogram>
 
 <histogram name="MediaRouter.WiredDisplay.AvailableDevicesCount" units="units"
-    expires_after="2025-06-08">
+    expires_after="2026-05-01">
   <owner>muyaoxu@google.com</owner>
   <owner>openscreen-eng@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/memory/histograms.xml b/tools/metrics/histograms/metadata/memory/histograms.xml
index cc3cf138..193be8c 100644
--- a/tools/metrics/histograms/metadata/memory/histograms.xml
+++ b/tools/metrics/histograms/metadata/memory/histograms.xml
@@ -974,7 +974,7 @@
 </histogram>
 
 <histogram name="Memory.Browser.MemoryFootprint.Active" units="MB"
-    expires_after="2025-09-14">
+    expires_after="2026-04-29">
   <owner>justincohen@chromium.org</owner>
   <owner>bling-fundamentals@google.com</owner>
   <summary>
@@ -985,7 +985,7 @@
 </histogram>
 
 <histogram name="Memory.Browser.MemoryFootprint.Active.Over200MBWatermark"
-    enum="BooleanGreaterOrEqualThan200MB" expires_after="2026-02-05">
+    enum="BooleanGreaterOrEqualThan200MB" expires_after="2026-04-29">
   <owner>justincohen@chromium.org</owner>
   <owner>bling-fundamentals@google.com</owner>
   <summary>
@@ -1001,7 +1001,7 @@
 </histogram>
 
 <histogram name="Memory.Browser.MemoryFootprint.Background" units="MB"
-    expires_after="2025-08-31">
+    expires_after="2026-04-29">
   <owner>justincohen@chromium.org</owner>
   <owner>bling-fundamentals@google.com</owner>
   <summary>
@@ -1017,7 +1017,7 @@
 </histogram>
 
 <histogram name="Memory.Browser.MemoryFootprint.Inactive" units="MB"
-    expires_after="2025-10-12">
+    expires_after="2026-04-29">
   <owner>justincohen@chromium.org</owner>
   <owner>bling-fundamentals@google.com</owner>
   <summary>
@@ -1030,7 +1030,7 @@
 </histogram>
 
 <histogram name="Memory.Browser.MemoryFootprint.NumOpenTabs" units="tabs"
-    expires_after="2025-09-14">
+    expires_after="2026-04-29">
   <owner>justincohen@chromium.org</owner>
   <owner>rkgibson@google.com</owner>
   <summary>
@@ -1045,7 +1045,7 @@
 </histogram>
 
 <histogram name="Memory.Browser.MemoryFootprint.OnBackground" units="MiB"
-    expires_after="2025-06-08">
+    expires_after="2026-04-29">
   <owner>justincohen@chromium.org</owner>
   <owner>bling-fundamentals@google.com</owner>
   <summary>
@@ -1057,7 +1057,7 @@
 </histogram>
 
 <histogram name="Memory.Browser.MemoryFootprint.Startup" units="MB"
-    expires_after="2025-10-19">
+    expires_after="2026-04-29">
   <owner>justincohen@chromium.org</owner>
   <owner>bling-fundamentals@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/storage/histograms.xml b/tools/metrics/histograms/metadata/storage/histograms.xml
index 37432a9..c95727ab6 100644
--- a/tools/metrics/histograms/metadata/storage/histograms.xml
+++ b/tools/metrics/histograms/metadata/storage/histograms.xml
@@ -882,6 +882,36 @@
   </summary>
 </histogram>
 
+<histogram name="Storage.DomStorage.BatchTaskGrowthSizeBytes" units="bytes"
+    expires_after="2025-10-23">
+  <owner>annasato@chromium.org</owner>
+  <owner>chrome-owp-storage@google.com</owner>
+  <summary>
+    Records the approximate growth in bytes of the leveldb::WriteBatch after
+    processing a single task within
+    AsyncDomStorageDatabase::RunBatchDatabaseTasks. Helps understand if
+    individual tasks contribute significantly to batch size. Recorded for each
+    task in the batch. See crbug.com/40245293.
+  </summary>
+</histogram>
+
+<histogram name="Storage.DomStorage.IterationsToReach{Size}MB" units="count"
+    expires_after="2025-10-23">
+  <owner>annasato@chromium.org</owner>
+  <owner>chrome-owp-storage@google.com</owner>
+  <summary>
+    Records the number of iterations (tasks processed) required for the
+    leveldb::WriteBatch in AsyncDomStorageDatabase::RunBatchDatabaseTasks to
+    first reach an approximate size of {Size} MiB. Recorded at most once per
+    batch. See crbug.com/40245293.
+  </summary>
+  <token key="Size">
+    <variant name="20"/>
+    <variant name="100"/>
+    <variant name="500"/>
+  </token>
+</histogram>
+
 <histogram name="Storage.FileSystemAccess.AttemptToObserveSymlinkOrJunction"
     enum="Boolean" expires_after="2025-09-01">
   <owner>memmott@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/translate/histograms.xml b/tools/metrics/histograms/metadata/translate/histograms.xml
index d1f39ce6..9c245db 100644
--- a/tools/metrics/histograms/metadata/translate/histograms.xml
+++ b/tools/metrics/histograms/metadata/translate/histograms.xml
@@ -81,7 +81,7 @@
 <!-- LINT.ThenChange(//chrome/browser/on_device_translation/language_pack_util.h:SupportedLanguage) -->
 
 <histogram name="Translate.ApplicationStart.AlwaysTranslateLanguage"
-    enum="LocaleCodeISO639" expires_after="2025-08-24">
+    enum="LocaleCodeBCP47" expires_after="2025-08-24">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -107,7 +107,7 @@
 </histogram>
 
 <histogram name="Translate.ApplicationStart.NeverTranslateLanguage"
-    enum="LocaleCodeISO639" expires_after="2025-08-10">
+    enum="LocaleCodeBCP47" expires_after="2025-08-10">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -144,7 +144,7 @@
   </summary>
 </histogram>
 
-<histogram name="Translate.CLD3.LanguageDetected" enum="LocaleCodeISO639"
+<histogram name="Translate.CLD3.LanguageDetected" enum="LocaleCodeBCP47"
     expires_after="2025-09-28">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
@@ -356,8 +356,8 @@
   <token key="LanguageRole" variants="LanguageRole"/>
 </histogram>
 
-<histogram name="Translate.PageLoad.FinalSourceLanguage"
-    enum="LocaleCodeISO639" expires_after="2025-08-24">
+<histogram name="Translate.PageLoad.FinalSourceLanguage" enum="LocaleCodeBCP47"
+    expires_after="2025-08-24">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -382,8 +382,8 @@
   </summary>
 </histogram>
 
-<histogram name="Translate.PageLoad.FinalTargetLanguage"
-    enum="LocaleCodeISO639" expires_after="2025-12-10">
+<histogram name="Translate.PageLoad.FinalTargetLanguage" enum="LocaleCodeBCP47"
+    expires_after="2025-12-10">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -408,7 +408,7 @@
 </histogram>
 
 <histogram name="Translate.PageLoad.InitialSourceLanguage"
-    enum="LocaleCodeISO639" expires_after="2025-12-10">
+    enum="LocaleCodeBCP47" expires_after="2025-12-10">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -434,7 +434,7 @@
 </histogram>
 
 <histogram name="Translate.PageLoad.InitialTargetLanguage"
-    enum="LocaleCodeISO639" expires_after="2025-10-19">
+    enum="LocaleCodeBCP47" expires_after="2025-10-19">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -598,7 +598,7 @@
 </histogram>
 
 <histogram name="Translate.PartialTranslation.SourceLanguage"
-    enum="LocaleCodeISO639" expires_after="2025-12-10">
+    enum="LocaleCodeBCP47" expires_after="2025-12-10">
   <owner>cuianthony@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -608,7 +608,7 @@
 </histogram>
 
 <histogram name="Translate.PartialTranslation.TargetLanguage"
-    enum="LocaleCodeISO639" expires_after="2025-12-10">
+    enum="LocaleCodeBCP47" expires_after="2025-12-10">
   <owner>cuianthony@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -674,7 +674,7 @@
   </summary>
 </histogram>
 
-<histogram name="Translate.Translation.SourceLanguage" enum="LocaleCodeISO639"
+<histogram name="Translate.Translation.SourceLanguage" enum="LocaleCodeBCP47"
     expires_after="2025-10-19">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
@@ -705,7 +705,7 @@
   </summary>
 </histogram>
 
-<histogram name="Translate.Translation.TargetLanguage" enum="LocaleCodeISO639"
+<histogram name="Translate.Translation.TargetLanguage" enum="LocaleCodeBCP47"
     expires_after="2025-10-19">
   <owner>megjablon@google.com</owner>
   <owner>chrome-language@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/webapps/histograms.xml b/tools/metrics/histograms/metadata/webapps/histograms.xml
index cee1ea0..607c6cc 100644
--- a/tools/metrics/histograms/metadata/webapps/histograms.xml
+++ b/tools/metrics/histograms/metadata/webapps/histograms.xml
@@ -1880,7 +1880,7 @@
 </histogram>
 
 <histogram name="WebApp.Preinstalled.InstallCount" units="apps"
-    expires_after="2025-06-07">
+    expires_after="2026-06-07">
   <owner>joelhockey@chromium.org</owner>
   <owner>pwa-team@google.com</owner>
   <summary>
@@ -1902,7 +1902,7 @@
 </histogram>
 
 <histogram name="WebApp.Preinstalled.UninstallAppRemovedCount" units="apps"
-    expires_after="2025-06-07">
+    expires_after="2026-06-07">
   <owner>joelhockey@chromium.org</owner>
   <owner>pwa-team@google.com</owner>
   <summary>
@@ -1914,7 +1914,7 @@
 </histogram>
 
 <histogram name="WebApp.Preinstalled.UninstallSourceRemovedCount" units="apps"
-    expires_after="2025-06-07">
+    expires_after="2026-06-07">
   <owner>joelhockey@chromium.org</owner>
   <owner>pwa-team@google.com</owner>
   <summary>
@@ -1927,7 +1927,7 @@
 </histogram>
 
 <histogram name="WebApp.Preinstalled.UninstallTotalCount" units="apps"
-    expires_after="2025-06-07">
+    expires_after="2026-06-07">
   <owner>joelhockey@chromium.org</owner>
   <owner>pwa-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/structured/sync/structured.xml b/tools/metrics/structured/sync/structured.xml
index e9eefad4..2c75760 100644
--- a/tools/metrics/structured/sync/structured.xml
+++ b/tools/metrics/structured/sync/structured.xml
@@ -989,7 +989,7 @@
   </event>
 </project>
 
-<project name="CrOSEvents" cros_events="true" targets="chromium,webui">
+<project name="CrOSEvents" cros_events="true" targets="webui,chromium">
   <owner>jongahn@chromium.org</owner>
   <id>per-project</id>
   <scope>device</scope>
@@ -1594,7 +1594,7 @@
     </metric>
     <metric name="Language" type="int">
       <summary>
-        The integer maps to the LocaleCodeISO639 enum indicating the language that
+        The integer maps to the LocaleCodeBCP47 enum indicating the language that
         CCA UI uses.
       </summary>
     </metric>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index f538f35..3da02b2 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -21272,6 +21272,39 @@
   </metric>
 </event>
 
+<event name="SafetyHub.DisruptiveNotificationRevocations.UserRegrant">
+  <owner>olesiamarukhnno@google.com</owner>
+  <owner>antoniosartori@chromium.org</owner>
+  <summary>
+    Recorded when a user has granted a notification permission for a site where
+    notifications where revoked due to disruptive notifications. Recorded when
+    user is visiting a site and has allowed notification permission for a site
+    in the revoke list.
+  </summary>
+  <metric name="DailyAverageVolume">
+    <summary>
+      Average daily volume of notifications sent by the site, measured over the
+      last 7 days.
+    </summary>
+  </metric>
+  <metric name="DaysSinceRevocation">
+    <summary>
+      The number of days between the website was put in the potential revocation
+      list and the detected increase in site engagement.
+    </summary>
+  </metric>
+  <metric name="NewSiteEngagement">
+    <summary>
+      New site engagement after user interaction with the site.
+    </summary>
+  </metric>
+  <metric name="OldSiteEngagement">
+    <summary>
+      Site engagement score when the site marked for revocation.
+    </summary>
+  </metric>
+</event>
+
 <event name="SalientImageAvailability" singular="True">
   <owner>chrome-intelligence-core@google.com</owner>
   <owner>tbansal@chromium.org</owner>
@@ -24101,7 +24134,7 @@
     instances where the user backgrounds then kills Chrome.
   </summary>
   <metric name="FinalSourceLanguage" semantic_type="ST_DEMOGRAPHIC_INFO"
-      enum="LocaleCodeISO639">
+      enum="LocaleCodeBCP47">
     <summary>
       The source language at the time the event is recorded. In most cases this
       will match the initial source language, but the user can change the source
@@ -24118,7 +24151,7 @@
     </summary>
   </metric>
   <metric name="FinalTargetLanguage" semantic_type="ST_DEMOGRAPHIC_INFO"
-      enum="LocaleCodeISO639">
+      enum="LocaleCodeBCP47">
     <summary>
       The target language at the time the event is recorded. In most cases this
       will match the initial target language, but the user can change the target
@@ -24138,7 +24171,7 @@
     </summary>
   </metric>
   <metric name="HTMLContentLanguage" semantic_type="ST_DEMOGRAPHIC_INFO"
-      enum="LocaleCodeISO639">
+      enum="LocaleCodeBCP47">
     <summary>
       The HTML language content attribute specified by the document. Note that
       the semantic_type attribute is included in order to remain consistent with
@@ -24146,7 +24179,7 @@
     </summary>
   </metric>
   <metric name="HTMLDocumentLanguage" semantic_type="ST_DEMOGRAPHIC_INFO"
-      enum="LocaleCodeISO639">
+      enum="LocaleCodeBCP47">
     <summary>
       The HTML language attribute specified by the document. Note that the
       semantic_type attribute is included in order to remain consistent with the
@@ -24154,7 +24187,7 @@
     </summary>
   </metric>
   <metric name="InitialSourceLanguage" semantic_type="ST_DEMOGRAPHIC_INFO"
-      enum="LocaleCodeISO639">
+      enum="LocaleCodeBCP47">
     <summary>
       The initial source language that Translate determines for the page. Note
       that the semantic_type attribute is included in order to remain consistent
@@ -24178,7 +24211,7 @@
     </summary>
   </metric>
   <metric name="InitialTargetLanguage" semantic_type="ST_DEMOGRAPHIC_INFO"
-      enum="LocaleCodeISO639">
+      enum="LocaleCodeBCP47">
     <summary>
       The initial target language that Translate thinks it should translate to.
       Note that the semantic_type attribute is included in order to remain
@@ -24192,7 +24225,7 @@
     </summary>
   </metric>
   <metric name="ModelDetectedLanguage" semantic_type="ST_DEMOGRAPHIC_INFO"
-      enum="LocaleCodeISO639">
+      enum="LocaleCodeBCP47">
     <summary>
       The language that was estimated by the language model based on the page's
       content. Note that the semantic_type attribute is included in order to
diff --git a/tools/perf/core/bot_platforms.py b/tools/perf/core/bot_platforms.py
index 13e93cd7..1be69fc 100644
--- a/tools/perf/core/bot_platforms.py
+++ b/tools/perf/core/bot_platforms.py
@@ -540,6 +540,10 @@
     ]),
 ])
 
+_CROSSBENCH_ANDROID_BYRA = frozenset([
+    _crossbench_speedometer3_1(arguments=['--fileserver', '--debug']),
+])
+
 _CROSSBENCH_TANGOR = frozenset([
     _crossbench_loadline_tablet(arguments=[
         '--cool-down-threshold=moderate',
@@ -768,6 +772,15 @@
         _GetBenchmarkConfig('speedometer2-minorms'),
         _GetBenchmarkConfig('speedometer3-minorms')
     ])
+# Android Desktop (AL)
+_ANDROID_BYRA_BENCHMARK_CONFIGS = PerfSuite([
+    # Byra will also run the crossbench variant to ensure that both legacy and
+    # crossbench work.
+    _GetBenchmarkConfig('speedometer3'),
+    _GetBenchmarkConfig('rendering.mobile'),
+    _GetBenchmarkConfig('rendering.desktop'),
+])
+
 _CHROMEOS_KEVIN_FYI_BENCHMARK_CONFIGS = PerfSuite(
     [_GetBenchmarkConfig('rendering.desktop')])
 _FUCHSIA_PERF_SMARTDISPLAY_BENCHMARK_CONFIGS = PerfSuite([
@@ -941,6 +954,14 @@
     is_fyi=True)
 
 # Android
+ANDROID_BYRA = PerfPlatform(name='android-byra-perf',
+                            description='AL Byra',
+                            num_shards=7,
+                            benchmark_configs=_ANDROID_BYRA_BENCHMARK_CONFIGS,
+                            platform_os='android',
+                            executables=None,
+                            crossbench=_CROSSBENCH_ANDROID_BYRA)
+
 ANDROID_PIXEL4 = PerfPlatform('android-pixel4-perf',
                               'Android R',
                               _ANDROID_PIXEL4_BENCHMARK_CONFIGS,
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index 4605d4d..7f31a47 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -619,6 +619,28 @@
             'device_os_flavor': 'google',
         },
     },
+    'android-desktop-x64-builder-perf': {},
+    'android-byra-perf': {
+        'tests': [{
+            'isolate':
+            'performance_test_suite_android_trichrome_chrome_google_64_32_bundle',
+        }],
+        'platform':
+        'android-trichrome-chrome-google-64-32-bundle',
+        'dimension': {
+            'dut_state': 'ready',
+            'pool': 'chrome',
+            'os': 'Android',
+            'label-pool': 'chrome.tests.perf',
+            'label-board': 'byra',
+        },
+        'server':
+        'https://chromeos-swarming.appspot.com',
+        'service_account':
+        'chromeos-tester@chops-service-accounts.iam.gserviceaccount.com',
+        'realm':
+        'chromeos:chrome',
+    },
     'android-pixel4-perf': {
         'tests': [{
             'isolate':
@@ -1822,8 +1844,10 @@
   result['swarming'] = {
       # Always say this is true regardless of whether the tester
       # supports swarming. It doesn't hurt.
-      'can_use_on_swarming_builders': True,
-      'expiration': 2 * 60 * 60,  # 2 hours pending max
+      'can_use_on_swarming_builders':
+      True,
+      'expiration':
+      2 * 60 * 60,  # 2 hours pending max
       # TODO(crbug.com/40585750): once we have plenty of windows hardwares,
       # to shards perf benchmarks on Win builders, reduce this hard timeout
       # limit to ~2 hrs.
@@ -1831,15 +1855,25 @@
       # (crbug.com/1036447), so we must timeout the shards within ~6 hours to
       # allow for other overhead. If the overall builder times out then we
       # don't get data even from the passing shards.
-      'hard_timeout': test.get('timeout', 4 * 60 * 60),  # default 4 hours
+      'hard_timeout':
+      test.get('timeout', 4 * 60 * 60),  # default 4 hours
       # This is effectively the timeout for a
       # benchmarking subprocess to run since we intentionally do not stream
       # subprocess output to the task stdout.
       # TODO(crbug.com/40585750): Reduce this once we can reduce hard_timeout.
-      'io_timeout': test.get('timeout', 6 * 60 * 60),
-      'dimensions': tester_config['dimension'],
-      'service_account': _TESTER_SERVICE_ACCOUNT,
+      'io_timeout':
+      test.get('timeout', 6 * 60 * 60),
+      'dimensions':
+      tester_config['dimension'],
+      'service_account':
+      tester_config.get('service_account', _TESTER_SERVICE_ACCOUNT),
   }
+
+  if tester_config.get('server', ''):
+    result['swarming']['server'] = tester_config.get('server')
+  if tester_config.get('realm', ''):
+    result['swarming']['realm'] = tester_config.get('realm')
+
   if shards:
     result['swarming']['shards'] = shards
   if tester_config.get('cipd'):
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 629dae66..1fd884e 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@
             "full_remote_path": "perfetto-luci-artifacts/v50.1/linux-arm64/trace_processor_shell"
         },
         "win": {
-            "hash": "ce928a75f32a7561430f3f4b47b1d7cd9b6adffa",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/899ca510c24cb839749c085e42f339bc157f5e33/trace_processor_shell.exe"
+            "hash": "cc3dd9dfb88aadb5177d498e96ff55675ae025ea",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/ed0bcb0f5a956cb4aad00d150851f07496cb23b0/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "99f971ca131f6d11c73f4b918099d434bdd8093c",
@@ -21,8 +21,8 @@
             "full_remote_path": "perfetto-luci-artifacts/v50.1/mac-arm64/trace_processor_shell"
         },
         "linux": {
-            "hash": "6dc573f78cc052f62cfa07deed4a4e3286f671c2",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/852ea3b3255852b10e27b15ee1dde39490519fb5/trace_processor_shell"
+            "hash": "6775a676fc4de6a1351464f1d632310681c1c9af",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/ed0bcb0f5a956cb4aad00d150851f07496cb23b0/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/perf/core/shard_maps/android-byra-perf_map.json b/tools/perf/core/shard_maps/android-byra-perf_map.json
new file mode 100644
index 0000000..94eba60
--- /dev/null
+++ b/tools/perf/core/shard_maps/android-byra-perf_map.json
@@ -0,0 +1,89 @@
+{
+    "0": {
+        "benchmarks": {
+            "rendering.mobile": {
+                "end": 58,
+                "abridged": false
+            }
+        }
+    },
+    "1": {
+        "benchmarks": {
+            "rendering.mobile": {
+                "begin": 58,
+                "end": 116,
+                "abridged": false
+            }
+        }
+    },
+    "2": {
+        "benchmarks": {
+            "rendering.mobile": {
+                "begin": 116,
+                "end": 174,
+                "abridged": false
+            }
+        }
+    },
+    "3": {
+        "benchmarks": {
+            "rendering.mobile": {
+                "begin": 174,
+                "end": 232,
+                "abridged": false
+            }
+        }
+    },
+    "4": {
+        "benchmarks": {
+            "rendering.mobile": {
+                "begin": 232,
+                "end": 290,
+                "abridged": false
+            }
+        }
+    },
+    "5": {
+        "benchmarks": {
+            "rendering.mobile": {
+                "begin": 290,
+                "end": 348,
+                "abridged": false
+            }
+        }
+    },
+    "6": {
+        "benchmarks": {
+            "rendering.mobile": {
+                "begin": 348,
+                "abridged": false
+            },
+            "speedometer3": {
+                "abridged": false
+            }
+        },
+        "crossbench": {
+            "speedometer_3.1": {
+                "display_name": "speedometer3.1.crossbench",
+                "arguments": [
+                    "--fileserver",
+                    "--debug"
+                ]
+            }
+        }
+    },
+    "extra_infos": {
+        "num_stories": 401,
+        "predicted_min_shard_time": 580,
+        "predicted_min_shard_index": 0,
+        "predicted_max_shard_time": 580,
+        "predicted_max_shard_index": 0,
+        "shard #0": 580,
+        "shard #1": 580,
+        "shard #2": 580,
+        "shard #3": 580,
+        "shard #4": 580,
+        "shard #5": 580,
+        "shard #6": 580
+    }
+}
diff --git a/tools/perf/core/shard_maps/timing_data/android-byra-perf_timing.json b/tools/perf/core/shard_maps/timing_data/android-byra-perf_timing.json
new file mode 100644
index 0000000..fe51488
--- /dev/null
+++ b/tools/perf/core/shard_maps/timing_data/android-byra-perf_timing.json
@@ -0,0 +1 @@
+[]
diff --git a/ui/android/java/src/org/chromium/ui/listmenu/ContextMenuCheckItemProperties.java b/ui/android/java/src/org/chromium/ui/listmenu/ContextMenuCheckItemProperties.java
new file mode 100644
index 0000000..64e1f032
--- /dev/null
+++ b/ui/android/java/src/org/chromium/ui/listmenu/ContextMenuCheckItemProperties.java
@@ -0,0 +1,25 @@
+// 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.ui.listmenu;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableIntPropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
+
+/** The properties controlling checkmark-type items in context menus. */
+@NullMarked
+public class ContextMenuCheckItemProperties {
+    public static final WritableObjectPropertyKey<String> TITLE = new WritableObjectPropertyKey<>();
+    public static final WritableIntPropertyKey MENU_ITEM_ID = new WritableIntPropertyKey();
+    // The ON_CLICK should update the model (if needed).
+    public static final WritableObjectPropertyKey<Runnable> ON_CLICK =
+            new WritableObjectPropertyKey<>();
+    public static final WritableBooleanPropertyKey ENABLED = new WritableBooleanPropertyKey();
+    public static final WritableBooleanPropertyKey CHECKED = new WritableBooleanPropertyKey();
+
+    public static final PropertyKey[] ALL_KEYS = {TITLE, MENU_ITEM_ID, ON_CLICK, ENABLED, CHECKED};
+}
diff --git a/ui/android/java/src/org/chromium/ui/listmenu/ContextMenuRadioItemProperties.java b/ui/android/java/src/org/chromium/ui/listmenu/ContextMenuRadioItemProperties.java
new file mode 100644
index 0000000..ea1f700
--- /dev/null
+++ b/ui/android/java/src/org/chromium/ui/listmenu/ContextMenuRadioItemProperties.java
@@ -0,0 +1,24 @@
+// 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.ui.listmenu;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableIntPropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
+
+/** The properties controlling radio-button-type items in context menus. */
+@NullMarked
+public class ContextMenuRadioItemProperties {
+    public static final WritableObjectPropertyKey<String> TITLE = new WritableObjectPropertyKey<>();
+    public static final WritableIntPropertyKey MENU_ITEM_ID = new WritableIntPropertyKey();
+    // The ON_CLICK should handle deselection of other radio button items & other model updates.
+    public static final WritableObjectPropertyKey<Runnable> ON_CLICK =
+            new WritableObjectPropertyKey<>();
+    public static final WritableBooleanPropertyKey ENABLED = new WritableBooleanPropertyKey();
+
+    public static final PropertyKey[] ALL_KEYS = {TITLE, MENU_ITEM_ID, ON_CLICK, ENABLED};
+}
diff --git a/ui/android/java/src/org/chromium/ui/listmenu/ContextMenuSubmenuItemProperties.java b/ui/android/java/src/org/chromium/ui/listmenu/ContextMenuSubmenuItemProperties.java
new file mode 100644
index 0000000..d396e815
--- /dev/null
+++ b/ui/android/java/src/org/chromium/ui/listmenu/ContextMenuSubmenuItemProperties.java
@@ -0,0 +1,36 @@
+// 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.ui.listmenu;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableIntPropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
+
+import java.util.List;
+
+/** The properties controlling submenu-type items in context menus. */
+@NullMarked
+public class ContextMenuSubmenuItemProperties {
+    public static final WritableObjectPropertyKey<String> TITLE = new WritableObjectPropertyKey<>();
+    public static final WritableIntPropertyKey MENU_ITEM_ID = new WritableIntPropertyKey();
+    // The ON_CLICK should enter the submenu (for drilldown).
+    public static final WritableObjectPropertyKey<Runnable> ON_CLICK =
+            new WritableObjectPropertyKey<>();
+    // The ON_HOVER should show the flyout on mouse hover or keyboard focus.
+    public static final WritableObjectPropertyKey<Runnable> ON_HOVER =
+            new WritableObjectPropertyKey<>();
+    public static final WritableBooleanPropertyKey ENABLED = new WritableBooleanPropertyKey();
+    // A list of PropertyModels, each of which represents a context menu item. Some of these menu
+    // items may represent context menus themselves.
+    public static final WritableObjectPropertyKey<List<PropertyModel>> SUBMENU_ITEMS =
+            new WritableObjectPropertyKey<>();
+
+    public static final PropertyKey[] ALL_KEYS = {
+        TITLE, MENU_ITEM_ID, ON_CLICK, ON_HOVER, ENABLED, SUBMENU_ITEMS
+    };
+}
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index dfca458..d2bd63f 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -408,13 +408,6 @@
       ]
     }
 
-    if (is_linux) {
-      sources += [
-        "linux/xdg_shortcut.cc",
-        "linux/xdg_shortcut.h",
-      ]
-    }
-
     if (is_linux || is_chromeos) {
       sources += [
         "accelerators/menu_label_accelerator_util_linux.cc",
@@ -1314,10 +1307,6 @@
     deps += [ "//ui/base/glib" ]
   }
 
-  if (is_linux) {
-    sources += [ "linux/xdg_shortcut_unittest.cc" ]
-  }
-
   if (is_linux && use_dbus) {
     sources += [ "accelerators/global_accelerator_listener/global_accelerator_listener_linux_unittest.cc" ]
     deps += [
diff --git a/ui/base/accelerators/global_accelerator_listener/BUILD.gn b/ui/base/accelerators/global_accelerator_listener/BUILD.gn
index ad8c793e..b2ed504a 100644
--- a/ui/base/accelerators/global_accelerator_listener/BUILD.gn
+++ b/ui/base/accelerators/global_accelerator_listener/BUILD.gn
@@ -43,7 +43,10 @@
       "global_accelerator_listener_ozone.cc",
       "global_accelerator_listener_ozone.h",
     ]
-    deps += [ "//build/config/linux/dbus:buildflags" ]
+    deps += [
+      "//build:branding_buildflags",
+      "//build/config/linux/dbus:buildflags",
+    ]
   }
 
   if (is_linux) {
diff --git a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.cc b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.cc
index d68684a9..e113c2b7 100644
--- a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.cc
+++ b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.cc
@@ -4,11 +4,10 @@
 
 #include "ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.h"
 
-#include <algorithm>
+#include <set>
 #include <string>
 #include <utility>
 
-#include "base/containers/contains.h"
 #include "base/functional/bind.h"
 #include "base/logging.h"
 #include "base/nix/xdg_util.h"
@@ -24,30 +23,28 @@
 #include "dbus/object_path.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/accelerators/command.h"
-#include "ui/base/linux/xdg_shortcut.h"
 
 namespace ui {
 
-using DbusShortcut = DbusStruct<DbusString, DbusDictionary>;
-using DbusShortcuts = DbusArray<DbusShortcut>;
+namespace {
+
+std::string GetShortcutPrefix(const std::string& accelerator_group_id,
+                              const std::string& profile_id) {
+  return base::HexEncode(
+             crypto::SHA256HashString(accelerator_group_id + profile_id))
+      .substr(0, 32);
+}
+
+}  // namespace
 
 GlobalAcceleratorListenerLinux::GlobalAcceleratorListenerLinux(
-    scoped_refptr<dbus::Bus> bus)
-    : bus_(std::move(bus)) {
+    scoped_refptr<dbus::Bus> bus,
+    const std::string& session_token)
+    : bus_(std::move(bus)), session_token_(session_token) {
   if (!bus_) {
     bus_ = dbus_thread_linux::GetSharedSessionBus();
   }
 
-  global_shortcuts_proxy_ = bus_->GetObjectProxy(
-      kPortalServiceName, dbus::ObjectPath(kPortalObjectPath));
-
-  global_shortcuts_proxy_->ConnectToSignal(
-      kGlobalShortcutsInterface, kSignalActivated,
-      base::BindRepeating(&GlobalAcceleratorListenerLinux::OnActivatedSignal,
-                          weak_ptr_factory_.GetWeakPtr()),
-      base::BindOnce(&GlobalAcceleratorListenerLinux::OnSignalConnected,
-                     weak_ptr_factory_.GetWeakPtr()));
-
   dbus_xdg::SetSystemdScopeUnitNameForXdgPortal(
       bus_.get(),
       base::BindOnce(&GlobalAcceleratorListenerLinux::OnSystemdUnitStarted,
@@ -55,17 +52,7 @@
 }
 
 GlobalAcceleratorListenerLinux::~GlobalAcceleratorListenerLinux() {
-  // Normally GlobalShortcutListener outlives the browser process, so this
-  // destructor won't normally get called. It's okay for the sessions not to be
-  // closed explicitly, but this destructor is left here for testing purposes,
-  // and in case this object ever does need to be destructed.
-  for (auto& entry : session_map_) {
-    dbus::MethodCall method_call(kSessionInterface, kMethodCloseSession);
-    entry.second->session_proxy->CallMethod(
-        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
-        base::DoNothing());
-  }
-  session_map_.clear();
+  CloseSession();
 }
 
 void GlobalAcceleratorListenerLinux::OnSystemdUnitStarted(
@@ -82,35 +69,39 @@
   service_started_ = service_started.value_or(false);
 
   if (!*service_started_) {
-    session_map_.clear();
+    bound_commands_.clear();
     return;
   }
 
-  for (auto& pair : session_map_) {
-    CreateSession(pair);
+  global_shortcuts_proxy_ = bus_->GetObjectProxy(
+      kPortalServiceName, dbus::ObjectPath(kPortalObjectPath));
+
+  global_shortcuts_proxy_->ConnectToSignal(
+      kGlobalShortcutsInterface, kSignalActivated,
+      base::BindRepeating(&GlobalAcceleratorListenerLinux::OnActivatedSignal,
+                          weak_ptr_factory_.GetWeakPtr()),
+      base::BindOnce(&GlobalAcceleratorListenerLinux::OnSignalConnected,
+                     weak_ptr_factory_.GetWeakPtr()));
+
+  if (!bound_commands_.empty()) {
+    CreateSession();
   }
 }
 
-void GlobalAcceleratorListenerLinux::CreateSession(SessionMapPair& pair) {
+void GlobalAcceleratorListenerLinux::CreateSession() {
   CHECK(!bus_->GetConnectionName().empty());
 
-  const SessionKey& session_key = pair.first;
-  SessionContext& session_context = *pair.second;
-
-  std::string session_token = session_key.GetTokenKey();
   std::string session_path_str = base::nix::XdgDesktopPortalSessionPath(
-      bus_->GetConnectionName(), session_token);
+      bus_->GetConnectionName(), session_token_);
   dbus::ObjectPath session_path(session_path_str);
-  session_context.session_proxy =
-      bus_->GetObjectProxy(kPortalServiceName, session_path);
-  session_context.bus = bus_;
+  session_proxy_ = bus_->GetObjectProxy(kPortalServiceName, session_path);
 
-  session_context.request = std::make_unique<dbus_xdg::Request>(
+  request_ = std::make_unique<dbus_xdg::Request>(
       bus_, global_shortcuts_proxy_, kGlobalShortcutsInterface,
       kMethodCreateSession, DbusParameters(),
-      MakeDbusDictionary("session_handle_token", DbusString(session_token)),
+      MakeDbusDictionary("session_handle_token", DbusString(session_token_)),
       base::BindOnce(&GlobalAcceleratorListenerLinux::OnCreateSession,
-                     weak_ptr_factory_.GetWeakPtr(), session_key));
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void GlobalAcceleratorListenerLinux::StartListening() {}
@@ -124,22 +115,7 @@
 }
 
 void GlobalAcceleratorListenerLinux::StopListeningForAccelerator(
-    const ui::Accelerator& accelerator) {
-  // Shortcut unregistration is now handled per extension
-}
-
-void GlobalAcceleratorListenerLinux::UnregisterAccelerators(
-    Observer* observer) {
-  std::vector<SessionKey> remove;
-  for (const auto& [key, context] : session_map_) {
-    if (context->observer == observer) {
-      remove.push_back(key);
-    }
-  }
-  for (const auto& key : remove) {
-    session_map_.erase(key);
-  }
-}
+    const ui::Accelerator& accelerator) {}
 
 bool GlobalAcceleratorListenerLinux::IsRegistrationHandledExternally() const {
   return true;
@@ -155,153 +131,152 @@
     return;
   }
 
-  // If no command is global, there's no need to register shortcuts.
-  if (std::ranges::none_of(
-          commands, [](const auto& pair) { return pair.second.global(); })) {
-    return;
-  }
-
-  SessionKey session_key = {accelerator_group_id, profile_id};
-  auto it = session_map_.find(session_key);
-  if (it != session_map_.end()) {
-    auto& session_context = *it->second;
-    session_context.commands = commands;
-
-    // BindShortcuts can only be called once per session.
-    if (session_context.bind_shortcuts_called) {
-      // If BindShortcuts was already called then recreate the session.
-      dbus::MethodCall method_call(kSessionInterface, kMethodCloseSession);
-      session_context.session_proxy->CallMethod(
-          &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
-          base::BindOnce(
-              &GlobalAcceleratorListenerLinux::RecreateSessionOnClosed,
-              weak_ptr_factory_.GetWeakPtr(), session_key));
+  const std::string prefix =
+      GetShortcutPrefix(accelerator_group_id, profile_id);
+  for (const auto& [_, command] : commands) {
+    std::string id = prefix + "-" + command.command_name();
+    if (bound_commands_.find(id) == bound_commands_.end()) {
+      bound_commands_[id] = {command, accelerator_group_id, observer};
     }
+  }
+
+  // Only proceed if there is at least one global command.
+  if (std::none_of(
+          bound_commands_.begin(), bound_commands_.end(),
+          [](const auto& pair) { return pair.second.command.global(); })) {
     return;
   }
 
-  it = session_map_.emplace_hint(
-      it, session_key, std::make_unique<SessionContext>(observer, commands));
+  // Wait until the service has started.
+  if (!service_started_.value_or(false)) {
+    return;
+  }
 
-  if (service_started_.has_value()) {
-    CreateSession(*it);
+  // If there is no session yet, create one.
+  if (!session_proxy_) {
+    CreateSession();
+    return;
+  }
+
+  if (bind_state_ == BindState::kBindCalled) {
+    // Wait for an existing bind to finish before re-binding. This is required
+    // since GNOME has a quirk where the shortcut dialogs need to be dismissed
+    // in the order they're created, otherwise the portal interface will
+    // indicate an error.
+    bind_state_ = BindState::kNeedsRebind;
+  } else if (bind_state_ == BindState::kBound) {
+    CloseSession();
+    CreateSession();
   }
 }
 
 void GlobalAcceleratorListenerLinux::OnCreateSession(
-    const SessionKey& session_key,
     base::expected<DbusDictionary, dbus_xdg::ResponseError> results) {
   if (!results.has_value()) {
     VLOG(1) << "Failed to call CreateSession (error code "
             << static_cast<int>(results.error()) << ").";
-    session_map_.erase(session_key);
+    session_proxy_ = nullptr;
     return;
   }
 
-  auto session_it = session_map_.find(session_key);
-  if (session_it == session_map_.end()) {
-    LOG(ERROR) << "Unknown session path.";
-    return;
-  }
-  const auto& session_context = session_it->second;
-
   auto* session_handle = results->GetAs<DbusString>("session_handle");
   if (!session_handle ||
-      session_context->session_proxy->object_path().value() !=
-          session_handle->value()) {
+      session_proxy_->object_path().value() != session_handle->value()) {
     LOG(ERROR) << "Expected session handle does not match.";
-    session_map_.erase(session_key);
+    session_proxy_ = nullptr;
     return;
   }
 
-  // Check the list of registered shortcuts using ListShortcuts so that
-  // BindShortcuts can be avoided if the registered shortcuts are the same,
-  // otherwise a settings window will open each time the extension is loaded
-  // (likely on browser start).
-  session_context->request = std::make_unique<dbus_xdg::Request>(
+  // Now that the session is created, bind all accumulated shortcuts.
+  dbus::MethodCall method_call(kGlobalShortcutsInterface, kMethodListShortcuts);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendObjectPath(session_proxy_->object_path());
+  request_ = std::make_unique<dbus_xdg::Request>(
       bus_, global_shortcuts_proxy_, kGlobalShortcutsInterface,
-      kMethodListShortcuts,
-      DbusObjectPath(session_context->session_proxy->object_path()),
+      kMethodListShortcuts, DbusObjectPath(session_proxy_->object_path()),
       DbusDictionary(),
       base::BindOnce(&GlobalAcceleratorListenerLinux::OnListShortcuts,
-                     weak_ptr_factory_.GetWeakPtr(), session_key));
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void GlobalAcceleratorListenerLinux::OnListShortcuts(
-    const SessionKey& session_key,
     base::expected<DbusDictionary, dbus_xdg::ResponseError> results) {
   if (!results.has_value()) {
     LOG(ERROR) << "Failed to call ListShortcuts (error code "
                << static_cast<int>(results.error()) << ").";
-    session_map_.erase(session_key);
     return;
   }
 
-  auto session_it = session_map_.find(session_key);
-  if (session_it == session_map_.end()) {
-    LOG(ERROR) << "Unknown session path.";
-    return;
-  }
-  const auto& session_context = session_it->second;
-
   auto* shortcuts = results->GetAs<DbusShortcuts>("shortcuts");
   if (!shortcuts) {
     LOG(ERROR) << "No shortcuts in ListShortcuts response.";
-    session_map_.erase(session_key);
     return;
   }
 
-  std::set<std::string> registered_shortcut_ids;
+  std::set<std::string> registered_ids;
   for (const DbusShortcut& shortcut : shortcuts->value()) {
     const DbusString& id = std::get<0>(shortcut.value());
-    registered_shortcut_ids.insert(id.value());
+    registered_ids.insert(id.value());
   }
 
-  // Only call BindShortcuts if necessary since it opens a settings window.
-  // The GlobalShortcuts interface doesn't provide a way to unregister
-  // shortcuts, so only check for new shortcuts that need registration.
-  for (const auto& command : session_context->commands) {
-    const std::string& id = command.first;
-    if (!base::Contains(registered_shortcut_ids, id)) {
-      BindShortcuts(*session_it->second);
+  // If any bound command is not found among the registered shortcuts, bind
+  // them.
+  for (const auto& [modified_id, bound_cmd] : bound_commands_) {
+    if (registered_ids.find(modified_id) == registered_ids.end()) {
+      BindShortcuts(*shortcuts);
       return;
     }
   }
 }
 
 void GlobalAcceleratorListenerLinux::BindShortcuts(
-    SessionContext& session_context) {
+    const DbusShortcuts& old_shortcuts) {
   dbus::MethodCall method_call(kGlobalShortcutsInterface, kMethodBindShortcuts);
   dbus::MessageWriter writer(&method_call);
 
-  writer.AppendObjectPath(session_context.session_proxy->object_path());
+  writer.AppendObjectPath(session_proxy_->object_path());
 
   DbusShortcuts shortcuts;
-  for (const auto& cmd_pair : session_context.commands) {
-    const auto& command = cmd_pair.second;
-
-    auto props = MakeDbusDictionary(
-        "description", DbusString(base::UTF16ToUTF8(command.description())));
-    if (command.accelerator().key_code()) {
-      props.PutAs(
-          "preferred_trigger",
-          DbusString(ui::AcceleratorToXdgShortcut(command.accelerator())));
+  for (const auto& old_shortcut : old_shortcuts.value()) {
+    const std::string& id = std::get<0>(old_shortcut.value()).value();
+    const DbusDictionary& properties = std::get<1>(old_shortcut.value());
+    DbusDictionary new_props;
+    if (auto* desc = properties.GetAs<DbusString>("description")) {
+      new_props.PutAs("description", DbusString(desc->value()));
     }
-    shortcuts.value().push_back(
-        MakeDbusStruct(DbusString(command.command_name()), std::move(props)));
+    shortcuts.value().emplace_back(DbusString(id), std::move(new_props));
   }
 
+  for (const auto& [modified_id, bound_cmd] : bound_commands_) {
+    DbusDictionary props = MakeDbusDictionary(
+        "description",
+        DbusString(base::UTF16ToUTF8(bound_cmd.command.description())));
+    shortcuts.value().push_back(
+        MakeDbusStruct(DbusString(modified_id), std::move(props)));
+  }
+
+  bind_state_ = BindState::kBindCalled;
   DbusString empty_parent_window;
-  session_context.request = std::make_unique<dbus_xdg::Request>(
+  request_ = std::make_unique<dbus_xdg::Request>(
       bus_, global_shortcuts_proxy_, kGlobalShortcutsInterface,
       kMethodBindShortcuts,
-      MakeDbusParameters(
-          DbusObjectPath(session_context.session_proxy->object_path()),
-          std::move(shortcuts), std::move(empty_parent_window)),
+      MakeDbusParameters(DbusObjectPath(session_proxy_->object_path()),
+                         std::move(shortcuts), std::move(empty_parent_window)),
       DbusDictionary(),
       base::BindOnce(&GlobalAcceleratorListenerLinux::OnBindShortcuts,
                      weak_ptr_factory_.GetWeakPtr()));
-  session_context.bind_shortcuts_called = true;
+}
+
+void GlobalAcceleratorListenerLinux::CloseSession() {
+  if (!session_proxy_) {
+    return;
+  }
+  dbus::MethodCall method_call(kSessionInterface, kMethodCloseSession);
+  session_proxy_->CallMethod(
+      &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::DoNothing());
+  session_proxy_ = nullptr;
+  request_.reset();
+  bind_state_ = BindState::kNotBound;
 }
 
 void GlobalAcceleratorListenerLinux::OnBindShortcuts(
@@ -311,19 +286,14 @@
                << static_cast<int>(results.error()) << ").";
     return;
   }
-
-  // Shortcuts successfully bound. The signal also includes information about
-  // the bound shortcuts, but it's currently not needed.
-}
-
-void GlobalAcceleratorListenerLinux::RecreateSessionOnClosed(
-    const SessionKey& session_key,
-    dbus::Response* response) {
-  auto session_it = session_map_.find(session_key);
-  if (session_it == session_map_.end()) {
-    return;
+  // Shortcuts successfully bound.
+  if (bind_state_ == BindState::kNeedsRebind) {
+    CloseSession();
+    CreateSession();
+  } else {
+    CHECK_EQ(bind_state_, BindState::kBindCalled);
+    bind_state_ = BindState::kBound;
   }
-  CreateSession(*session_it);
 }
 
 void GlobalAcceleratorListenerLinux::OnActivatedSignal(dbus::Signal* signal) {
@@ -338,14 +308,19 @@
     return;
   }
 
-  // Find the corresponding accelerator
-  for (const auto& [session_key, session_context] : session_map_) {
-    if (session_context->session_proxy->object_path() == session_handle) {
-      session_context->observer->ExecuteCommand(
-          session_key.accelerator_group_id, shortcut_id);
-      break;
-    }
+  // Only process the signal if it comes from our current session.
+  if (!session_proxy_ || session_proxy_->object_path() != session_handle) {
+    return;
   }
+
+  auto it = bound_commands_.find(shortcut_id);
+  if (it == bound_commands_.end()) {
+    return;
+  }
+
+  const auto& cmd = it->second;
+  it->second.observer->ExecuteCommand(cmd.accelerator_group_id,
+                                      cmd.command.command_name());
 }
 
 void GlobalAcceleratorListenerLinux::OnSignalConnected(
@@ -358,23 +333,4 @@
   }
 }
 
-std::string GlobalAcceleratorListenerLinux::SessionKey::GetTokenKey() const {
-  return kSessionTokenPrefix +
-         base::HexEncode(
-             crypto::SHA256HashString(accelerator_group_id + profile_id))
-             .substr(0, 32);
-}
-
-GlobalAcceleratorListenerLinux::SessionContext::SessionContext(
-    Observer* observer,
-    const ui::CommandMap& commands)
-    : observer(observer), commands(commands) {}
-
-GlobalAcceleratorListenerLinux::SessionContext::~SessionContext() {
-  if (session_proxy) {
-    bus->RemoveObjectProxy(kPortalServiceName, session_proxy->object_path(),
-                           base::DoNothing());
-  }
-}
-
 }  // namespace ui
diff --git a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.h b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.h
index 15f4e8bf..e405404f 100644
--- a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.h
+++ b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.h
@@ -5,12 +5,11 @@
 #ifndef UI_BASE_ACCELERATORS_GLOBAL_ACCELERATOR_LISTENER_GLOBAL_ACCELERATOR_LISTENER_LINUX_H_
 #define UI_BASE_ACCELERATORS_GLOBAL_ACCELERATOR_LISTENER_GLOBAL_ACCELERATOR_LISTENER_LINUX_H_
 
+#include <map>
 #include <memory>
 #include <optional>
 #include <string>
-#include <tuple>
 
-#include "base/containers/flat_map.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "components/dbus/xdg/request.h"
@@ -31,7 +30,8 @@
 // interface.
 class GlobalAcceleratorListenerLinux : public GlobalAcceleratorListener {
  public:
-  explicit GlobalAcceleratorListenerLinux(scoped_refptr<dbus::Bus> bus);
+  GlobalAcceleratorListenerLinux(scoped_refptr<dbus::Bus> bus,
+                                 const std::string& session_token);
 
   GlobalAcceleratorListenerLinux(const GlobalAcceleratorListenerLinux&) =
       delete;
@@ -44,6 +44,9 @@
   FRIEND_TEST_ALL_PREFIXES(GlobalAcceleratorListenerLinuxTest,
                            OnCommandsChanged);
 
+  using DbusShortcut = DbusStruct<DbusString, DbusDictionary>;
+  using DbusShortcuts = DbusArray<DbusShortcut>;
+
   // These are exposed in the header for testing.
   static constexpr char kPortalServiceName[] = "org.freedesktop.portal.Desktop";
   static constexpr char kPortalObjectPath[] = "/org/freedesktop/portal/desktop";
@@ -57,43 +60,25 @@
   static constexpr char kMethodCloseSession[] = "Close";
   static constexpr char kSignalActivated[] = "Activated";
 
-  static constexpr char kSessionTokenPrefix[] = "chromium_";
+  enum class BindState {
+    kNotBound,
+    kBindCalled,
+    kNeedsRebind,
+    kBound,
+  };
 
-  struct SessionKey {
+  struct BoundCommand {
+    ui::Command command;
     std::string accelerator_group_id;
-    std::string profile_id;
-
-    std::string GetTokenKey() const;
-
-    bool operator<(const SessionKey& other) const {
-      return std::tie(accelerator_group_id, profile_id) <
-             std::tie(other.accelerator_group_id, other.profile_id);
-    }
+    raw_ptr<Observer> observer = nullptr;
   };
 
-  struct SessionContext {
-    SessionContext(Observer* observer, const ui::CommandMap& commands);
-    ~SessionContext();
-
-    scoped_refptr<dbus::Bus> bus;
-    raw_ptr<dbus::ObjectProxy> session_proxy;
-    const raw_ptr<Observer> observer;
-    ui::CommandMap commands;
-    bool bind_shortcuts_called = false;
-    std::unique_ptr<dbus_xdg::Request> request;
-  };
-
-  using SessionMap =
-      base::flat_map<SessionKey, std::unique_ptr<SessionContext>>;
-  using SessionMapPair = std::pair<SessionKey, std::unique_ptr<SessionContext>>;
-
   // GlobalAcceleratorListener:
   void StartListening() override;
   void StopListening() override;
   bool StartListeningForAccelerator(
       const ui::Accelerator& accelerator) override;
   void StopListeningForAccelerator(const ui::Accelerator& accelerator) override;
-  void UnregisterAccelerators(Observer* observer);
   bool IsRegistrationHandledExternally() const override;
   void OnCommandsChanged(const std::string& accelerator_group_id,
                          const std::string& profile_id,
@@ -101,17 +86,12 @@
                          Observer* observer) override;
 
   void OnCreateSession(
-      const SessionKey& session_key,
       base::expected<DbusDictionary, dbus_xdg::ResponseError> results);
   void OnListShortcuts(
-      const SessionKey& session_key,
       base::expected<DbusDictionary, dbus_xdg::ResponseError> results);
   void OnBindShortcuts(
       base::expected<DbusDictionary, dbus_xdg::ResponseError> results);
 
-  void RecreateSessionOnClosed(const SessionKey& session_key,
-                               dbus::Response* response);
-
   // Callbacks for DBus signals.
   void OnActivatedSignal(dbus::Signal* signal);
 
@@ -123,20 +103,22 @@
 
   void OnServiceStarted(std::optional<bool> service_started);
 
-  void CreateSession(SessionMapPair& pair);
+  void CreateSession();
 
-  void BindShortcuts(SessionContext& session_context);
+  void BindShortcuts(const DbusShortcuts& old_shortcuts);
+
+  void CloseSession();
 
   // DBus components.
   scoped_refptr<dbus::Bus> bus_;
   raw_ptr<dbus::ObjectProxy> global_shortcuts_proxy_ = nullptr;
-
-  // Whether the GlobalShortcuts service is available, or nullopt if the status
-  // is not yet known.
+  raw_ptr<dbus::ObjectProxy> session_proxy_ = nullptr;
   std::optional<bool> service_started_;
+  std::unique_ptr<dbus_xdg::Request> request_;
+  BindState bind_state_ = BindState::kNotBound;
+  const std::string session_token_;
 
-  // One session per extension.
-  base::flat_map<SessionKey, std::unique_ptr<SessionContext>> session_map_;
+  std::map<std::string, BoundCommand> bound_commands_;
 
   base::WeakPtrFactory<GlobalAcceleratorListenerLinux> weak_ptr_factory_{this};
 };
diff --git a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux_unittest.cc b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux_unittest.cc
index a548173..64e62de 100644
--- a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux_unittest.cc
+++ b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux_unittest.cc
@@ -4,12 +4,16 @@
 
 #include "ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.h"
 
+#include <string>
+
 #include "base/memory/scoped_refptr.h"
 #include "base/nix/xdg_util.h"
 #include "base/notreached.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/dbus/properties/types.h"
 #include "content/public/test/browser_task_environment.h"
+#include "crypto/sha2.h"
 #include "dbus/message.h"
 #include "dbus/mock_bus.h"
 #include "dbus/mock_object_proxy.h"
@@ -32,6 +36,10 @@
 constexpr char kBusName[] = ":1.456";
 constexpr char kExtensionId[] = "test_extension_id";
 constexpr char kProfileId[] = "test_profile_id";
+// This is computed based on `kExtensionId` and `kProfileId`. The value should
+// not change, otherwise user registered shortcuts will be lost.
+constexpr char kSessionId[] = "40E0F983AEACE624C2FE6A78C8E19771";
+constexpr char kSessionToken[] = "test_session_token";
 constexpr char kCommandName[] = "test_command";
 constexpr char16_t kShortcutDescription[] = u"Test Shortcut Description";
 
@@ -151,214 +159,242 @@
           }));
 
   auto global_shortcut_listener =
-      std::make_unique<GlobalAcceleratorListenerLinux>(mock_bus);
+      std::make_unique<GlobalAcceleratorListenerLinux>(mock_bus, kSessionToken);
   auto observer = std::make_unique<MockObserver>();
-
-  // These object proxies have unique generated names, so are initialized when
-  // GetObjectProxy() is called.
-  scoped_refptr<dbus::MockObjectProxy> create_session_request_proxy;
-  scoped_refptr<dbus::MockObjectProxy> list_shortcuts_request_proxy;
-  scoped_refptr<dbus::MockObjectProxy> bind_shortcuts_request_proxy;
   scoped_refptr<dbus::MockObjectProxy> session_proxy;
-
-  auto get_object_proxy_session =
-      [&](std::string_view service_name,
-          const dbus::ObjectPath& object_path) -> dbus::ObjectProxy* {
-    // The first call in the sequence is for the session proxy.
-    session_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
-        mock_bus.get(), GlobalAcceleratorListenerLinux::kPortalServiceName,
-        object_path);
-    return session_proxy.get();
-  };
-
-  auto get_object_proxy_create_session =
-      [&](std::string_view service_name,
-          const dbus::ObjectPath& object_path) -> dbus::ObjectProxy* {
-    // CreateSession
-    create_session_request_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
-        mock_bus.get(), GlobalAcceleratorListenerLinux::kPortalServiceName,
-        object_path);
-    EXPECT_CALL(*create_session_request_proxy, DoConnectToSignal(_, _, _, _))
-        .WillOnce(Invoke(
-            [&](const std::string& interface_name,
-                const std::string& signal_name,
-                dbus::ObjectProxy::SignalCallback signal_callback,
-                dbus::ObjectProxy::OnConnectedCallback* on_connected_callback) {
-              EXPECT_EQ(interface_name, "org.freedesktop.portal.Request");
-              EXPECT_EQ(signal_name, "Response");
-
-              std::move(*on_connected_callback)
-                  .Run(interface_name, signal_name, true);
-
-              dbus::Signal signal(interface_name, signal_name);
-              dbus::MessageWriter writer(&signal);
-              writer.AppendUint32(kResponseSuccess);
-              MakeDbusDictionary(
-                  "session_handle",
-                  DbusString(session_proxy->object_path().value()))
-                  .Write(&writer);
-              signal_callback.Run(&signal);
-            }));
-    return create_session_request_proxy.get();
-  };
-
-  auto get_object_proxy_list_shortcuts =
-      [&](std::string_view service_name,
-          const dbus::ObjectPath& object_path) -> dbus::ObjectProxy* {
-    // ListShortcuts
-    list_shortcuts_request_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
-        mock_bus.get(), GlobalAcceleratorListenerLinux::kPortalServiceName,
-        object_path);
-    EXPECT_CALL(*list_shortcuts_request_proxy, DoConnectToSignal(_, _, _, _))
-        .WillOnce(Invoke(
-            [&](const std::string& interface_name,
-                const std::string& signal_name,
-                dbus::ObjectProxy::SignalCallback signal_callback,
-                dbus::ObjectProxy::OnConnectedCallback* on_connected_callback) {
-              EXPECT_EQ(interface_name, "org.freedesktop.portal.Request");
-              EXPECT_EQ(signal_name, "Response");
-
-              std::move(*on_connected_callback)
-                  .Run(interface_name, signal_name, true);
-
-              dbus::Signal signal(interface_name, signal_name);
-              dbus::MessageWriter writer(&signal);
-              writer.AppendUint32(kResponseSuccess);
-              // Simulate empty list of shortcuts
-              MakeDbusDictionary("shortcuts", DbusShortcuts()).Write(&writer);
-              signal_callback.Run(&signal);
-            }));
-    return list_shortcuts_request_proxy.get();
-  };
-
-  auto get_object_proxy_bind_shortcuts =
-      [&](std::string_view service_name,
-          const dbus::ObjectPath& object_path) -> dbus::ObjectProxy* {
-    // BindShortcuts
-    bind_shortcuts_request_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
-        mock_bus.get(), GlobalAcceleratorListenerLinux::kPortalServiceName,
-        object_path);
-    EXPECT_CALL(*bind_shortcuts_request_proxy, DoConnectToSignal(_, _, _, _))
-        .WillOnce(Invoke(
-            [&](const std::string& interface_name,
-                const std::string& signal_name,
-                dbus::ObjectProxy::SignalCallback signal_callback,
-                dbus::ObjectProxy::OnConnectedCallback* on_connected_callback) {
-              EXPECT_EQ(interface_name, "org.freedesktop.portal.Request");
-              EXPECT_EQ(signal_name, "Response");
-
-              std::move(*on_connected_callback)
-                  .Run(interface_name, signal_name, true);
-
-              dbus::Signal signal(interface_name, signal_name);
-              dbus::MessageWriter writer(&signal);
-              writer.AppendUint32(kResponseSuccess);
-              DbusDictionary().Write(&writer);
-              signal_callback.Run(&signal);
-            }));
-    return bind_shortcuts_request_proxy.get();
-  };
-
-  EXPECT_CALL(
-      *mock_bus,
-      GetObjectProxy(GlobalAcceleratorListenerLinux::kPortalServiceName, _))
-      .WillOnce(Invoke(get_object_proxy_session))
-      .WillOnce(Invoke(get_object_proxy_create_session))
-      .WillOnce(Invoke(get_object_proxy_list_shortcuts))
-      .WillOnce(Invoke(get_object_proxy_bind_shortcuts));
-
-  // CreateSession request
-  EXPECT_CALL(
-      *mock_global_shortcuts_proxy,
-      DoCallMethodWithErrorResponse(
-          MatchMethod(GlobalAcceleratorListenerLinux::kGlobalShortcutsInterface,
-                      GlobalAcceleratorListenerLinux::kMethodCreateSession),
-          _, _))
-      .WillOnce(
-          Invoke([&](dbus::MethodCall* method_call, int timeout_ms,
-                     dbus::ObjectProxy::ResponseOrErrorCallback* callback) {
-            dbus::MessageReader reader(method_call);
-            DbusDictionary options;
-            EXPECT_TRUE(options.Read(&reader));
-            auto* token = options.GetAs<DbusString>("session_handle_token");
-            ASSERT_TRUE(token);
-            std::string session_path_str =
-                base::nix::XdgDesktopPortalSessionPath(kBusName,
-                                                       token->value());
-            EXPECT_EQ(dbus::ObjectPath(session_path_str),
-                      session_proxy->object_path());
-
-            auto response = dbus::Response::CreateEmpty();
-            dbus::MessageWriter writer(response.get());
-            writer.AppendObjectPath(
-                create_session_request_proxy->object_path());
-            std::move(*callback).Run(response.get(), nullptr);
-          }));
-
-  // ListShortcuts request
-  EXPECT_CALL(
-      *mock_global_shortcuts_proxy,
-      DoCallMethodWithErrorResponse(
-          MatchMethod(GlobalAcceleratorListenerLinux::kGlobalShortcutsInterface,
-                      GlobalAcceleratorListenerLinux::kMethodListShortcuts),
-          _, _))
-      .WillOnce(
-          Invoke([&](dbus::MethodCall* method_call, int timeout_ms,
-                     dbus::ObjectProxy::ResponseOrErrorCallback* callback) {
-            dbus::MessageReader reader(method_call);
-            dbus::ObjectPath session_path;
-            EXPECT_TRUE(reader.PopObjectPath(&session_path));
-            DbusDictionary options;
-            EXPECT_TRUE(options.Read(&reader));
-
-            auto response = dbus::Response::CreateEmpty();
-            dbus::MessageWriter writer(response.get());
-            writer.AppendObjectPath(
-                list_shortcuts_request_proxy->object_path());
-            std::move(*callback).Run(response.get(), nullptr);
-          }));
-
-  // BindShortcuts request
-  EXPECT_CALL(
-      *mock_global_shortcuts_proxy,
-      DoCallMethodWithErrorResponse(
-          MatchMethod(GlobalAcceleratorListenerLinux::kGlobalShortcutsInterface,
-                      GlobalAcceleratorListenerLinux::kMethodBindShortcuts),
-          _, _))
-      .WillOnce(
-          Invoke([&](dbus::MethodCall* method_call, int timeout_ms,
-                     dbus::ObjectProxy::ResponseOrErrorCallback* callback) {
-            dbus::MessageReader reader(method_call);
-            dbus::ObjectPath session_path;
-            EXPECT_TRUE(reader.PopObjectPath(&session_path));
-            DbusShortcuts shortcuts;
-            EXPECT_TRUE(shortcuts.Read(&reader));
-            DbusString parent_window;
-            EXPECT_TRUE(parent_window.Read(&reader));
-
-            auto response = dbus::Response::CreateEmpty();
-            dbus::MessageWriter writer(response.get());
-            writer.AppendObjectPath(
-                bind_shortcuts_request_proxy->object_path());
-            std::move(*callback).Run(response.get(), nullptr);
-          }));
-
   ui::CommandMap commands;
+
+  auto update_commands = [&]() {
+    // These object proxies have unique generated names, so are initialized when
+    // GetObjectProxy() is called.
+    scoped_refptr<dbus::MockObjectProxy> create_session_request_proxy;
+    scoped_refptr<dbus::MockObjectProxy> list_shortcuts_request_proxy;
+    scoped_refptr<dbus::MockObjectProxy> bind_shortcuts_request_proxy;
+
+    auto get_object_proxy_session =
+        [&](std::string_view service_name,
+            const dbus::ObjectPath& object_path) -> dbus::ObjectProxy* {
+      // The first call in the sequence is for the session proxy.
+      session_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
+          mock_bus.get(), GlobalAcceleratorListenerLinux::kPortalServiceName,
+          object_path);
+      return session_proxy.get();
+    };
+
+    auto get_object_proxy_create_session =
+        [&](std::string_view service_name,
+            const dbus::ObjectPath& object_path) -> dbus::ObjectProxy* {
+      // CreateSession
+      create_session_request_proxy =
+          base::MakeRefCounted<dbus::MockObjectProxy>(
+              mock_bus.get(),
+              GlobalAcceleratorListenerLinux::kPortalServiceName, object_path);
+      EXPECT_CALL(*create_session_request_proxy, DoConnectToSignal(_, _, _, _))
+          .WillOnce(
+              Invoke([&](const std::string& interface_name,
+                         const std::string& signal_name,
+                         dbus::ObjectProxy::SignalCallback signal_callback,
+                         dbus::ObjectProxy::OnConnectedCallback*
+                             on_connected_callback) {
+                EXPECT_EQ(interface_name, "org.freedesktop.portal.Request");
+                EXPECT_EQ(signal_name, "Response");
+
+                std::move(*on_connected_callback)
+                    .Run(interface_name, signal_name, true);
+
+                dbus::Signal signal(interface_name, signal_name);
+                dbus::MessageWriter writer(&signal);
+                writer.AppendUint32(kResponseSuccess);
+                MakeDbusDictionary(
+                    "session_handle",
+                    DbusString(session_proxy->object_path().value()))
+                    .Write(&writer);
+                signal_callback.Run(&signal);
+              }));
+      return create_session_request_proxy.get();
+    };
+
+    auto get_object_proxy_list_shortcuts =
+        [&](std::string_view service_name,
+            const dbus::ObjectPath& object_path) -> dbus::ObjectProxy* {
+      // ListShortcuts
+      list_shortcuts_request_proxy =
+          base::MakeRefCounted<dbus::MockObjectProxy>(
+              mock_bus.get(),
+              GlobalAcceleratorListenerLinux::kPortalServiceName, object_path);
+      EXPECT_CALL(*list_shortcuts_request_proxy, DoConnectToSignal(_, _, _, _))
+          .WillOnce(
+              Invoke([&](const std::string& interface_name,
+                         const std::string& signal_name,
+                         dbus::ObjectProxy::SignalCallback signal_callback,
+                         dbus::ObjectProxy::OnConnectedCallback*
+                             on_connected_callback) {
+                EXPECT_EQ(interface_name, "org.freedesktop.portal.Request");
+                EXPECT_EQ(signal_name, "Response");
+
+                std::move(*on_connected_callback)
+                    .Run(interface_name, signal_name, true);
+
+                dbus::Signal signal(interface_name, signal_name);
+                dbus::MessageWriter writer(&signal);
+                writer.AppendUint32(kResponseSuccess);
+                // Simulate empty list of shortcuts
+                MakeDbusDictionary("shortcuts", DbusShortcuts()).Write(&writer);
+                signal_callback.Run(&signal);
+              }));
+      return list_shortcuts_request_proxy.get();
+    };
+
+    auto get_object_proxy_bind_shortcuts =
+        [&](std::string_view service_name,
+            const dbus::ObjectPath& object_path) -> dbus::ObjectProxy* {
+      // BindShortcuts
+      bind_shortcuts_request_proxy =
+          base::MakeRefCounted<dbus::MockObjectProxy>(
+              mock_bus.get(),
+              GlobalAcceleratorListenerLinux::kPortalServiceName, object_path);
+      EXPECT_CALL(*bind_shortcuts_request_proxy, DoConnectToSignal(_, _, _, _))
+          .WillOnce(
+              Invoke([&](const std::string& interface_name,
+                         const std::string& signal_name,
+                         dbus::ObjectProxy::SignalCallback signal_callback,
+                         dbus::ObjectProxy::OnConnectedCallback*
+                             on_connected_callback) {
+                EXPECT_EQ(interface_name, "org.freedesktop.portal.Request");
+                EXPECT_EQ(signal_name, "Response");
+
+                std::move(*on_connected_callback)
+                    .Run(interface_name, signal_name, true);
+
+                dbus::Signal signal(interface_name, signal_name);
+                dbus::MessageWriter writer(&signal);
+                writer.AppendUint32(kResponseSuccess);
+                DbusDictionary().Write(&writer);
+                signal_callback.Run(&signal);
+              }));
+      return bind_shortcuts_request_proxy.get();
+    };
+
+    EXPECT_CALL(
+        *mock_bus,
+        GetObjectProxy(GlobalAcceleratorListenerLinux::kPortalServiceName, _))
+        .WillOnce(Invoke(get_object_proxy_session))
+        .WillOnce(Invoke(get_object_proxy_create_session))
+        .WillOnce(Invoke(get_object_proxy_list_shortcuts))
+        .WillOnce(Invoke(get_object_proxy_bind_shortcuts));
+
+    // CreateSession request
+    EXPECT_CALL(
+        *mock_global_shortcuts_proxy,
+        DoCallMethodWithErrorResponse(
+            MatchMethod(
+                GlobalAcceleratorListenerLinux::kGlobalShortcutsInterface,
+                GlobalAcceleratorListenerLinux::kMethodCreateSession),
+            _, _))
+        .WillOnce(
+            Invoke([&](dbus::MethodCall* method_call, int timeout_ms,
+                       dbus::ObjectProxy::ResponseOrErrorCallback* callback) {
+              dbus::MessageReader reader(method_call);
+              DbusDictionary options;
+              EXPECT_TRUE(options.Read(&reader));
+              auto* token = options.GetAs<DbusString>("session_handle_token");
+              ASSERT_TRUE(token);
+              std::string session_path_str =
+                  base::nix::XdgDesktopPortalSessionPath(kBusName,
+                                                         token->value());
+              EXPECT_EQ(dbus::ObjectPath(session_path_str),
+                        session_proxy->object_path());
+
+              auto response = dbus::Response::CreateEmpty();
+              dbus::MessageWriter writer(response.get());
+              writer.AppendObjectPath(
+                  create_session_request_proxy->object_path());
+              std::move(*callback).Run(response.get(), nullptr);
+            }));
+
+    // ListShortcuts request
+    EXPECT_CALL(
+        *mock_global_shortcuts_proxy,
+        DoCallMethodWithErrorResponse(
+            MatchMethod(
+                GlobalAcceleratorListenerLinux::kGlobalShortcutsInterface,
+                GlobalAcceleratorListenerLinux::kMethodListShortcuts),
+            _, _))
+        .WillOnce(
+            Invoke([&](dbus::MethodCall* method_call, int timeout_ms,
+                       dbus::ObjectProxy::ResponseOrErrorCallback* callback) {
+              dbus::MessageReader reader(method_call);
+              dbus::ObjectPath session_path;
+              EXPECT_TRUE(reader.PopObjectPath(&session_path));
+              DbusDictionary options;
+              EXPECT_TRUE(options.Read(&reader));
+
+              auto response = dbus::Response::CreateEmpty();
+              dbus::MessageWriter writer(response.get());
+              writer.AppendObjectPath(
+                  list_shortcuts_request_proxy->object_path());
+              std::move(*callback).Run(response.get(), nullptr);
+            }));
+
+    // BindShortcuts request
+    EXPECT_CALL(
+        *mock_global_shortcuts_proxy,
+        DoCallMethodWithErrorResponse(
+            MatchMethod(
+                GlobalAcceleratorListenerLinux::kGlobalShortcutsInterface,
+                GlobalAcceleratorListenerLinux::kMethodBindShortcuts),
+            _, _))
+        .WillOnce(
+            Invoke([&](dbus::MethodCall* method_call, int timeout_ms,
+                       dbus::ObjectProxy::ResponseOrErrorCallback* callback) {
+              dbus::MessageReader reader(method_call);
+              dbus::ObjectPath session_path;
+              EXPECT_TRUE(reader.PopObjectPath(&session_path));
+              DbusShortcuts shortcuts;
+              EXPECT_TRUE(shortcuts.Read(&reader));
+              DbusString parent_window;
+              EXPECT_TRUE(parent_window.Read(&reader));
+
+              auto response = dbus::Response::CreateEmpty();
+              dbus::MessageWriter writer(response.get());
+              writer.AppendObjectPath(
+                  bind_shortcuts_request_proxy->object_path());
+              std::move(*callback).Run(response.get(), nullptr);
+            }));
+
+    global_shortcut_listener->OnCommandsChanged(kExtensionId, kProfileId,
+                                                commands, observer.get());
+  };
+
   commands[kCommandName] = ui::Command(kCommandName, kShortcutDescription,
                                        /*global=*/true);
   commands[kCommandName].set_accelerator(
       ui::Accelerator(ui::VKEY_A, ui::EF_CONTROL_DOWN));
 
-  global_shortcut_listener->OnCommandsChanged(kExtensionId, kProfileId,
-                                              commands, observer.get());
+  update_commands();
 
-  // Simulate the Activated signal
+  EXPECT_CALL(
+      *session_proxy,
+      DoCallMethod(
+          MatchMethod(GlobalAcceleratorListenerLinux::kSessionInterface,
+                      GlobalAcceleratorListenerLinux::kMethodCloseSession),
+          _, _));
+
+  update_commands();
+
+  const std::string expected_command_id =
+      kSessionId + std::string("-") + kCommandName;
+
+  // Expect that when the activated signal is received, the observer is invoked
+  // with the accelerator group id and the modified command id.
   EXPECT_CALL(*observer, ExecuteCommand(kExtensionId, kCommandName));
+
+  // Simulate the Activated signal using the modified command id.
   dbus::Signal signal(GlobalAcceleratorListenerLinux::kGlobalShortcutsInterface,
                       GlobalAcceleratorListenerLinux::kSignalActivated);
   dbus::MessageWriter writer(&signal);
   writer.AppendObjectPath(session_proxy->object_path());
-  writer.AppendString(kCommandName);
+  writer.AppendString(expected_command_id);
   writer.AppendUint64(0);  // timestamp
   activated_callback.Run(&signal);
 
diff --git a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_ozone.cc b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_ozone.cc
index c98ecc36..b6985bd 100644
--- a/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_ozone.cc
+++ b/ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_ozone.cc
@@ -13,7 +13,9 @@
 #include "ui/ozone/public/ozone_platform.h"
 
 #if BUILDFLAG(IS_LINUX) && BUILDFLAG(USE_DBUS)
+#include "base/environment.h"
 #include "base/feature_list.h"
+#include "build/branding_buildflags.h"
 #include "ui/base/accelerators/global_accelerator_listener/global_accelerator_listener_linux.h"
 #endif
 
@@ -24,7 +26,41 @@
 BASE_FEATURE(kGlobalShortcutsPortal,
              "GlobalShortcutsPortal",
              base::FEATURE_ENABLED_BY_DEFAULT);
+constexpr char kChannelEnvVar[] = "CHROME_VERSION_EXTRA";
+
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+constexpr char kSessionPrefix[] = "chrome";
+#else
+constexpr char kSessionPrefix[] = "chromium";
 #endif
+
+constexpr char kSessionSuffix[] = "_global_shortcuts";
+
+std::string GetSessionPrefixChannel() {
+  auto env = base::Environment::Create();
+  auto channel = env->GetVar(kChannelEnvVar);
+  if (channel == "beta") {
+    return "_beta";
+  }
+  if (channel == "unstable") {
+    return "_unstable";
+  }
+  if (channel == "canary") {
+    return "_canary";
+  }
+  // No suffix for stable. Also if the channel is unknown, the most likely
+  // scenario is the user is running the binary directly and not getting the
+  // environment variable set, so assume stable to minimize potential risk of
+  // settings or data loss.
+  return "";
+}
+
+std::string GetSessionName() {
+  // The session name must not ever change, otherwise user registered
+  // shortcuts will be lost.
+  return kSessionPrefix + GetSessionPrefixChannel() + kSessionSuffix;
+}
+#endif  // BUILDFLAG(IS_LINUX) && BUILDFLAG(USE_DBUS)
 }  // namespace
 
 namespace ui {
@@ -41,7 +77,7 @@
 #if BUILDFLAG(IS_LINUX) && BUILDFLAG(USE_DBUS)
   if (base::FeatureList::IsEnabled(kGlobalShortcutsPortal)) {
     static GlobalAcceleratorListenerLinux* const linux_instance =
-        new GlobalAcceleratorListenerLinux(nullptr);
+        new GlobalAcceleratorListenerLinux(nullptr, GetSessionName());
     return linux_instance;
   }
 #endif
diff --git a/ui/base/linux/xdg_shortcut.cc b/ui/base/linux/xdg_shortcut.cc
deleted file mode 100644
index 9701dc96..0000000
--- a/ui/base/linux/xdg_shortcut.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/linux/xdg_shortcut.h"
-
-#include <vector>
-
-#include "base/numerics/safe_conversions.h"
-#include "base/strings/string_util.h"
-
-namespace ui {
-
-std::string KeyboardCodeToString(KeyboardCode key_code) {
-  if (key_code >= VKEY_A && key_code <= VKEY_Z) {
-    return std::string(1, base::checked_cast<char>('a' + (key_code - VKEY_A)));
-  }
-  if (key_code >= VKEY_0 && key_code <= VKEY_9) {
-    return std::string(1, base::checked_cast<char>('0' + (key_code - VKEY_0)));
-  }
-
-  switch (key_code) {
-    // General keys
-    case VKEY_OEM_COMMA:
-      return "comma";
-    case VKEY_OEM_PERIOD:
-      return "period";
-    case VKEY_HOME:
-      return "Home";
-    case VKEY_END:
-      return "End";
-    case VKEY_PRIOR:
-      return "Prior";
-    case VKEY_NEXT:
-      return "Next";
-    case VKEY_SPACE:
-      return "space";
-    case VKEY_INSERT:
-      return "Insert";
-    case VKEY_DELETE:
-      return "Delete";
-
-    // Arrow keys
-    case VKEY_LEFT:
-      return "Left";
-    case VKEY_UP:
-      return "Up";
-    case VKEY_RIGHT:
-      return "Right";
-    case VKEY_DOWN:
-      return "Down";
-
-    // Media keys
-    case VKEY_MEDIA_NEXT_TRACK:
-      return "XF86AudioNext";
-    case VKEY_MEDIA_PREV_TRACK:
-      return "XF86AudioPrev";
-    case VKEY_MEDIA_STOP:
-      return "XF86AudioStop";
-    case VKEY_MEDIA_PLAY_PAUSE:
-      return "XF86AudioPlay";
-
-    default:
-      return "UnknownKey";
-  }
-}
-
-std::string AcceleratorToXdgShortcut(const Accelerator& accelerator) {
-  std::vector<std::string> parts;
-
-  // Map Chromium modifiers to XDG spec modifiers
-  if (accelerator.IsCtrlDown()) {
-    parts.push_back("CTRL");
-  }
-  if (accelerator.IsAltDown()) {
-    parts.push_back("ALT");
-  }
-  if (accelerator.IsShiftDown()) {
-    parts.push_back("SHIFT");
-  }
-  if (accelerator.IsCmdDown()) {
-    parts.push_back("LOGO");
-  }
-
-  parts.push_back(KeyboardCodeToString(accelerator.key_code()));
-
-  return base::JoinString(parts, "+");
-}
-
-}  // namespace ui
diff --git a/ui/base/linux/xdg_shortcut.h b/ui/base/linux/xdg_shortcut.h
deleted file mode 100644
index 2666ba0a..0000000
--- a/ui/base/linux/xdg_shortcut.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_LINUX_XDG_SHORTCUT_H_
-#define UI_BASE_LINUX_XDG_SHORTCUT_H_
-
-#include <string>
-
-#include "base/component_export.h"
-#include "ui/base/accelerators/accelerator.h"
-
-namespace ui {
-
-// Converts an Accelerator to an XDG shortcut string.  The contained
-// KeyboardCode to a string according to the XDG shortcut specification [1],
-// which relies on strings from xkbcommon-keysyms.h [2]. This handles only keys
-// supported by the chrome.commands API [3].
-// [1]
-// https://gitlab.freedesktop.org/xdg/xdg-specs/-/blob/master/shortcuts/shortcuts-spec.xml
-// [2]
-// https://raw.githubusercontent.com/xkbcommon/libxkbcommon/master/include/xkbcommon/xkbcommon-keysyms.h
-// [3] https://developer.chrome.com/docs/extensions/reference/api/commands
-COMPONENT_EXPORT(UI_BASE)
-std::string AcceleratorToXdgShortcut(const Accelerator& accelerator);
-
-}  // namespace ui
-
-#endif  // UI_BASE_LINUX_XDG_SHORTCUT_H_
diff --git a/ui/base/linux/xdg_shortcut_unittest.cc b/ui/base/linux/xdg_shortcut_unittest.cc
deleted file mode 100644
index 560b8a2..0000000
--- a/ui/base/linux/xdg_shortcut_unittest.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/linux/xdg_shortcut.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-
-namespace ui {
-
-TEST(AcceleratorToXdgShortcutTest, BasicKeys) {
-  // Test alphabet keys
-  EXPECT_EQ(AcceleratorToXdgShortcut(Accelerator(VKEY_A, 0)), "a");
-  EXPECT_EQ(AcceleratorToXdgShortcut(Accelerator(VKEY_Z, 0)), "z");
-
-  // Test number keys
-  EXPECT_EQ(AcceleratorToXdgShortcut(Accelerator(VKEY_0, 0)), "0");
-  EXPECT_EQ(AcceleratorToXdgShortcut(Accelerator(VKEY_9, 0)), "9");
-
-  // Test general keys
-  EXPECT_EQ(AcceleratorToXdgShortcut(Accelerator(VKEY_SPACE, 0)), "space");
-  EXPECT_EQ(AcceleratorToXdgShortcut(Accelerator(VKEY_HOME, 0)), "Home");
-
-  // Test arrow keys
-  EXPECT_EQ(AcceleratorToXdgShortcut(Accelerator(VKEY_LEFT, 0)), "Left");
-  EXPECT_EQ(AcceleratorToXdgShortcut(Accelerator(VKEY_UP, 0)), "Up");
-
-  // Test media keys
-  EXPECT_EQ(AcceleratorToXdgShortcut(Accelerator(VKEY_MEDIA_PLAY_PAUSE, 0)),
-            "XF86AudioPlay");
-}
-
-TEST(AcceleratorToXdgShortcutTest, Modifiers) {
-  // Test CTRL modifier
-  EXPECT_EQ(AcceleratorToXdgShortcut(Accelerator(VKEY_A, EF_CONTROL_DOWN)),
-            "CTRL+a");
-
-  // Test SHIFT modifier
-  EXPECT_EQ(AcceleratorToXdgShortcut(Accelerator(VKEY_A, EF_SHIFT_DOWN)),
-            "SHIFT+a");
-
-  // Test ALT modifier
-  EXPECT_EQ(AcceleratorToXdgShortcut(Accelerator(VKEY_A, EF_ALT_DOWN)),
-            "ALT+a");
-
-  // Test LOGO (CMD) modifier
-  EXPECT_EQ(AcceleratorToXdgShortcut(Accelerator(VKEY_A, EF_COMMAND_DOWN)),
-            "LOGO+a");
-
-  // Test multiple modifiers
-  EXPECT_EQ(AcceleratorToXdgShortcut(
-                Accelerator(VKEY_A, EF_CONTROL_DOWN | EF_SHIFT_DOWN)),
-            "CTRL+SHIFT+a");
-
-  EXPECT_EQ(AcceleratorToXdgShortcut(
-                Accelerator(VKEY_A, EF_CONTROL_DOWN | EF_ALT_DOWN)),
-            "CTRL+ALT+a");
-
-  EXPECT_EQ(AcceleratorToXdgShortcut(
-                Accelerator(VKEY_A, EF_CONTROL_DOWN | EF_ALT_DOWN |
-                                        EF_SHIFT_DOWN | EF_COMMAND_DOWN)),
-            "CTRL+ALT+SHIFT+LOGO+a");
-}
-
-}  // namespace ui