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 - "en-US"). 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 + "en-US" (i.e. ISO639) or extended BCP47 tags "zh-Hant"). + 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